ome / omero-cli-render

OMERO command-line tool for rendering
https://www.openmicroscopy.org/omero/
GNU General Public License v2.0
2 stars 10 forks source link

New rendering settings specification #55

Open dominikl opened 2 years ago

dominikl commented 2 years ago

The render plugin is a good starting point to play around with different ideas. Wonder if we should have an 'experimental' branch maybe? /cc @jburel @dgault @francesw

Here's a first attempt, kind of a hybrid of the current render plugin output and the current NGFF draft specification (code see draft PR #54 ):

{
    "channels": {
        "0": {
            "active": true,
            "color": "00FF00",
            "color-format": "hex",
            "color-type": "rgb",
            "label": "CEP192-M",
            "window": {
                "end": 16633.45703125,
                "max": 16633.45703125,
                "min": 0.0,
                "start": 0.0
            }
        },
        "1": {
            "active": true,
            "color": "FF0000",
            "color-format": "hex",
            "color-type": "rgb",
            "label": "CENT2",
            "window": {
                "end": 103353.1796875,
                "max": 103353.1796875,
                "min": 0.0,
                "start": 0.0
            }
        }
    },
    "color-model": "color",
    "default-dimension-0": 0,
    "default-dimension-1": 0,
    "dimensions": "zt",
    "plane": "xy",
    "version": 3
}

Instead of defaultZ/T it's more generic default-dimension- and what the dimensions actually mean is specified in dimensions, what a plane actually means likewise in plane. Also the color can be more generic. See above for the common html color specification, but it could also hold lookup tables (e.g. specified by a name or maybe url, etc.), e.g.

    "channels": {
        "0": {
            "active": true,
            "color": "glasbey",
            "color-format": "name",
            "color-type": "lut",
            "label": "CEP192-M",
            "window": {
                "end": 23900.765625,
                "max": 23900.765625,
                "min": 0.0,
                "start": 0.0
            }
        },
        ...
    }

Edit: Actually default-dimension- should better be a list, not several keys.

jburel commented 2 years ago

other elements like mapping family needs to be added: this assumes linear mapping This could also be an opportunity to re-activate the "co-domain" transformations i.e. changes in the device space

Introducing an experimental branch will make sense otherwise we will have a long open PR

sbesson commented 2 years ago

