OME-Zarr storage layout, sharding, and pyramids for fast viewing.
The viewer streams OME-Zarr image data over HTTP, tile by tile. Storage layout determines loading speed, memory use, and interactivity.
| Recommended | Avoid | |
|---|---|---|
| Zarr version | Zarr v3 (OME-NGFF 0.5) with sharding_indexed | Zarr v2 or unsharded v3 |
| Pyramid | ≥ 4 resolution levels (LODs) | Single LOD |
| Inner chunk (XY) | 512 × 512 px or 256 × 256 | Anything that covers a full XY plane |
Storage layout directly affects image loading speed and interactivity. Multi-scale pyramids and appropriately sized chunks help the viewer load only the image data needed for the current view.
OME-NGFF 0.5 stores data as Zarr v3. The sharding_indexed codec packs many small inner chunks into larger shard files on disk, which is ideal for HTTP access:
| Field | Recommendation |
|---|---|
| Chunk shape | Keep inner XY dimensions at or below 512 × 512, for example (1, 1, 1, 256, 256) |
| Shard shape | Group multiple inner chunks while keeping shard files practical for the storage backend |
| Codec | Use sharding_indexed with a supported inner compression codec |
The inner chunk shape controls each image fetch. Shard size, dtype, compression, and storage latency also affect performance, so benchmark the intended backend with representative images.
Any zarr inspector that exposes shape + chunking will do. iohub (a separate tool) needs no permanent install:
uvx iohub info --verbose <plate.zarr>Look for inner chunks ≤ 512 × 512:
Chunk size: (1, 1, 1, 256, 256) ← inner chunk
No. bytes decompressed: 1.4 TiB ← sanity check on total sizeAnd 4–5 resolution levels per position:
0 (1, 12, 1, 104683, 104776) float32 ← LOD 0: full res
1 (1, 12, 1, 52342, 52388) float32
2 (1, 12, 1, 26171, 26194) float32
3 (1, 12, 1, 13086, 13097) float32
4 (1, 12, 1, 6543, 6549) float32 ← LOD 4: thumbnailPyramids (multi-scale / multi-resolution) are strongly recommended. Without them the background thumbnail must read full-resolution chunks, which delays each field-of-view change.
from iohub import open_ome_zarr
with open_ome_zarr("plate.zarr", mode="r+") as plate:
for _, position in plate.positions():
position.make_multiscale(
scale_factors=[[1, 1, 2, 2]], # downsample XY by 2×
chunks=(1, 1, 1, 512, 512),
num_levels=4,
)Zarr v2 (OME-NGFF 0.4) works, with caveats:
(1, 1, 1, 748, 1135) chunk forces the client to download a 748 × 1135 px plane to display a 10 × 10 px region.Pyramids matter as much for v2 as for v3 because the background-loading path does not change with storage version.