xcube-dev / xcube

xcube is a Python package for generating and exploiting data cubes powered by xarray, dask, and zarr.
https://xcube.readthedocs.io/
MIT License
195 stars 18 forks source link

Configure custom color maps in xcube server #1046

Closed forman closed 1 month ago

forman commented 2 months ago

Is your feature request related to a problem? Please describe.

Since xcube 1.6, xcube server accepts custom color maps from xcube viewer. We want to allow configuring the same type of custom color maps in xcube server, namely

Describe the solution you'd like

CustomColorMaps:
  - Identifier: my_categorical_cmap
    Type: categorical     # or continuous, stepwise 
    Colors:
    - Value: 0
      Color: red
      Label: low
    - Value: 1
      Color: #0000FF
      Label: medium
    - Value: 2
      Color: 0,0,255
      Label: high
  - ...

EDIT:

An entry in the in the Colors list may have one of the following forms (TypeScript notation):


type ColorEntry = ColorEntryObj | ColorEntryTuple;

interface ColorEntryObj {
  Value: number;
  Color: Color;
  Label?: string;
}

type ColorEntryTuple = [number, Color] | [number, Color: label];

type Color = ColorName | ColorHex | ColorTuple;
type ColorName = <A CSS color name>; 
type ColorHex = <A CSS color in hexdecimal form>;
type ColorTuple = [number, number, number] | [number, number, number, number]
forman commented 2 months ago

Here is another practical example for Sentinel 2 level 2, scene classification band SCL:

CustomColorMaps:
  - Identifier: S2_L2_SCL
    Type: categorical 
    Colors:
    - [ 0, red,     no data]
    - [ 1, yellow,  defective]
    - [ 2, black,   dark area pixels]
    - [ 3, gray,    cloud shadows]
    - [ 4, green,   vegetation]
    - [ 5, tan,     bare soils]
    - [ 6, blue,    water]
    - [ 7, "#aaaabb", clouds low prob ]
    - [ 8, "#bbbbcc", clouds medium prob]
    - [ 9, "#ccccdd", clouds high prob]
    - [10, "#ddddee", cirrus]
    - [11, "#ffffff", snow or ice]
forman commented 1 month ago

@konstntokas, I just tested PR #1055 with a real-life server configuration and I see several problems, therefore I reopened the issue:

I'm sorry that I didn't discover the problems during the PR review which concentrated on plain code review rather than on practical experience.

forman commented 1 month ago

Proof for my point 2: /colorbars returns

[ 
  "Custom", 
  "Custom colormaps, e.g. loaded from SNAP *.cpd files or defined via the xcube server config file.",
  [ 
    [
      "s2_l2_scl", 
      "iVBORw0KGgoAAAA...kSuQmCC", 
      { 
        "name": "s2_l2_scl", 
        "type": "categorical", 
        "colors": [ 
          [ 0, "red" ], [ 1, "yellow" ], [ 2, "black" ], [ 3, "gray" ], [ 4, "green" ], [ 5, "tan" ], [ 6, "blue" ], 
          [ 7, "#aaaabb" ], [ 8, "#bbbbcc" ], [ 9, "#ccccdd" ], [ 10, "#ddddee" ], [ 11, "#ffffff" ] ] 
      } 
    ] 
  ] 
]

for

CustomColorMaps:
  - Identifier: s2_l2_scl
    Type: categorical
    Colors:
    - [ 0, red,     no data]
    - [ 1, yellow,  defective]
    - [ 2, black,   dark area pixels]
    - [ 3, gray,    cloud shadows]
    - [ 4, green,   vegetation]
    - [ 5, tan,     bare soils]
    - [ 6, blue,    water]
    - [ 7, "#aaaabb", clouds low prob ]
    - [ 8, "#bbbbcc", clouds medium prob]
    - [ 9, "#ccccdd", clouds high prob]
    - [10, "#ddddee", cirrus]
    - [11, "#ffffff", snow or ice]
konstntokas commented 1 month ago

@konstntokas, I just tested PR #1055 with a real-life server configuration and I see several problems, therefore I reopened the issue:

* The most important use case of the `CustomColorMaps` is creating categorical color maps. But the endpoint `/colorbars` drops the labels from the color entries.

* `CustomColorMaps` are only returned by the server if they are actually used in the current configuration. That was not the intention. The server must publish all custom color maps for use by the viewer and other clients.

* Why do you use `CustomColorBar` instead of the existing `ColorBar` key in a `ColorMappings` value? `ColorBar` should be fine, because `CustomColorMaps` should be treated like "normal" color maps.

I'm sorry that I didn't discover the problems during the PR review which concentrated on plain code review rather than on practical experience.

No problem; I was thinking about the levels at one point, but then forgot about them as well. The rest mainly comes from the fact that I took the ColorFile case as a analogy. See my comments below regarding the individual points:

I suggest to move ColorFile to CustomColorMaps, so that all custom color maps are in one place and cvan be accessed via an identifier. We evaluate all custom color maps and add them to the 'general' color maps, which will be all available at the endpoint /colorbars. In the Styles section, we only use ColorBar for any case where ValueRange is not allowed for custom color bars.

forman commented 1 month ago

I will add the labels to the publication at the /colorbar endpoint.

Ok.

Adding all defined custom color maps make sense so the will be available in the color map selector field. But then I would also suggest to apply the same methodology to ColorFile to be consistent.

Ok, but not now. Please apply the changes for CustomColorMaps first.

I use CustomColorBar to get a distinctive case in the if/elif/esle statement deciding between ColorFile, CustomColorBar and 'general' colormaps. I think it does not make sense to allow the user using ColorBar and ValueRange for custom color maps.

Don't do that. Color maps must be identified through their identifier, independently of their type or origin.

forman commented 1 month ago

I suggest to move ColorFile to CustomColorMaps.

Not now.

forman commented 1 month ago

@konstntokas please create a new issue afterwards for a more consistent handling of color maps from SNAP CPD files.

konstntokas commented 1 month ago

@konstntokas please create a new issue afterwards for a more consistent handling of color maps from SNAP CPD files.

see #1058

konstntokas commented 1 month ago

Colors defined as RGB are making problems in the viewer due to the viewer only accepts uint8 value range (0-255) and not 0-1 ranges. See https://github.com/xcube-dev/xcube-viewer/issues/392#issuecomment-2284310738

To fix this, all RGBs are converted to HEX. Note that matplotlib.colors.rgb2hex only allows value ranges from 0-1. Thus, if RGB is given in a range of 0-255, the range will be converted to 0-1.