A few high-level thoughts, I think the development workflow will come across several repositories (https://github.com/ome/omero-cli-zarr/pull/88 is another example). Completely fine from my side with having an experimental/development branch where PRs get integrated more quickly.

A few additional considerations:

will-moore commented 2 years ago

Maybe for default dimensions, this might be nicer:

"default_dimensions" : {
  "0": 10,
  "2": 2
}

Also, note the discussion of naming style at https://github.com/ome/ngff/issues/54 Strong preference for color_format over color-format etc.

jburel commented 2 years ago

for the naming discussion, I am wondering if we should not follow the schema.org rule i.e. colorFormat

jburel commented 2 years ago

concept of group should be supported. We will need support for multiple groups

group : {
  "name":  "group1",
  "visible": True,
  "indexes": "1, 2, 5",
  "type": "channel" (could be angle)
}
jburel commented 2 years ago

Looking at the BDV xml files, they need support for AffineTransform for each viewSetup. A viewSetup is either a channel or an angle. There is a transform per timepoint.

jburel commented 2 years ago

The physicalSizeX etc. will need to be known for scale bar but I assume that will be stored elsewhere in the file

jburel commented 2 years ago

Resolution level, viewport could be considered

will-moore commented 2 years ago

@jburel If you're suggesting that the ngff spec uses a different naming convention than snake_case then you should suggest that on https://github.com/ome/ngff/issues/54 since I don't think we want different conventions for different parts of the spec. I don't quite understand the relevance of https://schema.org/ here. Are you thinking that we might want to extend the schema.org vocabulary with our ngff terms?

jburel commented 2 years ago

My comment is more general that this specific issue. The suggestion of following schema.org is coming from the fact that others efforts e.g. bioschema.org, ro-crate follow that convention so it might make more sense to follow similar rule instead of the snake_case convention

joshmoore commented 2 years ago

Are you thinking that we might want to extend the schema.org vocabulary with our ngff terms?

There's a pretty good likelihood that we will eventually want to incorporate schema.org types into our metadata, but that's true for other ontologies & vocabularies as well. The likelihood of being able to find a set which follow the same naming style is basically zero.

jburel commented 2 years ago

I am currently looking at https://www.ebi.ac.uk/spot/oxo/docs/api for a project: mappingTarget is for example a field returned

dominikl commented 2 years ago

With the recent suggestions added, it would look like these:

{
    "channels": {
        "0": {
            "color": "00FF00",
            "color_format": "hex",
            "color_type": "rgb",
            "label": "GFP",
            "mapping": {
                "coefficient": "1.8",
                "family": "exponential",
                "reverse": "False"
            },
            "noise_reduction": "False",
            "window": {
                "end": 1542.5789794921875,
                "max": 1542.5789794921875,
                "min": 0.0,
                "start": 0.0
            }
        },
...
    },
    "color_model": "color",
    "default_dimensions": {
        "0": 0,
        "1": 0
    },
    "dimensions": "zt",
    "group": {
        "0": {
            "indexes": [
                "0",
                "2"
            ],
            "type": "channel",
            "visible": "True"
        }
    },
    "plane": "xy",
    "version": 3
}

Not sure where to put the viewSetup.

sbesson commented 2 years ago

A few initial thoughts while reading https://github.com/ome/omero-cli-render/issues/55#issuecomment-942313450 (without having looked at the notes):

dominikl commented 2 years ago

You're right, color as dictionary is better. And default Z/T (dimensions/axis) should be part of the group. Also dimension should actually be axis. And the coefficient in the channel mapping is now a list (as far as I understand one could have other operations than linear, exponential which might have more than one parameter).

I struggle a bit with a further generalisation of the dimension/axis bit. In general the axis are XYZTC (or whatever order). But they are not the same kind of thing. Channel is a special dimension, and you also still need the concept of a plane, plus extra dimensions. Right? But then @jburel said instead of channels one could also have angles (sorry I still don't really get this bit).

Anyway, at the moment it would look like this:

Another example ``` { "axes": "zt", "channels": { "0": { "color": { "format": "hex", "type": "rgb", "value": "00FF00" }, "label": "GFP", "mapping": { "coefficients": [ "1.8" ], "family": "exponential", "reverse": "False" }, "noise_reduction": "False", "window": { "end": 1542.5789794921875, "max": 1542.5789794921875, "min": 0.0, "start": 0.0 } }, "1": { "color": { "format": "hex", "type": "rgb", "value": "FFFFFF" }, "label": "1", "mapping": { "coefficients": [ "1.0" ], "family": "linear", "reverse": "False" }, "noise_reduction": "False", "window": { "end": 1555.0537109375, "max": 1555.0537109375, "min": 0.0, "start": 0.0 } }, "2": { "color": { "format": "name", "type": "lut", "value": "brgbcmyw" }, "label": "2", "mapping": { "coefficients": [ "1.0" ], "family": "linear", "reverse": "False" }, "noise_reduction": "False", "window": { "end": 188.89093017578125, "max": 188.89093017578125, "min": 0.007875712588429451, "start": 0.007875712588429451 } } }, "color_model": "color", "group": { "0": { "default_axis": { "0": 0, "1": 0 }, "indexes": [ "0", "2" ], "type": "channel", "visible": "True" } }, "plane": "xy", "version": 3 }```
dominikl commented 2 years ago

does the current draft of the rendering model support sparse channel settings or should all channels be specified?

That's a good question too. I don't think we've discussed that yet.

will-moore commented 2 years ago

Currently, it looks like if the number of channels in the omero data is different from the size_c of the data (or if any of the channels is missing color) then the image will fail to open in napari. But it shouldn't be hard to fix this and handle missing channels / colors.

Apologies for missing any discussions on this, but what does "plane": "xy" and "axes": "zt" signify? The proposal at https://github.com/ome/ngff/pull/57 is to specify the types of the various axes, e.g.:

"axes": [
  {"name": "t", "type": "time", "unit": "millisecond"},
  {"name": "c", "type": "channel"},
  {"name": "z", "type": "space", "unit": "micrometer"},
  {"name": "y", "type": "space", "unit": "micrometer"},
  {"name": "x", "type": "space", "unit": "micrometer"}
],
dominikl commented 2 years ago

You need to somehow specify that you're viewing a x,y plane and that the further dimensions are labelled as z and t (in exactly that order). This axis list looks good. But is that ordered? And how would you in that case say you want to show the x,y plane for z-axis 3 by default for example?

will-moore commented 2 years ago

The axes list above is certainly ordered. Already for v0.3 we have "axes": ["z", "y", "x"] etc, but for v0.4 it's proposed to specify the type of each axis. If you have "axes": ["z", "y", "x"] with "default_dimensions": {"0": 3,} I think that would do it for "z-axis 3"? Just being picky, I wonder if default_dimensions in your examples is really specifying defaultIndices rather than dimensions? NB: it's looking like https://github.com/ome/ngff/issues/54 is heading for camelCase.

dominikl commented 2 years ago

But still needs a plane. Or should one assume from default_dimensions": {"0": 3,} and axes": ["z", "y", "x"] that the plane is x,y? That would mean all default_dimensions have to specified. Yes, it should rather be defaultIndices indeed.

will-moore commented 2 years ago

I think that plane can default to xy, so we don't need to specify it. If you choose to specify the x or y dimension in the defaultIndices then I guess you might need to know plane (only if you have size_T > 1 AND size_Z > 1), but we have no way to support that in napari or vizarr as far as I can tell (https://napari.org/docs/dev/api/napari.view_layers.Viewer.html#napari.view_layers.Viewer.add_image) And in genuine 3D viewers (moBie, neuroglancer) I don't think you'll use it either?

dominikl commented 2 years ago

I thought the point was to keep things as generic as possible, no matter what's currently supported by our or other software. But if we define the plane is always x/y and the axis are always z and t - like it is now - then this whole discussion is pointless and we can basically take the current output of the render plugin as rendering settings spec (just have to change a few names like z to default-z, defaultZ, default_z, ...)

jburel commented 2 years ago

plane cannot default to xy, in our model we have the concept of PlaneDef and support for xy, xz and yz. This was previously implemented in insight as a slice viewer.

unidesigner commented 2 years ago

Just a quick, perhaps unrelated question: Is the idea that tool-specific (e.g. rendering specific) metadata becomes part of the "official" ngff spec? I'm wondering because I created this issue with regards to tool-specific metadata. Sorry if this has been answered already elsewhere.

jburel commented 2 years ago
"mapping": {
                "coefficients": [
                    "1.0"
                ],
                "family": "linear",
                "reverse": "False"
            },

I don't see why coefficients is a list. if you have a mapping function that takes more than one parameter it will have to be a dictionary. The proposal is mixing 2 concepts:

jburel commented 2 years ago

Looking at the BDV example,

<Timepoints type="range">
<first>0</first>
<last>2</last>
</Timepoints>

defaultIndices will probably need to support range or list of ranges and not only a value in our case it could be "0": [0,0]. This adds some complexity in the handling but should hopefully accommodate other viewers' needs

dominikl commented 2 years ago

As the axis definition is apparently already in the "general" ngff spec, we might as well use the axis names z, t for the plane and defaultIndices instead of indices. I don't know where/what kind of dictionary this mapping element should be, nor how/where to add an angle definition, please just add an example @jburel / @dgault .

@unidesigner : Yes, it's going to be an ngff specfication, but as far as I know there will be places for tool specific metadata too.

Updated example: ``` { "channels": { "0": { "coefficient": "1.8", "color": { "format": "hex", "type": "rgb", "value": "00FF00" }, "family": "exponential", "label": "GFP", "noiseReduction": "False", "reverse": "False", "window": { "end": 1542.5789794921875, "max": 1542.5789794921875, "min": 0.0, "start": 0.0 } }, "1": { "coefficient": "1.0", "color": { "format": "hex", "type": "rgb", "value": "FFFFFF" }, "family": "linear", "label": "1", "noiseReduction": "False", "reverse": "False", "window": { "end": 1555.0537109375, "max": 1555.0537109375, "min": 0.0, "start": 0.0 } }, "2": { "coefficient": "1.0", "color": { "format": "name", "type": "lut", "value": "brgbcmyw" }, "family": "linear", "label": "2", "noiseReduction": "False", "reverse": "False", "window": { "end": 188.89093017578125, "max": 188.89093017578125, "min": 0.007875712588429451, "start": 0.007875712588429451 } } }, "colorModel": "color", "group": { "0": { "defaultIndices": { "t": { "from": 0, "to": 0 }, "z": { "from": 0, "to": 0 } }, "indices": [ "0", "2" ], "type": "channel", "visible": "True" } }, "plane": "xy" } ```
jburel commented 2 years ago
{
    "views": {
       "type": "channel",
        "0": {
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "00FF00"
            },
            "coefficient": "1.8",
            "family": "exponential",
            "label": "GFP",
            "noiseReduction": "False",
            "deviceSpaceMapping":  [{"reverseIntensity": {"value": True}}],
            "window": {
                "end": 1542.5789794921875,
                "max": 1542.5789794921875,
                "min": 0.0,
                "start": 0.0
            }
        },
        "1": {
            "coefficient": "1.0",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "FFFFFF"
            },
            "family": "linear",
            "label": "1",
            "noiseReduction": "False",
            "deviceSpaceMapping":  [{"reverseIntensity": {"value": True}}, {"binning": {"0-100": 100, "101-200": 200, "201-255": 255}}]
            "window": {
                "end": 1555.0537109375,
                "max": 1555.0537109375,
                "min": 0.0,
                "start": 0.0
            }
        },
        "2": {
            "coefficient": "1.0",
            "color": {
                "format": "name",
                "type": "lut",
                "value": "brgbcmyw"
            },
            "family": "linear",
            "label": "2",
            "noiseReduction": "False",
            "reverse": "False",
            "window": {
                "end": 188.89093017578125,
                "max": 188.89093017578125,
                "min": 0.007875712588429451,
                "start": 0.007875712588429451
            }
        }
    },
    "colorModel": "color",
    "group": {
        "0": {
            "defaultIndices": {
                "t": {
                    "from": 0,
                    "to": 0
                },
                "z": {
                    "from": 0,
                    "to": 0
                }
            },
            "indices": [
                "0",
                "2"
            ],
            "type": "channel",
            "visible": "True",
            "name": "Group 1"
        }
    },
    "plane": "xy"
}

