cellmap_flow.io.metadata

Array metadata for every format cellmap-flow reads, as one ArrayMeta.

read_array_meta(path) reads zarr v2 and v3, N5 and neuroglancer precomputed, on disk or at an http(s), s3 or gs URL: every document is read through io.store, so a URL reads as the same files on disk do. Every axis is kept, in the array’s own (C) order; sizes and translations are nanometer floats, and the translation is the lower corner of voxel 0 – an OME translation (voxel 0’s centre) is converted exactly, with no rounding onto the voxel grid. .spatial() drops the channel/time axes.

Four parsers produce it:

  • _ome: an OME-NGFF multiscales entry (v2 .zattrs and v3 zarr.json alike), matched on datasets[].path.

  • _n5: the N5/funlib attribute search – resolution, scale, pixelResolution x downsamplingFactors, transform, offset, units – on an array and its parent group, with the axis reversal N5 needs. zarr v2 arrays without OME metadata go through it too, and keep its rounding of the offset onto the voxel grid (regularize_offset).

  • legacy_attrs: transform or resolution/offset on a v3 array itself (and on crops), taken as written.

  • _precomputed: the volume’s info JSON, as tensorstore reads it.

list_levels(path) gives the levels of an OME multiscale group, or the scales of a precomputed volume.

Each format’s reader keeps the lookup order and fallbacks of the per-format reader it replaced; tests/utils/test_io_metadata.py pins them.

Attributes

logger

NANOMETER

Classes

ArrayMeta

What one array is, independent of its format.

Functions

nm_per_unit(→ float)

How many nanometers one unit is; 1 for a missing or unknown unit.

to_nm(→ Tuple[float, ...])

values (one per axis) in nanometers; units None means nm.

spatial_axes(axes)

Indices, names and units of the spatial axes of an OME axes list.

snap_integral(values)

values as floats, with near-whole numbers made exactly whole.

is_integral(→ bool)

regularize_offset(voxel_size_float, offset_float)

offset is not a multiple of voxel_size. This is often due to someone defining

match_dataset(→ Optional[dict])

The datasets entry of one multiscales item whose path is

dataset_transforms(entry)

(scale, translation) of an OME datasets entry as written, each

n5_voxel_size(items, order)

The voxel size in the first of items (array attrs, then its

n5_offset(items, order)

offset, or transform.translate, as n5_voxel_size finds it.

n5_units(items, order, ndim)

units, pixelResolution.unit or transform.units, one per

legacy_attrs(→ Tuple[List[float], List[float]])

(voxel_size, offset) from an array's own transform or

read_zarr_json(→ dict)

The zarr.json of the v3 node at path; FileNotFoundError when

attrs_from_meta(→ dict)

Merge OME-NGFF 0.5's nested attributes.ome with the top-level

multiscales_from_group(→ Optional[dict])

The first multiscales item of a v3 group, or None (also for an array).

node_type(→ Tuple[str, str])

(node, "group" or "array"): the zarr v2, v3 or N5 node that

read_array_meta(→ ArrayMeta)

Metadata of the array at path (see the module docstring). A path at

list_levels(→ List[Tuple[str, ArrayMeta]])

[(dataset path, ArrayMeta)] for each level of the OME multiscale

Module Contents

cellmap_flow.io.metadata.logger
cellmap_flow.io.metadata.NANOMETER = 'nanometer'
cellmap_flow.io.metadata.nm_per_unit(unit) → float

How many nanometers one unit is; 1 for a missing or unknown unit.

cellmap_flow.io.metadata.to_nm(values, units) → Tuple[float, ...]

values (one per axis) in nanometers; units None means nm.

cellmap_flow.io.metadata.spatial_axes(axes)

Indices, names and units of the spatial axes of an OME axes list.

Returns (None, None, None) when there is no axes list. Axes typed “space” are spatial; untyped ones are unless named like a channel or time axis (OME 0.3 lists bare names).

cellmap_flow.io.metadata.snap_integral(values)

values as floats, with near-whole numbers made exactly whole.

cellmap_flow.io.metadata.is_integral(values) → bool
cellmap_flow.io.metadata.regularize_offset(voxel_size_float, offset_float)

offset is not a multiple of voxel_size. This is often due to someone defining offset to the point source of each array element i.e. the center of the rendered voxel, vs the offset to the corner of the voxel. apparently this can be a heated discussion. See here for arguments against the convention we are using: http://alvyray.com/Memos/CG/Microsoft/6_pixel.pdf

Only the legacy (non-OME) attributes go through this; an OME translation is converted to a corner exactly instead.

Parameters:
  • voxel_size_float ([float]) – float voxel size list

  • offset_float ([float]) – float offset list

Returns:

returned offset size that is multiple of voxel size. For a non-integer voxel size, two tuples of floats instead (the same rounding, without truncating the voxel size to an integer first).

Return type:

(Coordinate, Coordinate))

