Getting Started
Installation
npm install zarr-maps
# or
yarn add zarr-maps
Basic Example
1. Leaflet
import L from 'leaflet';
import { ZarrLayer } from 'zarr-maps/leaflet';
const map = L.map('map', {
center: [36.1, -5.4],
zoom: 6
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
const options = {
url: 'https://example.com/data.zarr',
variable: 'salinity',
colormap: 'viridis',
scale: [30, 40]
};
const zarrLayer = new ZarrLayer(options);
// Load Zarr metadata before adding to map
await zarrLayer.load();
zarrLayer.addTo(map);
This:
- Creates the Leaflet map
- Creates the ZarrLayer with options
- Loads Zarr metadata
- Detects CRS
- Loads dimension values (time/depth/etc.)
- Starts rendering tiles on demand as Leaflet requests them
Example of visualizing a Zarr dataset in a Leaflet map using zarr-maps. You can dynamically change time slices, colormaps, and scale ranges.
2. OpenLayers
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import { ZarrLayer } from 'zarr-maps/ol';
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
center: [0, 0],
zoom: 2,
projection: 'EPSG:3857'
})
});
const options = {
url: 'https://example.com/data.zarr',
variable: 'salinity',
colormap: 'viridis',
scale: [30, 40]
};
const zarrLayer = new ZarrLayer(options);
// Load Zarr metadata before adding to map
await zarrLayer.load();
map.addLayer(zarrLayer);
This:
- Creates the OpenLayers map
- Creates the ZarrLayer with options
- Loads Zarr metadata
- Detects CRS
- Loads dimension values (time/depth/etc.)
- Starts rendering tiles on demand as OpenLayers requests them
Example of visualizing a Zarr dataset in a OpenLayers map using zarr-maps. You can dynamically change time slices, colormaps, and scale ranges.
Options
1. Leaflet
export interface LeafletLayerOptions {
id: string; // Unique layer ID
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)
tileSize?: number; // Leaflet tile size (default 256)
maxZoom?: number; // Max zoom level
dimensionNames?: DimensionNamesProps; // Custom dimension names. If not provided, defaults will be used or identified automatically based on CF conventions.
selectors?: ZarrSelectors; // 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.
}
2. OpenLayers
export interface OLLayerOptions {
id: string; // Unique layer ID
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)
tileSize?: number; // Leaflet tile size (default 256)
maxZoom?: number; // Max zoom level
dimensionNames?: DimensionNamesProps; // Custom dimension names. If not provided, defaults will be used or identified automatically based on CF conventions.
selectors?: ZarrSelectors; // 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 Leaflet 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 Leaflet, the layer behaves like a normal L.Layer, plus extra Zarr-specific features.
const zarrLayer = new ZarrLayer(options);
map.addLayer(zarrLayer);
Update Style (colormap, scale and opacity)
- colormap
zarrLayer.updateStyle({ colormap: 'plasma' });
The full list of supported colormaps is available in the Colormaps section.
- scale range
zarrLayer.updateStyle({ scale: [20, 35] });
- opacity
zarrLayer.updateStyle({ opacity: 0.5 });
After updating style, the layer performs a soft refresh so Leaflet re-renders the tiles in the viewport with the new style.
Update dimension slicing
zarrLayer.updateSelectors({
time: { type: 'index', selected: 5 }
});
You can get the list of current dimension and current selectors values using:
const dimValues = zarrLayer.provider.dimensionValues;
const selectors = zarrLayer.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:
map.removeLayer(layer);