diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dfa3e2..9884712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#18](https://github.com/stac-extensions/render/issues/18)) - `bidx` index selectors are now documented and validated as 1-based integers (`minimum: 1`), matching the GDAL/rio-tiler/titiler convention ([#18](https://github.com/stac-extensions/render/issues/18)) +- **BREAKING** (to be released as a new major version): `colormap_name` MUST now be a standard + [matplotlib colormap](https://matplotlib.org/stable/users/explain/colors/colormaps.html) name (e.g. `viridis`, + `YlGn`), to give the field a well-known, renderer-agnostic naming convention instead of an arbitrary free-form + string ([#14](https://github.com/stac-extensions/render/issues/14)). The schema enforces it with an `enum` + of the 182 colormap names registered in matplotlib 3.11.2 (including `_r` variants); names are + case-sensitive, so e.g. `ylgn` must be written `YlGn` ### Added diff --git a/README.md b/README.md index 684330a..ca6c1a7 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ The fields in the table below can be used in these parts of STAC documents: | title | string | Optional title of the rendering | | rescale | \[float] | 2 dimensions array of delimited Min,Max range per band. If not provided, the data will not be rescaled. | | nodata | float, string | Nodata value to use for this render, overriding any nodata value already defined on the referenced assets (e.g. via the [raster](https://github.com/stac-extensions/raster) extension). If not set, implementations SHOULD fall back to the asset's own nodata value. | -| colormap_name | string | Color map identifier that must be applied for a raster band | +| colormap_name | string | Name of a standard [matplotlib colormap](https://matplotlib.org/3.11.2/users/explain/colors/colormaps.html) (e.g. `viridis`, `YlGn`) to apply to a raster band, including the reversed `_r` variants. The schema validates it against the colormaps registered in matplotlib 3.11.2, case-sensitively. Third party colormaps are not supported, use `colormap` instead. | | colormap | object | [Color map JSON definition](https://developmentseed.org/titiler/user_guide/rendering/#custom-colormaps) that must be applied for a raster band | | color_formula | string | [Color formula](https://developmentseed.org/titiler/user_guide/rendering/#color-formula) that must be applied for a raster band | | resampling | string | Resampling algorithm to apply to the referenced assets. See [GDAL resampling algorithm](https://gdal.org/programs/gdalwarp.html#cmdoption-gdalwarp-r) for some examples. | @@ -182,6 +182,17 @@ by simply specifying the `url` and `assets` query parameters. | `assets=\|bidx=,` (or the legacy `bidx` param) | `bidx`, resolving any name-based selector to a 1-based index via the asset's band metadata | Per-asset dataset band indexes. See [Band references](#band-references). | | `asset_as_band` | `asset_as_band` | Required when expression uses multiple single-band assets | +Titiler delegates colormaps to [rio-tiler](https://github.com/cogeotiff/rio-tiler)'s built-in registry +(`rio_tiler.colormap.cmap`), which is derived from matplotlib's colormaps but is not an exact match: + +- Names are **lowercased** (`colormap_name: "YlGn"` must be sent to titiler as `ylgn`). +- Reversed colormaps use matplotlib's `_r` suffix convention (e.g. `viridis_r`). +- The registry also includes some non-matplotlib colormaps (e.g. from [cmocean](https://matplotlib.org/cmocean/)), + and does not guarantee coverage of every matplotlib colormap name. + +A client sending `colormap_name` to titiler MUST lowercase the value first, and SHOULD verify the resulting +name is one titiler actually supports (`GET /colorMaps` lists the registered names) before assuming a match. + #### Shortwave Infra-red visual thermal signature example From the [Sentinel-2 item](examples/item-sentinel2.json): @@ -248,7 +259,7 @@ the NDVI asset could also be downloaded as a standalone asset. "title": "Normalized Difference Vegetation Index", "assets": [ "ndvi" ], "resampling": "average", - "colormap_name": "ylgn" + "colormap_name": "YlGn" } } } @@ -263,7 +274,7 @@ If this case, the parameters to titiler must be extracted from both the virtual | assets | Assets used in the expression, in the order they are referenced | `B08,B04` | | expression | Band math formula as defined in field `vrt:algorithm` | `(B08-B04)/(B08+B04)` | | rescale | Delimited Min,Max bounds defined in `rescale` field | `-1,1` | -| colormap_name | Color map name as defined in `colormap_name` | `ylgn` | +| colormap_name | Color map name as defined in `colormap_name`, lowercased | `ylgn` | | resampling_method | Resampling method to use when reprojecting the raster as defined in `resampling` | `average` | Example URL, using a self-hosted or public [titiler](https://github.com/developmentseed/titiler) instance. @@ -288,7 +299,7 @@ Obviously, the same rendering can be applied to local source assets without usin "title": "Normalized Difference Vegetation Index", "assets": [ "B08", "B04" ], "resampling": "average", - "colormap_name": "ylgn", + "colormap_name": "YlGn", "expression": "(B08-B04)/(B08+B04)", "rescale": [[-1,1]] } diff --git a/examples/collection.json b/examples/collection.json index fbcb943..5bc803a 100644 --- a/examples/collection.json +++ b/examples/collection.json @@ -69,7 +69,7 @@ "ndvi" ], "resampling": "average", - "colormap_name": "ylgn" + "colormap_name": "YlGn" } }, "summaries": { diff --git a/examples/item-landsat8.json b/examples/item-landsat8.json index aeb20a4..a09f1d7 100644 --- a/examples/item-landsat8.json +++ b/examples/item-landsat8.json @@ -57,7 +57,7 @@ "ndvi" ], "resampling": "average", - "colormap_name": "ylgn" + "colormap_name": "YlGn" } } }, diff --git a/examples/item-sentinel2.json b/examples/item-sentinel2.json index 9299745..67a0933 100644 --- a/examples/item-sentinel2.json +++ b/examples/item-sentinel2.json @@ -91,7 +91,7 @@ "ndvi" ], "resampling": "average", - "colormap_name": "ylgn" + "colormap_name": "YlGn" } } }, diff --git a/json-schema/schema.json b/json-schema/schema.json index eaebd12..95aaa58 100644 --- a/json-schema/schema.json +++ b/json-schema/schema.json @@ -251,7 +251,192 @@ ] }, "colormap_name": { - "type": "string" + "$comment": "Colormap names registered in matplotlib 3.11.2 (matplotlib.colormaps), including the reversed _r variants.", + "type": "string", + "enum": [ + "Accent", + "Accent_r", + "afmhot", + "afmhot_r", + "autumn", + "autumn_r", + "berlin", + "berlin_r", + "binary", + "binary_r", + "Blues", + "Blues_r", + "bone", + "bone_r", + "BrBG", + "BrBG_r", + "brg", + "brg_r", + "BuGn", + "BuGn_r", + "BuPu", + "BuPu_r", + "bwr", + "bwr_r", + "cividis", + "cividis_r", + "CMRmap", + "CMRmap_r", + "cool", + "cool_r", + "coolwarm", + "coolwarm_r", + "copper", + "copper_r", + "cubehelix", + "cubehelix_r", + "Dark2", + "Dark2_r", + "flag", + "flag_r", + "gist_earth", + "gist_earth_r", + "gist_gray", + "gist_gray_r", + "gist_grey", + "gist_grey_r", + "gist_heat", + "gist_heat_r", + "gist_ncar", + "gist_ncar_r", + "gist_rainbow", + "gist_rainbow_r", + "gist_stern", + "gist_stern_r", + "gist_yarg", + "gist_yarg_r", + "gist_yerg", + "gist_yerg_r", + "GnBu", + "GnBu_r", + "gnuplot", + "gnuplot2", + "gnuplot2_r", + "gnuplot_r", + "gray", + "gray_r", + "Grays", + "Grays_r", + "Greens", + "Greens_r", + "grey", + "grey_r", + "Greys", + "Greys_r", + "hot", + "hot_r", + "hsv", + "hsv_r", + "inferno", + "inferno_r", + "jet", + "jet_r", + "magma", + "magma_r", + "managua", + "managua_r", + "nipy_spectral", + "nipy_spectral_r", + "ocean", + "ocean_r", + "okabe_ito", + "okabe_ito_r", + "Oranges", + "Oranges_r", + "OrRd", + "OrRd_r", + "Paired", + "Paired_r", + "Pastel1", + "Pastel1_r", + "Pastel2", + "Pastel2_r", + "pink", + "pink_r", + "PiYG", + "PiYG_r", + "plasma", + "plasma_r", + "PRGn", + "PRGn_r", + "prism", + "prism_r", + "PuBu", + "PuBu_r", + "PuBuGn", + "PuBuGn_r", + "PuOr", + "PuOr_r", + "PuRd", + "PuRd_r", + "Purples", + "Purples_r", + "rainbow", + "rainbow_r", + "RdBu", + "RdBu_r", + "RdGy", + "RdGy_r", + "RdPu", + "RdPu_r", + "RdYlBu", + "RdYlBu_r", + "RdYlGn", + "RdYlGn_r", + "Reds", + "Reds_r", + "seismic", + "seismic_r", + "Set1", + "Set1_r", + "Set2", + "Set2_r", + "Set3", + "Set3_r", + "Spectral", + "Spectral_r", + "spring", + "spring_r", + "summer", + "summer_r", + "tab10", + "tab10_r", + "tab20", + "tab20_r", + "tab20b", + "tab20b_r", + "tab20c", + "tab20c_r", + "terrain", + "terrain_r", + "turbo", + "turbo_r", + "twilight", + "twilight_r", + "twilight_shifted", + "twilight_shifted_r", + "vanimo", + "vanimo_r", + "viridis", + "viridis_r", + "winter", + "winter_r", + "Wistia", + "Wistia_r", + "YlGn", + "YlGn_r", + "YlGnBu", + "YlGnBu_r", + "YlOrBr", + "YlOrBr_r", + "YlOrRd", + "YlOrRd_r" + ] }, "colormap": { "type": "object"