As mentioned during the call, angle is a new dimension so I have replaced channels by views and we identify the views by its type. If we have settings for angles and channels, we will have multiple views entries, this is no different from groups. I have also added a new entry deviceSpaceMapping. This is a bit complicated since we need a name and the parameters for the transformation. For reverseIntensity, the name is probably enough but it seems strange to just have the name

jburel commented 2 years ago

From discussion today it should probably be

 "views": {
        "0": {
           "channel": "0",
           "angle": "1",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "00FF00"
            },
            "coefficient": "1.8",
            "family": "exponential",
            "label": "GFP",
            "noiseReduction": "False",
            "deviceSpaceMapping":  [{"reverseIntensity": {"value": True}}],
            "window": {
                "end": 1542.5789794921875,
                "max": 1542.5789794921875,
                "min": 0.0,
                "start": 0.0
            }
        },
jburel commented 2 years ago
"group": {
        "0": {
            "defaultIndices": {
                "t": {
                    "from": 0,
                    "to": 0
                },
                "z": {
                    "from": 0,
                    "to": 0
                }
            },
            "indicesChannel": [
                "0",
                "2"
            ],
            "indicesAngle": [
                "1"
            ],
            "visible": "True",
            "name": "Group 1"
        }
    },
    "plane": "xy"
