ZarrLayerProvider
The ZarrLayerProvider allows you to render 2D raster data from Zarr datasets as a Cesium imagery layer. It handles:
- Reading Zarr metadata and multiscale pyramids
- WebGL rendering of tiles (fast GPU-based color mapping)
- Dynamic slicing of dimensions (e.g., time, elevation)
- Runtime style updates (colormap, scale, opacity)
- CRS detection (
EPSG:4326/EPSG:3857) - Smooth integration with Cesium’s
ImageryLayercollection
This provider works as a drop-in replacement for Cesium imagery layers, enabling you to visualize 2D scalar fields (e.g., temperature, salinity, chlorophyll) stored in Zarr format, without any server-side preprocessing or conversion.
When to Use ZarrLayerProvider
Use ZarrLayerProvider when your dataset is:
- 2D (lat × lon)
- Optionally has extra dimensions:
time,elevation,depth, etc. - Stored as a Zarr array, possibly multiscale
- Represents scalar fields (not vectors)
If you need:
- 3D rendering → use ZarrCubeProvider
- 3D vector fields → use ZarrCubeVelocityProvider
- 2D tiled imagery using a backend server → use titiler
Basic Example
import { Viewer } from 'cesium';
import { ZarrLayerProvider } from 'zarr-cesium';
const viewer = new Viewer('cesiumContainer');
const options = {
url: 'https://example.com/data.zarr',
variable: 'salinity',
colormap: 'viridis',
scale: [30, 40]
};
const zbLayer = await ZarrLayerProvider.createLayer(viewer, options);
viewer.imageryLayers.add(zbLayer);
This method:
- Creates the provider
- Loads Zarr metadata
- Detects CRS
- Sets tiling scheme
- Loads the first dimension slice
- Returns a ready-to-use
ZarrImageryLayer
Options
export interface LayerOptions {
url: string; // Public Zarr store
variable: string; // Zarr array name
scale?: [number, number]; // Min/max for color scaling
colormap?: ColorMapName; // Name from jsColormaps, based on matplotlib colormaps
opacity?: number; // Imagery opacity (0–1)
tileWidth?: number; // Cesium tile size (default 256)
tileHeight?: number; // Cesium tile size (default 256)
minimumLevel?: number; // Min zoom level
maximumLevel?: number; // Max zoom level
dimensionNames?: DimensionNamesProps; // Custom dimension names. If not provided, defaults will be used or identified automatically based on CF conventions.
selectors?: Record<string, ZarrSelectorsProps>; // Initial dimension slices
zarrVersion?: 2 | 3; // Zarr version (auto-detected if not set)
crs?: 'EPSG:4326' | 'EPSG:3857'; // Force CRS (auto-detected if not set)
noDataMin?: number; // Custom no-data minimum value. Overrides _FillValue/missing_value.
noDataMax?: number; // Custom no-data maximum value. Overrides _FillValue/missing_value.
}
Dimension Selectors
If your Zarr dataset has dimensions like: time, level related (e.g. depth, elevation), and others, you can slice them using the selectors option.
You can set an initial slice using:
// LayerOptions
selectors: {
time: { type: 'index', selected: 0 },
elevation: { type: 'index', selected: 10 }
}
Or slice by value instead of index:
// LayerOptions
selectors: {
time: { type: 'value', selected: '2020-01-01T00:00Z' },
elevation: { type: 'value', selected: 50 } // meters
}
The provider automatically converts value→index using nearest-neighbor lookup. The default behavior (if no selectors are provided) is to select the first index (0) for each dimension.
Supported CRS
Zarr datasets may store coordinate values in:
EPSG:4326(lat, lon degrees)EPSG:3857(Web Mercator meters)
The provider detects the CRS automatically using:
- Zarr metadata
- consolidated metadata
- coordinate ranges (West/East > 360 → Web Mercator)
For example, you can set the CRS explicitly:
// set CRS to Web Mercator in LayerOptions
crs: 'EPSG:3857';
Multiscale Support
If the dataset contains Zarr multiscale metadata (generated by ndpyramid):
"multiscales": [
{
"datasets": [
{"path": "0"}, {"path": "1"}, {"path": "2"}
]
}
]
The provider automatically:
- chooses the best level based on Cesium zoom
- caches levels (LRU = 3)
- correctly slices each level
- uses metadata-supported shapes for accurate scaling
No extra configuration is required.
No-data Handling
Automatically applies:
_FillValuemissing_valuevalid_min/valid_max- or custom range
Example of custom range:
// LayerOptions
noDataMin: -9999, // defaults is to Zarr attributes and then -9999
noDataMax: 9999 // defaults is to Zarr attributes and then 9999
Runtime API
When added to Cesium, the layer behaves like a normal ImageryLayer, plus extra Zarr-specific features.
const zbLayer = await ZarrLayerProvider.createLayer(viewer, options);
viewer.imageryLayers.add(zbLayer);
Update Style (colormap, scale and opacity)
- colormap
zbLayer.updateStyle({ colormap: 'plasma' });
The full list of supported colormaps is available in the Colormaps section.
- scale range
zbLayer.updateStyle({ scale: [20, 35] });
- opacity
zbLayer.updateStyle({ opacity: 0.5 });
// or using Cesium ImageryLayer API
// zbLayer.alpha = 0.5;
After updating style, the layer performs a soft refresh so Cesium re-renders the tiles in the viewport with the new style.
Update dimension slicing
zbLayer.updateSelectors({
time: { type: 'index', selected: 5 }
});
You can get the list of current dimension and current selectors values using:
const dimValues = zbLayer.provider.dimensionValues;
const selectors = zbLayer.provider.selectors;
This returns a mapping of dimension names to their list of values, e.g.:
dimNames = {
time: ['2020-01-01T00:00Z', '2020-01-02T00:00Z', ...],
elevation: [0, 10, 20, 30, ...]
}
And the current selectors:
selectors = {
time: { type: 'index', selected: 5 },
elevation: { type: 'index', selected: 2 }
};
And with that, you can build UI controls (sliders, dropdowns) to update the layer dynamically.
Remove Layer
To remove the layer and free resources:
viewer.imageryLayers.remove(zbLayer);
zbLayer.destroy();
It is important to call destroy() after removing the layer from the viewer, because this cleans up all internal resources (abort pending requests, etc.).
Summary
| Feature | Supported |
|---|---|
| 2D raster Zarr | ✔️ |
| Zarr v2 & v3 | ✔️ |
| Time dimension | ✔️ |
| Elevation/depth | ✔️ |
| Multiscale pyramids | ✔️ |
| WebGL GPU shading | ✔️ |
| Colormap updates | ✔️ |
| Dynamic slicing | ✔️ |
| CRS auto-detection | ✔️ |
Next Steps
- ZarrCubeProvider – render 3D volumes
- ZarrCubeVelocityProvider – render vector fields
- Data Preparation – Prepare Zarr datasets for the browser