class cellmap_flow.io.metadata.ArrayMeta

What one array is, independent of its format.

Every per-axis tuple has one entry per array dimension, in the array’s (C) order. units[i] is “nanometer” on a spatial axis – its voxel_size and translation have been converted to nm – and None on a channel or time axis, where voxel_size is 1.0 and translation 0.0. translation is the lower corner of voxel 0. An axis nobody named has the name “”.

format is “zarr2”, “zarr3”, “n5” or “precomputed”.

path: str
format: str
shape: Tuple[int, ...]
dtype: numpy.dtype | None
chunk_shape: Tuple[int, ...]
axes: Tuple[str, ...]
units: Tuple[str | None, ...]
voxel_size: Tuple[float, ...]
translation: Tuple[float, ...]
fill_value: object = None
property spatial_indices: Tuple[int, ...]
property channel_axis: int | None

The first non-spatial axis that is not time, or None.

spatial() → ArrayMeta

This array’s metadata with only its spatial axes.

cellmap_flow.io.metadata.match_dataset(multiscale: dict, dataset_path: str) → dict | None

The datasets entry of one multiscales item whose path is dataset_path (leading and trailing “/” ignored), or None.

cellmap_flow.io.metadata.dataset_transforms(entry: dict)

(scale, translation) of an OME datasets entry as written, each None when the entry has none.

cellmap_flow.io.metadata.n5_voxel_size(items: Sequence[dict], order: str)

The voxel size in the first of items (array attrs, then its parent’s) that has one: resolution, scale, pixelResolution times downsamplingFactors, or transform.scale.

order is the axis order the caller reads in (“C”, or “F” for N5). transform states its own ordering (C unless it says otherwise: Davis writes C order whatever the store) and is reversed to order.

cellmap_flow.io.metadata.n5_offset(items: Sequence[dict], order: str)

offset, or transform.translate, as n5_voxel_size finds it.

cellmap_flow.io.metadata.n5_units(items: Sequence[dict], order: str, ndim: int)

units, pixelResolution.unit or transform.units, one per axis (see _per_axis); ndim “pixels” when there are none.

cellmap_flow.io.metadata.legacy_attrs(attrs: dict, ndim: int) → Tuple[List[float], List[float]]

(voxel_size, offset) from an array’s own transform or resolution/offset attributes, as written; 1 and 0 without them.

For zarr v3 plain arrays and imported crops, which never went through the N5 search: no parent lookup, no units, no rounding.

cellmap_flow.io.metadata.read_zarr_json(path: str) → dict

The zarr.json of the v3 node at path; FileNotFoundError when there is none.

cellmap_flow.io.metadata.attrs_from_meta(meta: dict) → dict

Merge OME-NGFF 0.5’s nested attributes.ome with the top-level attributes dict (some writers emit OME metadata unnested).

cellmap_flow.io.metadata.multiscales_from_group(group_path: str) → dict | None

The first multiscales item of a v3 group, or None (also for an array).

cellmap_flow.io.metadata.node_type(path: str) → Tuple[str, str]

(node, "group" or "array"): the zarr v2, v3 or N5 node that answers for path and what it is. The node is path itself, except on disk under a v3 node (_v3_node). FileNotFoundError when there is none.

cellmap_flow.io.metadata.read_array_meta(path: str) → ArrayMeta

Metadata of the array at path (see the module docstring). A path at a group reads its first level: the first its multiscales list, else its first array (_child_names).

cellmap_flow.io.metadata.list_levels(group_path: str) → List[Tuple[str, ArrayMeta]]

[(dataset path, ArrayMeta)] for each level of the OME multiscale group at group_path, in the order its datasets list them, or of the precomputed volume there (_precomputed_levels).

Raises when there is no such group (KeyError for a v2 group without multiscales, ValueError for a v3 one).