Skip to content

Map viewer at /maps with STAC-backed display metadata #66

@turban

Description

@turban

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:

  1. Fetches /stac/catalog.json to list published datasets
  2. Lets the user select one — loads the STAC collection to read renders and cube:dimensions
  3. Initialises a MapLibre map with a ZarrLayer pointed at the Zarr asset href, using rescale for clim and the colormap for the color ramp
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions