Idea
Add a lightweight map interface at /maps where users can select any published dataset and see it visualised on a map, with a time slider to step through available time steps. Display parameters (color scale, colormap, value range) are defined in the dataset YAML and published through the existing STAC catalog — so any STAC-compatible tool benefits, not just the built-in viewer.
A proof of concept already exists at dhis2/climate-map using MapLibre GL and @carbonplan/zarr-layer. The library reads the Zarr store directly from the browser via HTTP range requests — no tile server required.
How display metadata flows
dataset YAML → STAC collection → /maps viewer
↑ ↑
(authored) (generated at publish time,
same as pygeoapi config today)
STAC extensions
Two existing STAC extensions cover almost everything needed:
Render extension — display parameters per asset:
"renders": {
"default": {
"title": "Daily precipitation",
"assets": ["zarr"],
"rescale": [[0.0, 20.0]],
"colormap_name": "blues",
"nodata": 0.0
}
}
rescale maps directly to @carbonplan/zarr-layer's clim parameter. nodata maps to fillValue.
Datacube extension — time axis metadata:
"cube:dimensions": {
"time": {
"type": "temporal",
"extent": ["2021-01-01", "2025-12-31"],
"step": "P1D"
}
}
The step field (or an explicit values array for irregular intervals) gives the map viewer everything it needs to build a time slider. The viewer calls layer.setSelector({ time: i }) to jump between steps without reloading the full Zarr.
Dataset YAML additions
A new display block in the dataset template:
display:
colormap: blues # named colormap
range: [0.0, 20.0] # default clim / rescale range
units: mm/day
nodata: 0.0
At publish time, publications/services.py already generates config from artifact metadata. The same step would populate the STAC Render and Datacube fields from the artifact's display block and its time extent.
The /maps viewer
A single-page HTML/JS app bundled with the package and served as a static mount at /maps. It:
- Fetches
/stac/catalog.json to list published datasets
- Lets the user select one — loads the STAC collection to read
renders and cube:dimensions
- Initialises a MapLibre map with a
ZarrLayer pointed at the Zarr asset href, using rescale for clim and the colormap for the color ramp
- Renders a time slider from the temporal dimension metadata; each step calls
layer.setSelector({ time: i })
No tile server, no server-side rendering. The browser reads the Zarr directly via the existing /zarr/{dataset_id} HTTP range endpoint.
Gaps and implementation notes
| Gap |
Resolution |
colormap_name is a string but zarr-layer wants a hex array |
Either bundle a colormap lookup table in the frontend, or include the hex array as an extra field on the render object (the Render extension spec permits additional fields) |
variable name (which Zarr variable to render) has no STAC home |
Add as climate_api:variable on the render object — one line, consistent with STAC extension conventions for vendor fields |
latIsAscending (Zarr axis orientation) |
Can be derived at runtime from the coordinate array; no need to store in STAC |
| Colormap vs value range per period type |
Some datasets (WorldPop population) need a very different range from precipitation. display in the YAML is per dataset template, so each template carries its own defaults |
Why this is worth doing
- The PoC proves the rendering approach works with the current Zarr endpoint — no new server infrastructure needed
- STAC Render + Datacube metadata is useful beyond the built-in viewer: TiTiler, QGIS, and other STAC-aware tools can pick up the same display hints
- It makes the API explorable without any external tooling — a health ministry analyst can open
/maps and see what data is available
- The
display block in the dataset YAML is the natural place for this metadata; it keeps rendering intent with the dataset definition rather than scattered across frontend config files
Idea
Add a lightweight map interface at
/mapswhere users can select any published dataset and see it visualised on a map, with a time slider to step through available time steps. Display parameters (color scale, colormap, value range) are defined in the dataset YAML and published through the existing STAC catalog — so any STAC-compatible tool benefits, not just the built-in viewer.A proof of concept already exists at dhis2/climate-map using MapLibre GL and
@carbonplan/zarr-layer. The library reads the Zarr store directly from the browser via HTTP range requests — no tile server required.How display metadata flows
STAC extensions
Two existing STAC extensions cover almost everything needed:
Render extension — display parameters per asset:
rescalemaps directly to@carbonplan/zarr-layer'sclimparameter.nodatamaps tofillValue.Datacube extension — time axis metadata:
The
stepfield (or an explicitvaluesarray for irregular intervals) gives the map viewer everything it needs to build a time slider. The viewer callslayer.setSelector({ time: i })to jump between steps without reloading the full Zarr.Dataset YAML additions
A new
displayblock in the dataset template:At publish time,
publications/services.pyalready generates config from artifact metadata. The same step would populate the STAC Render and Datacube fields from the artifact'sdisplayblock and its time extent.The
/mapsviewerA single-page HTML/JS app bundled with the package and served as a static mount at
/maps. It:/stac/catalog.jsonto list published datasetsrendersandcube:dimensionsZarrLayerpointed at the Zarr assethref, usingrescaleforclimand the colormap for the color ramplayer.setSelector({ time: i })No tile server, no server-side rendering. The browser reads the Zarr directly via the existing
/zarr/{dataset_id}HTTP range endpoint.Gaps and implementation notes
colormap_nameis a string butzarr-layerwants a hex arrayvariablename (which Zarr variable to render) has no STAC homeclimate_api:variableon the render object — one line, consistent with STAC extension conventions for vendor fieldslatIsAscending(Zarr axis orientation)displayin the YAML is per dataset template, so each template carries its own defaultsWhy this is worth doing
/mapsand see what data is availabledisplayblock in the dataset YAML is the natural place for this metadata; it keeps rendering intent with the dataset definition rather than scattered across frontend config files