dgault commented 2 years ago

Alternative:

            "indices": {
                "channel": {
                    "0",
                    "1"
                },
                "angle": {
                    "2"
                }
            },
will-moore commented 2 years ago
"deviceSpaceMapping":  [{"reverseIntensity": {"value": True}}],

could be a bit more concise

"deviceSpaceMapping":  [{"reverseIntensity": True}],

(unless this is trying to model omero.rtypes.rbool, or there's other info that could be included in future?)

jburel commented 2 years ago

@will-moore we could simplify, I was trying to go for the same pattern for each entry

will-moore commented 2 years ago

Another thought concerning validation: I don't know what schema etc we might use (e.g. SALAD at https://github.com/ome/ngff/pull/69 or https://wiki.ebrains.eu/bin/view/Collabs/openminds/Documentation/Implementation%20details/#HTheopenMINDSsyntax) but it seems that validation won't work well if the attribute keys (fields) are variable (not defined by the spec). E.g. a key of "0" or "50" for channel index is hard to validate, since you don't have named fields. Same for channel/angle/otherDimensionName (unless we can state in the spec that only channel and angle are supported?

jburel commented 2 years ago

@will-moore good point

dominikl commented 2 years ago

Updated example taking the latest discussions into account:

{
    "colorModel": "color",
    "group": [
        {
            "indices": {
                "angle": [],
                "channel": [
                    "0",
                    "2"
                ],
                "t": {
                    "from": 0,
                    "to": 0
                },
                "z": {
                    "from": 0,
                    "to": 0
                }
            },
            "name": "Group 0",
            "visible": "True"
        }
    ],
    "plane": "xy",
    "version": 3,
    "views": [
        {
            "angle": "",
            "channel": "0",
            "coefficient": "1.8",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "00FF00"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "exponential",
            "label": "GFP",
            "noiseReduction": "False",
            "window": {
                "end": 1542.5789794921875,
                "max": 1542.5789794921875,
                "min": 0.0,
                "start": 0.0
            }
        },
        {
            "angle": "",
            "channel": "1",
            "coefficient": "1.0",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "FFFFFF"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "linear",
            "label": "1",
            "noiseReduction": "False",
            "window": {
                "end": 1555.0537109375,
                "max": 1555.0537109375,
                "min": 0.0,
                "start": 0.0
            }
        },
        {
            "angle": "",
            "channel": "2",
            "coefficient": "1.0",
            "color": {
                "format": "name",
                "type": "lut",
                "value": "brgbcmyw"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "linear",
            "label": "2",
            "noiseReduction": "False",
            "window": {
                "end": 188.89093017578125,
                "max": 188.89093017578125,
                "min": 0.007875712588429451,
                "start": 0.007875712588429451
            }
        }
    ]
}
jburel commented 2 years ago

Capturing discussion from Today I am not sure about the groupVisible cc @dominikl

{
    "colorModel": "color",
    "plane": "xy",
    "version": 3,
    "views": [
        {
            "angle": "",
            "channel": "0",
            "coefficient": "1.8",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "00FF00"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "exponential",
            "label": "GFP",
            "noiseReduction": "False",
            "window": {
                "end": 1542.5789794921875,
                "max": 1542.5789794921875,
                "min": 0.0,
                "start": 0.0
            },
            "active": "True",
            "inGroup": " Group 0",
            "groupVisible": "True", 
            "t": {
               "from": 0,
                    "to": 0
                },
            "z": {
                    "from": 0,
                    "to": 0
                }
           },
          {
            "angle": "",
            "channel": "1",
            "coefficient": "1.0",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "FFFFFF"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "linear",
            "label": "1",
            "noiseReduction": "False",
            "window": {
                "end": 1555.0537109375,
                "max": 1555.0537109375,
                "min": 0.0,
                "start": 0.0
            },
           "active": "False",
           "inGroup": " Group 1",
           "groupVisible": "False", 
           "t": {
               "from": 0,
                    "to": 0
                },
           "z": {
                    "from": 0,
                    "to": 0
                }
          },
          {
            "angle": "",
            "channel": "2",
            "coefficient": "1.0",
            "color": {
                "format": "name",
                "type": "lut",
                "value": "brgbcmyw"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "linear",
            "label": "2",
            "noiseReduction": "False",
            "window": {
                "end": 188.89093017578125,
                "max": 188.89093017578125,
                "min": 0.007875712588429451,
                "start": 0.007875712588429451
            },
           "active": "True",
          "inGroup": " Group 0",
          "groupVisible": "True", 
          "t": {
               "from": 0,
                    "to": 0
                },
          "z": {
                    "from": 0,
                    "to": 0
                }
        },
    ]
}
will-moore commented 2 years ago

@jburel I like the fact that it's easy for a viewer that doesn't support groups to ignore them. And hopefully not too much work for a viewer that does support them. NB: the JSON is not quite formatted correctly? e.g. "window" and "active" are sibling keys in the first and 2nd view, but at different levels in the 3rd. The indentation is inconsistent so it's a bit hard to be sure what's meant?

Is it possible to load the same channel at 2 different angles or Z/T indices?

One option I had imagined from the discussion was to try Dom's last example above, and nest the views within the groups, replacing angle and channel with the view that has angle and channel E.g, a single group with 2 channels:

{
    "colorModel": "color",
    "group": [
        {
            "indices": {
                "views": [
                    {
                        "angle": "",
                        "channel": "0",
                        "color": {}... etc.
                    },
                    {
                        "angle": "",
                        "channel": "1",
                        "color": {}... etc.
                    }
                ],
                "t": {
                    "from": 0,
                    "to": 0
                },
                "z": {
                    "from": 0,
                    "to": 0
                }
            },
            "name": "Group 0",
            "visible": "True"
        }
    ],
    "plane": "xy",
    "version": 3
}

(just in case that has any appeal)?

I wonder if we should document the use-cases we're trying to support. E.g. do any viewers allow you to show different channels (or the same channel) at different Z/T indices or angles? The pathviewer example was helpful in directing the discussions, but there were other viewers mentioned (BigDataViewer etc) that it would be handy if everyone was on the same page.

will-moore commented 2 years ago

To summarise grouping of channels in pathviewer:

jburel commented 2 years ago

@will-moore formatting should be fixed

jburel commented 2 years ago
   "groups: [
      {
       "views": [id1, id2],
       "name": "Cycle1",
       "visible": "True",
      },
      {
       "views": [id3],
       "name": "Cycle2",
       "visible": "True",
      },
    ],
    "views": [
             { 
                 "id": xxx,
                 "angle": "",
                 "channel": "0",
                 "color": {}... etc.
              },
              {
                 "id": xxx,
                 "angle": "",
                  "channel": "1",
                  "color": {}... etc.
              }
        ],
   "colorModel": "color",
   "defaultPlane": [3,4] 
   "defaultIndices" = [5,10:20,0:200,null],   // (t,z, x, y) view only 0-200 on x axis and all values on y axis 
   "version": 3
will-moore commented 2 years ago

Fixing a few things:

edit: @will-moore I have added angle so people don't think we dropped it during our brainstorming

will-moore commented 2 years ago

I removed angle since it's not yet allowed as a dimension type by the spec v0.3 or v0.4 proposal at https://github.com/ome/ngff/pull/57/files#diff-ffe6148e5d9f47acc4337bb319ed4503a810214933e51f5f3e46a227b10e3fcdR214 Unless you want to suggest an update to that PR, or add "angle" as a specified type when we add rendering?

jburel commented 2 years ago

For the spec that we propose when ready we can omit angle if we are not ready at the ngff spec level yet. This is to avoid confusion amongst people currently involve in this discussion

jburel commented 2 years ago

With the current specification in mind We should have something like renderingSettings: a collection of renderingDefinition objects

"renderingDefinition": {
   "@id": "renderingDef1"
   "groups": [
        {
            "views": ["view1", "view2"],
            "name": "Cycle1",
            "visible": "True"
        },
        {
            "views": ["view3"],
            "name": "Cycle2",
            "visible": "True"
        }
    ],
    "views": [
        {
            "@id": "view1",
            "channel": 0,
            "visible": true,
            "coefficient": "1.0",
            "color": {
                "format": "name",
                "type": "lut",
                "value": "brgbcmyw.lut"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "linear",
            "label": "GFP",
            "noiseReduction": "False",
            "window": {
                "end": 188.89093017578125,
                "max": 188.89093017578125,
                "min": 0.007875712588429451,
                "start": 0.007875712588429451
            }
        },
        {
            "@id": "view2",
            "channel": 1,
            "visible": "False",
            "coefficient": "1.8",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "00FF00"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "exponential",
            "label": "DAPI",
            "noiseReduction": "False",
            "window": {
                "end": 1542.5789794921875,
                "max": 1542.5789794921875,
                "min": 0.0,
                "start": 0.0
            }
        },
        {
            "@id": "view3",
            "channel": 2,
            "visible": "True",
            "color": {
                "format": "hex",
                "type": "rgb",
                "value": "FFFFFF"
            },
            "deviceSpaceMapping": {
                "reverseIntensity": "False"
            },
            "family": "linear",
            "label": "OOOO",
            "noiseReduction": "False",
            "window": {
                "end": 1555.0537109375,
                "max": 1555.0537109375,
                "min": 0.0,
                "start": 0.0
            }
        }
    ],
    "colorModel": "color",
    // e.g. shape is (t,c,z,y,x)
    "defaultIndices": [5, null, 10:20, null, null],   // default view: t=5 and range 10-20 on z axis 
    // we want to view y,x plane by default
    "defaultPlane": [3, 4],
    "resolution": 0
}
jburel commented 2 years ago

One remaining question is about the LUT, it is currently identify by a name. Is that acceptable? or do we want to ship the binary? A viewer will still need to be able to read the LUT. I think the name of the lut e.g. a.lut will be enough for most cases i.e.

"color": {
                "format": "name",
                "type": "lut",
                "value": "brgbcmyw"
            },
jburel commented 2 years ago

@will-moore I have added a new parameter resolution. This is a value currently missing in our model and important when browsing pyramid for example

chris-allan commented 2 years ago

Yes, currently PathViewer's channel group specification allows for a channel to be in more than one group. There's lots of history there and @emilroz, @erindiel, and @knabar would be your authorities.

jburel commented 2 years ago

Suggestion from @chris-allan: use term palette instead LUT see https://en.wikipedia.org/wiki/List_of_color_palettes

jburel commented 2 years ago

https://colorcet.holoviz.org/