Skip to content

Data

Data stores hold the arrays backing each visual, along with the request and slice-result types used to fetch data for the current view.

Common

cellier.data.DataStoreType module-attribute

Images

cellier.data.image.ImageMemoryStore

Bases: BaseDataStore

In-memory image data store backed by a numpy array.

Serves axis-aligned slices or full sub-volumes to the AsyncSlicer. All reads are synchronous (the array is in CPU RAM); the method is still declared async to satisfy the AsyncSlicer contract.

Parameters:

Name Type Description Default
data ndarray

The image data. Any dtype; coerced to float32 on construction. Shape convention follows numpy axis order — e.g. (D, H, W) for 3-D, (H, W) for 2-D, (T, C, D, H, W) for 5-D.

required
name str

Human-readable label. Default "image_memory_store".

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

The store's coordinate system, as a one-entry list built by the caller, with one axis per array dimension. A voxel grid is sample-indexed, so build its axes with sampling="discrete". Empty by default, in which case the store takes the scene's world axes when it is added to a scene.

required
level_scales list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_translations list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_transforms list[AffineTransform]

The level-0 identity, installed from data_coordinate_systems. Not normally passed.

required

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

ndim property

ndim: int

Number of dimensions in the stored array.

shape property

shape: tuple[int, ...]

Shape of the stored array in numpy axis order.

n_levels property

n_levels: int

Always 1 — single-resolution, no multiscale pyramid.

level_shapes property

level_shapes: list[tuple[int, ...]]

List with one entry (level 0 = the full array).

axis_extents property

axis_extents: tuple[tuple[float, float], ...]

Per-axis (low, high) extents in level-0 data coordinates.

The edge convention: an axis of size voxels spans [-0.5, size - 0.5]. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

__setattr__

__setattr__(name: str, value: Any) -> None

Assign a field, announcing the change when it is a data field.

A class-level hook rather than a connection to self.events made in model_post_init: model_copy(deep=True) -- which to_model and from_model use -- runs no model_post_init, so a connection would silently go missing on every copy. Construction assigns through __dict__ and announces nothing.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

model_post_init

model_post_init(__context: Any) -> None

Check the systems passed at construction and install their transforms.

Stores that open array handles in their own model_post_init call this after opening them: the level count and rank it checks against are read off the handles.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

dataset_info

dataset_info() -> DatasetInfo

Describe the array: shape, dtype, value range and footprint.

The value range is a full pass over the array, affordable only because the data is already resident in RAM. The zarr-backed stores deliberately omit it (see their dataset_info).

get_data async

get_data(request: ChunkRequest) -> ndarray

Return the requested sub-region as a float32 array.

Interprets request.axis_selections generically:

  • int entry → sliced axis; the integer index is applied and the axis is dropped from the output.
  • (start, stop) tuple → displayed axis; a slice is applied and the axis is kept in the output.

Out-of-bounds coordinates are clamped to array extents and zero-padded on the output side so the returned shape always matches what the caller requested.

Parameters:

Name Type Description Default
request ChunkRequest

Built by GFXImageMemoryVisual.build_slice_request[_2d]. request.scale_index is always 0 (ignored). request.axis_selections has one entry per data axis.

required

Returns:

Type Description
ndarray

float32 array with one dimension per displayed (tuple) axis.

cellier.data.image.MultiscaleZarrDataStore pydantic-model

Bases: TensorStoreCacheMixin, BaseDataStore

Data store for a multiscale zarr volume read via tensorstore.

Public fields are validated and serialisable (pydantic). Tensorstore handles are opened synchronously in model_post_init and stored as private attributes so they are not serialised.

Parameters:

Name Type Description Default
store_type Literal['multiscale_zarr']

Discriminator field. Always "multiscale_zarr".

required
zarr_path

Path to the root directory of the multiscale zarr store. Pass as a string; pathlib.Path is accepted and coerced.

required
scale_names

Ordered list of subdirectory names, finest → coarsest, e.g. ["s0", "s1", "s2"].

required
level_scales

Per-level, per-axis scale of level-k voxels in level-0 voxels. level_scales[0] must be all ones. Length must match scale_names.

required
level_translations

The offset half of the same, in level-0 voxels.

required
id

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems

One system per resolution level, finest first. The store reads no axis metadata, so these come from the caller -- :meth:from_scale_and_translation builds them from a level-0 system -- or, when left empty, from the scene's world axes once the store is added to a scene. Each system's datastore_id must equal id.

required
level_transforms

Level k voxels -> level 0 voxels, one per system, built from level_scales and level_translations once the systems exist. Not normally passed.

required
name

Human-readable name for the store (inherited from BaseDataStore; defaults to "multiscale zarr data store").

required
Attributes (read-only properties)

n_levels : Number of scale levels (length of scale_names). level_shapes : List of shape tuples, one per level.

Config:

  • arbitrary_types_allowed: True

Fields:

Validators:

  • _check_cache_pool_bytes → cache_pool_bytes
  • _check_request_concurrency → request_concurrency
  • _check_file_io_concurrency → file_io_concurrency
  • _validate_level_geometry

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

n_levels property

n_levels: int

Number of scale levels.

ndim property

ndim: int

Number of data dimensions, read off the level-0 handle.

This store reads no axis metadata -- unlike the OME-Zarr readers it is constructed from bare scale and translation vectors. Its axes come from a caller's data_coordinate_system or from the scene it is added to, and this rank is what either must match.

level_shapes property

level_shapes: list[tuple[int, ...]]

Shape for each scale level, finest first.

axis_extents property

axis_extents: tuple[tuple[float, float], ...]

Per-axis (low, high) extents in level-0 data coordinates.

The edge convention: an axis of size voxels spans [-0.5, size - 0.5]. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

dtype property

dtype: dtype

Data type of the underlying arrays.

Read off the level-0 tensorstore handle, which is already open, so this costs nothing. get_data converts to float32 on the way out; this reports what is actually on disk.

__setattr__

__setattr__(key: str, value: Any) -> None

Set a field, reopening the handles when the cache settings change.

cache_pool_bytes, request_concurrency and file_io_concurrency rebuild the pool on a new context. recheck_cached_data reopens on the same context. Every other field is set as usual. Assigning the value a field already has is a no-op, so a redundant write does not throw away a warm cache.

Raises:

Type Description
ValueError

If value is out of range for the field.

RuntimeError

If a paint transaction is open on this store. Reopening would leave the paint write buffer holding a handle bound to the discarded pool, so the change is refused until the stroke is committed or aborted.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

register_paint_writer

register_paint_writer(writer: Any) -> None

Record the paint write buffer currently open on this store.

Held weakly: a controller that is dropped without tearing down does not leave the store permanently locked.

The first registration reopens the handles with rechecks on, on the same context, so a write from outside this store is not masked by the cache while painting. Registering again while registered (a fresh buffer after an autosave) only swaps the reference. A transaction already open on the old handle is unaffected: it shares the context, so its staged and committed writes are visible through the new handles.

Parameters:

Name Type Description Default
writer Any

An object with a transaction property that is None whenever no transaction is open -- i.e. a TensorStoreWriteBuffer.

required

unregister_paint_writer

unregister_paint_writer() -> None

Forget the paint write buffer, undoing :meth:register_paint_writer.

Reopens the handles with rechecks off again, unless recheck_cached_data keeps them on.

revalidate_cache

revalidate_cache() -> None

Revalidate every cached chunk once, on its next read.

Reopens the handles on the same context with recheck_cached_data="open": chunks cached before now are checked against the kvstore when next read (unchanged ones cost a 304, changed ones are refetched), then trusted again. Called for every announced change (:meth:_invalidate_caches), so a store another process writes to shows the new data after notify_changed.

A no-op while rechecks are on, since every read revalidates then, and before the handles are opened.

model_post_init

model_post_init(__context: Any) -> None

Open all tensorstore handles.

Called automatically by pydantic after __init__. Must run before QtAsyncio.run() starts the event loop.

from_scale_and_translation classmethod

from_scale_and_translation(*, zarr_path: str, scale_names: list[str], level_scales: list[tuple[float, ...]], level_translations: list[tuple[float, ...]], data_coordinate_system: DataCoordinateSystem | None = None, name: str = 'multiscale zarr data store') -> MultiscaleZarrDataStore

Construct from per-level scale and translation vectors.

Parameters:

Name Type Description Default
zarr_path str

Path to the root directory of the multiscale zarr store.

required
scale_names list[str]

Ordered list of subdirectory names, finest → coarsest.

required
level_scales list[tuple[float, ...]]

Per-level scale vectors. level_scales[0] should be all 1s.

required
level_translations list[tuple[float, ...]]

Per-level translation vectors. level_translations[0] should be all 0s.

required
data_coordinate_system DataCoordinateSystem | None

The level-0 coordinate system, one axis per data dimension. The coarser levels copy its axes (names, types, units and sampling) with fresh ids, and the store adopts its datastore_id as its id. None leaves the store without systems until it is added to a scene.

None
name str

Human-readable name for the store.

'multiscale zarr data store'

dataset_info

dataset_info() -> DatasetInfo

Describe the pyramid: path, dtype, and the per-level geometry.

No value range: unlike the in-memory stores, computing one here would mean reading every level-0 chunk off disk or over the network.

The per-level scale rows are derived from level_scales rather than asserted -- the examples used to hardcode strings like "2x isotropic" that no longer matched an anisotropic pyramid.

get_data async

get_data(request: ChunkRequest) -> ndarray

Read a single padded brick, returning a zero-padded float32 array.

Interprets request.axis_selections generically: displayed axes (tuple ranges) become slice dimensions in the output; sliced axes (int values) become point selections.

Parameters:

Name Type Description Default
request ChunkRequest

Padded brick specification. Coordinates may be negative or exceed store bounds; clamping is handled internally.

required

Returns:

Name Type Description
out ndarray

float32 array. Shape has one dimension per displayed axis (those with tuple selections). Out-of-bounds regions are filled with zero.

cellier.data.image.OMEZarrImageDataStore pydantic-model

Bases: TensorStoreCacheMixin, BaseDataStore

Data store for an OME-Zarr v0.5 image read via tensorstore.

Use the :meth:from_path class method to construct from an OME-Zarr URI.

Parameters:

Name Type Description Default
store_type Literal['ome_zarr_image']

Discriminator field. Always "ome_zarr_image".

required
zarr_path str

URI to the root OME-Zarr group. Must start with file://, s3://, gs://, or https://.

required
multiscale_index int

Index into multiscales[]. Defaults to 0.

required
scale_names list[str]

Per-level relative array paths, finest to coarsest.

required
level_scales list[tuple[float, ...]]

Full-rank (all axes) per-level scale: level-k voxels in level-0 voxels. Level 0 is all ones by construction.

required
level_translations list[tuple[float, ...]]

The offset half of the same, in level-0 voxels.

required
physical_scale list[float]

Level-0 data-to-world scale per axis, i.e. the OME global scale composed with the level-0 dataset scale. level_scales is normalised to level-0 voxels and so has this divided out; it is kept here for display. Empty when not known.

required
physical_translation list[float]

Level-0 data-to-world translation per axis, the companion to physical_scale. Empty when not known.

required
channel_labels list[str] or None

One name per channel, in channel-index order, from the image's omero metadata. None when the image has no omero block. axis_values_from_viewer uses them to label a channel slider.

required
name str

Human-readable name for the store.

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

One system per resolution level, finest first, and the store's only record of its axis names, types and units. :meth:from_path builds them from the NGFF axis metadata (every axis sampling="discrete") or from a caller's level-0 system. Each system's datastore_id must equal id.

required
level_transforms list[AffineTransform]

Level k voxels -> level 0 voxels, one per system, built from level_scales and level_translations. Not normally passed.

required

Config:

  • arbitrary_types_allowed: True

Fields:

Validators:

  • _check_cache_pool_bytes → cache_pool_bytes
  • _check_request_concurrency → request_concurrency
  • _check_file_io_concurrency → file_io_concurrency

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

n_levels property

n_levels: int

Number of scale levels.

level_shapes property

level_shapes: list[tuple[int, ...]]

Full-rank shape per level (all axes), finest first.

Returns shapes over all axes, including non-spatial ones. The controller projects to the displayed subshape using dims.displayed_axes before constructing the render visual.

axis_extents property

axis_extents: tuple[tuple[float, float], ...]

Per-axis (low, high) extents in level-0 data coordinates.

The edge convention: an axis of size voxels spans [-0.5, size - 0.5]. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

ndim property

ndim: int

Number of data dimensions, read off the level-0 handle.

dtype property

dtype: dtype

Data type of the underlying arrays.

__setattr__

__setattr__(key: str, value: Any) -> None

Set a field, reopening the handles when the cache settings change.

cache_pool_bytes, request_concurrency and file_io_concurrency rebuild the pool on a new context. recheck_cached_data reopens on the same context. Every other field is set as usual. Assigning the value a field already has is a no-op, so a redundant write does not throw away a warm cache.

Raises:

Type Description
ValueError

If value is out of range for the field.

RuntimeError

If a paint transaction is open on this store. Reopening would leave the paint write buffer holding a handle bound to the discarded pool, so the change is refused until the stroke is committed or aborted.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

register_paint_writer

register_paint_writer(writer: Any) -> None

Record the paint write buffer currently open on this store.

Held weakly: a controller that is dropped without tearing down does not leave the store permanently locked.

The first registration reopens the handles with rechecks on, on the same context, so a write from outside this store is not masked by the cache while painting. Registering again while registered (a fresh buffer after an autosave) only swaps the reference. A transaction already open on the old handle is unaffected: it shares the context, so its staged and committed writes are visible through the new handles.

Parameters:

Name Type Description Default
writer Any

An object with a transaction property that is None whenever no transaction is open -- i.e. a TensorStoreWriteBuffer.

required

unregister_paint_writer

unregister_paint_writer() -> None

Forget the paint write buffer, undoing :meth:register_paint_writer.

Reopens the handles with rechecks off again, unless recheck_cached_data keeps them on.

revalidate_cache

revalidate_cache() -> None

Revalidate every cached chunk once, on its next read.

Reopens the handles on the same context with recheck_cached_data="open": chunks cached before now are checked against the kvstore when next read (unchanged ones cost a 304, changed ones are refetched), then trusted again. Called for every announced change (:meth:_invalidate_caches), so a store another process writes to shows the new data after notify_changed.

A no-op while rechecks are on, since every read revalidates then, and before the handles are opened.

model_post_init

model_post_init(__context: Any) -> None

Open all TensorStore handles (synchronous, before QtAsyncio).

from_path classmethod

from_path(zarr_path: str, *, multiscale_index: int = 0, series_index: int = 0, anonymous: bool = False, cache_pool_bytes: int = DEFAULT_CACHE_POOL_BYTES, request_concurrency: int = DEFAULT_REQUEST_CONCURRENCY, file_io_concurrency: int | None = None, recheck_cached_data: bool = False, data_coordinate_system: DataCoordinateSystem | None = None, name: str = 'ome zarr image data store') -> OMEZarrImageDataStore

Construct from an OME-Zarr v0.5 URI.

Supports both standard Image stores and Bf2Raw (bioformats2raw) multi-series containers. For Bf2Raw stores the series_index selects which child image to open.

Parameters:

Name Type Description Default
zarr_path str

URI with a scheme prefix: file://, s3://, gs://, or https://. For local files use an absolute path, e.g. file:///home/user/data/image.ome.zarr.

required
multiscale_index int

Which multiscales[] entry to use. Defaults to 0.

0
series_index int

For Bf2Raw containers, which image series to open. Ignored for standard Image stores. Defaults to 0.

0
anonymous bool

When True, read an s3:// store without signing requests (for public buckets). gs:// needs no setting: a public bucket is read unauthenticated whenever no Google credentials are found. Default False.

False
cache_pool_bytes int

Chunk cache cap for this store, in bytes, shared by all of its resolution levels. 0 disables caching.

DEFAULT_CACHE_POOL_BYTES
request_concurrency int

Requests outstanding at once against a remote kvstore. Raise it together with SchedulerConfig.max_in_flight. No effect on a local store.

DEFAULT_REQUEST_CONCURRENCY
file_io_concurrency int or None

Reads outstanding at once against the local filesystem. None leaves tensorstore's default. No effect on a remote store.

None
recheck_cached_data bool

Revalidate cached chunks on every read. Set it when another process writes this data while it is open. Default False.

False
data_coordinate_system DataCoordinateSystem or None

The level-0 coordinate system, one axis per array dimension. None builds it from the NGFF axis metadata. A passed system replaces that metadata outright; the coarser levels copy its axes with fresh ids, and the store adopts its datastore_id.

None
name str

Human-readable name for the store.

'ome zarr image data store'

Raises:

Type Description
ValueError

If the URI scheme is not supported, the series index is out of range, an NGFF axis has an empty type and no data_coordinate_system is passed, or the passed system does not have one axis per array dimension.

TypeError

If the OME metadata is neither Image nor Bf2Raw (e.g. a Plate).

dataset_info

dataset_info() -> DatasetInfo

Describe the store from metadata it already holds.

Reads only fields parsed at construction plus the open tensorstore handles' shapes and dtype -- it never re-opens the group, which for an s3:// store would mean a network round trip every time an appearance panel is built.

No value range, for the same reason: it would be a full read of level 0.

get_data async

get_data(request: ChunkRequest) -> ndarray

Read a single padded brick, returning a zero-padded float32 array.

Interprets request.axis_selections generically: displayed axes (tuple ranges) become slice dimensions in the output; sliced axes (int values) become point selections.

Parameters:

Name Type Description Default
request ChunkRequest

Padded brick specification.

required

Returns:

Type Description
ndarray

float32 array.

cellier.data.image.ChunkRequest

Bases: NamedTuple

A request for one padded brick / chunk of data.

All coordinates encode the padded region including overlap. They may be negative or exceed the store bounds; get_data() on the MultiscaleZarrDataStore is responsible for clamping and zero-padding so the returned array always has the full requested shape.

Parameters:

Name Type Description Default
chunk_request_id

Unique ID for this individual chunk.

required
slice_request_id

Shared ID for all chunks that belong to the same planning event.

required
scale_index

0-based index into MultiscaleZarrDataStore levels (0 = finest).

required
axis_selections

Per-axis selection in data axis order. Each element is either: - int → axis is sliced (single plane, already scaled to this level) - (start, stop) → axis is displayed (windowed range; may extend outside bounds)

required

Labels

cellier.data.label.LabelMemoryStore

Bases: BaseDataStore

In-memory label data store backed by a numpy integer array.

Serves axis-aligned slices or full sub-volumes as int32 arrays. Source dtype may be int8, int16, or int32; int64/uint* are rejected.

Parameters:

Name Type Description Default
data ndarray

Integer label array (int8, int16, or int32). Shape follows numpy axis order — e.g. (D, H, W) for 3-D, (H, W) for 2-D.

Deserialisation also accepts the {"dtype": ..., "values": ...} mapping this store serialises to; the dtype is validated, not coerced, so it has to survive the round trip.

required
name str

Human-readable label. Default "label_memory_store".

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

The store's coordinate system, as a one-entry list built by the caller, with one axis per array dimension. A voxel grid is sample-indexed, so build its axes with sampling="discrete". Empty by default, in which case the store takes the scene's world axes when it is added to a scene.

required
level_scales list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_translations list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_transforms list[AffineTransform]

The level-0 identity, installed from data_coordinate_systems. Not normally passed.

required

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

axis_extents property

axis_extents: tuple[tuple[float, float], ...]

Per-axis (low, high) extents in level-0 data coordinates.

The edge convention: an axis of size voxels spans [-0.5, size - 0.5]. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

__setattr__

__setattr__(name: str, value: Any) -> None

Assign a field, announcing the change when it is a data field.

A class-level hook rather than a connection to self.events made in model_post_init: model_copy(deep=True) -- which to_model and from_model use -- runs no model_post_init, so a connection would silently go missing on every copy. Construction assigns through __dict__ and announces nothing.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

model_post_init

model_post_init(__context: Any) -> None

Check the systems passed at construction and install their transforms.

Stores that open array handles in their own model_post_init call this after opening them: the level count and rank it checks against are read off the handles.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

dataset_info

dataset_info() -> DatasetInfo

Describe the array, including how many distinct labels it holds.

The label count is a full pass over the array (np.unique), which is affordable only because the data is already resident in RAM. OMEZarrLabelDataStore deliberately omits it: there the same row would mean reading every chunk off disk.

get_data async

get_data(request: ChunkRequest) -> ndarray

Return the requested sub-region as an int32 array.

Interprets request.axis_selections generically: - int entry → sliced axis (dropped from output) - (start, stop) tuple → displayed axis (kept in output)

Out-of-bounds coordinates are clamped and zero-padded. Always returns int32 regardless of source dtype.

cellier.data.label.OMEZarrLabelDataStore pydantic-model

Bases: TensorStoreCacheMixin, BaseDataStore

Multiscale OME-Zarr label store returning int32 bricks.

Use the :meth:from_path class method to construct from a URI that points to an OME-NGFF label group (containing ome → multiscales metadata).

Parameters:

Name Type Description Default
store_type Literal['ome_zarr_label']

Discriminator field. Always "ome_zarr_label".

required
zarr_path str

URI to the label group. Must point to the label sub-group (e.g. "file:///path/to/seg.ome.zarr/labels/cells"), not the root OME-Zarr.

required
multiscale_index int

Which multiscale entry to use (default 0).

required
scale_names list[str]

Per-level relative array paths, finest to coarsest.

required
level_scales list[tuple[float, ...]]

Full-rank per-level scale: level-k voxels in level-0 voxels.

required
level_translations list[tuple[float, ...]]

The offset half of the same, in level-0 voxels.

required
physical_scale list[float]

Level-0 data-to-world scale per axis, i.e. the OME global scale composed with the level-0 dataset scale. level_scales is normalised to level-0 voxels and so has this divided out; it is kept here for display. Empty when not known.

required
physical_translation list[float]

Level-0 data-to-world translation per axis, the companion to physical_scale. Empty when not known.

required
name str

Human-readable name for the store.

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

One system per resolution level, finest first, and the store's only record of its axis names, types and units. :meth:from_path builds them from the NGFF axis metadata (every axis sampling="discrete") or from a caller's level-0 system. Each system's datastore_id must equal id.

required
level_transforms list[AffineTransform]

Level k voxels -> level 0 voxels, one per system, built from level_scales and level_translations. Not normally passed.

required

Config:

  • arbitrary_types_allowed: True

Fields:

Validators:

  • _check_cache_pool_bytes → cache_pool_bytes
  • _check_request_concurrency → request_concurrency
  • _check_file_io_concurrency → file_io_concurrency

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

n_levels property

n_levels: int

Number of scale levels.

level_shapes property

level_shapes: list[tuple[int, ...]]

Full-rank shape per level (all axes), finest first.

axis_extents property

axis_extents: tuple[tuple[float, float], ...]

Per-axis (low, high) extents in level-0 data coordinates.

The edge convention: an axis of size voxels spans [-0.5, size - 0.5]. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

dtype property

dtype: dtype

Data type of the underlying arrays (must be int8/int16/int32).

ndim property

ndim: int

Number of data dimensions, read off the level-0 handle.

__setattr__

__setattr__(key: str, value: Any) -> None

Set a field, reopening the handles when the cache settings change.

cache_pool_bytes, request_concurrency and file_io_concurrency rebuild the pool on a new context. recheck_cached_data reopens on the same context. Every other field is set as usual. Assigning the value a field already has is a no-op, so a redundant write does not throw away a warm cache.

Raises:

Type Description
ValueError

If value is out of range for the field.

RuntimeError

If a paint transaction is open on this store. Reopening would leave the paint write buffer holding a handle bound to the discarded pool, so the change is refused until the stroke is committed or aborted.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

register_paint_writer

register_paint_writer(writer: Any) -> None

Record the paint write buffer currently open on this store.

Held weakly: a controller that is dropped without tearing down does not leave the store permanently locked.

The first registration reopens the handles with rechecks on, on the same context, so a write from outside this store is not masked by the cache while painting. Registering again while registered (a fresh buffer after an autosave) only swaps the reference. A transaction already open on the old handle is unaffected: it shares the context, so its staged and committed writes are visible through the new handles.

Parameters:

Name Type Description Default
writer Any

An object with a transaction property that is None whenever no transaction is open -- i.e. a TensorStoreWriteBuffer.

required

unregister_paint_writer

unregister_paint_writer() -> None

Forget the paint write buffer, undoing :meth:register_paint_writer.

Reopens the handles with rechecks off again, unless recheck_cached_data keeps them on.

revalidate_cache

revalidate_cache() -> None

Revalidate every cached chunk once, on its next read.

Reopens the handles on the same context with recheck_cached_data="open": chunks cached before now are checked against the kvstore when next read (unchanged ones cost a 304, changed ones are refetched), then trusted again. Called for every announced change (:meth:_invalidate_caches), so a store another process writes to shows the new data after notify_changed.

A no-op while rechecks are on, since every read revalidates then, and before the handles are opened.

model_post_init

model_post_init(__context: Any) -> None

Open all TensorStore handles (synchronous, before QtAsyncio).

from_path classmethod

from_path(zarr_path: str, *, multiscale_index: int = 0, anonymous: bool = False, cache_pool_bytes: int = DEFAULT_CACHE_POOL_BYTES, request_concurrency: int = DEFAULT_REQUEST_CONCURRENCY, file_io_concurrency: int | None = None, recheck_cached_data: bool = False, data_coordinate_system: DataCoordinateSystem | None = None, name: str = 'ome zarr label data store') -> OMEZarrLabelDataStore

Construct from a URI pointing directly at an OME-NGFF label group.

The URI must point at a zarr group that carries ome.multiscales metadata (i.e. the label sub-group itself, not the root OME-Zarr).

Parameters:

Name Type Description Default
zarr_path str

URI with a scheme prefix: file://, s3://, gs://, or https://. For local files use an absolute path, e.g. file:///home/user/data/seg.ome.zarr/labels/cells.

required
multiscale_index int

Which multiscales[] entry to use. Defaults to 0.

0
anonymous bool

When True, read an s3:// store without signing requests (for public buckets). gs:// needs no setting: a public bucket is read unauthenticated whenever no Google credentials are found. Default False.

False
cache_pool_bytes int

Chunk cache cap for this store, in bytes, shared by all of its resolution levels. 0 disables caching.

DEFAULT_CACHE_POOL_BYTES
request_concurrency int

Requests outstanding at once against a remote kvstore. Raise it together with SchedulerConfig.max_in_flight. No effect on a local store.

DEFAULT_REQUEST_CONCURRENCY
file_io_concurrency int or None

Reads outstanding at once against the local filesystem. None leaves tensorstore's default. No effect on a remote store.

None
recheck_cached_data bool

Revalidate cached chunks on every read. Set it when another process writes this data while it is open. Default False.

False
data_coordinate_system DataCoordinateSystem or None

The level-0 coordinate system, one axis per array dimension. None builds it from the NGFF axis metadata, and an axis with an empty type raises. A passed system replaces that metadata outright; the coarser levels copy its axes with fresh ids, and the store adopts its datastore_id.

None
name str

Human-readable name for the store.

'ome zarr label data store'

dataset_info

dataset_info() -> DatasetInfo

Describe the store from metadata it already holds.

Like the image store, this never re-opens the group and never reads array data -- so no label count, which would require a full pass over level 0. LabelMemoryStore reports one because its data is already in RAM.

The Data type row names the on-disk dtype and the int32 the store hands out, which differ whenever the source is int8 or int16.

get_data async

get_data(request) -> ndarray

Read a padded brick, returning int32 (zero-padded for out-of-bounds).

Parameters:

Name Type Description Default
request ChunkRequest

Padded brick specification with axis_selections and scale_index.

required

Returns:

Type Description
ndarray

int32 array.

Points

cellier.data.points.PointsMemoryStore

Bases: BaseDataStore

In-memory point-cloud data store backed by numpy arrays.

All reads are synchronous (data is in CPU RAM); get_data is declared async to satisfy the AsyncSlicer contract and to provide a single cancellation checkpoint.

Positions are stored in data-axis order: column 0 is axis 0 (z), column 1 is axis 1 (y), column 2 is axis 2 (x). The render layer applies the [:, [2, 1, 0]] reversal before uploading to pygfx.

Parameters:

Name Type Description Default
positions ndarray

(n_points, ndim) float32 array.

required
colors ndarray | None

(n_points, 4) float32 RGBA, index-matched to positions. Pass None for uniform-color rendering.

required
sizes ndarray | None

(n_points,) float32 per-point sizes. Pass None for uniform-size rendering.

required
name str

Human-readable label.

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

The store's coordinate system, as a one-entry list built by the caller, with one axis per positions column. Mark an axis sampling="discrete" when its column holds sample indices, such as frame numbers. Empty by default, in which case the store takes the scene's world axes when it is added to a scene.

required
level_scales list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_translations list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_transforms list[AffineTransform]

The level-0 identity, installed from data_coordinate_systems. Not normally passed.

required

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

ndim property

ndim: int

Number of spatial dimensions per point.

axis_extents property

axis_extents: tuple[tuple[float, float], ...] | None

Per-axis (low, high) extents in level-0 data coordinates.

The bounding box of the points, with no padding -- a vertex is a point, not a cell, so there is no half-voxel to add. None when the store is empty. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

n_points property

n_points: int

Total number of points in the store.

color_mode property

color_mode: str

"vertex" when per-point colors are present, else "uniform".

Descriptive only. It reports what this store carries; it does not decide what the material does. Where RGB comes from is declared on the appearance and honoured verbatim (D20) -- the render layer never infers it from the data and never writes it back at commit time.

size_mode property

size_mode: str

"vertex" when per-point sizes are present, else "uniform".

__setattr__

__setattr__(name: str, value: Any) -> None

Assign a field, announcing the change when it is a data field.

A class-level hook rather than a connection to self.events made in model_post_init: model_copy(deep=True) -- which to_model and from_model use -- runs no model_post_init, so a connection would silently go missing on every copy. Construction assigns through __dict__ and announces nothing.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

model_post_init

model_post_init(__context: Any) -> None

Check the systems passed at construction and install their transforms.

Stores that open array handles in their own model_post_init call this after opening them: the level count and rank it checks against are read off the handles.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

dataset_info

dataset_info() -> DatasetInfo

Describe the point cloud: count, dimensionality, extent, footprint.

color_mode and size_mode are deliberately absent: they describe how the points are drawn, not what the store holds, and the appearance model is where a reader should look for that.

get_data async

get_data(request: PointsSliceRequest) -> PointsData

Return proximity-filtered point data for request.

Checkpoint

A After the proximity mask is built but before gathering surviving points. Fires if the slider is moved quickly enough to cancel the task before the gather.

If CancelledError fires at the checkpoint, the callback is never called, preventing stale geometry from reaching the GPU.

Parameters:

Name Type Description Default
request PointsSliceRequest

Built by GFXPointsMemoryVisual.build_slice_request[_2d].

required

Returns:

Type Description
PointsData

Proximity-filtered, projected points ready for GPU upload. is_empty=True when the filter produced zero points.

cellier.data.points.PointsSliceRequest

Bases: NamedTuple

Request for one proximity-filtered slice of points data.

The first three fields satisfy the AsyncSlicer logging contract: slice_request_id is the task key; chunk_request_id and scale_index appear in INFO/DEBUG log lines.

Parameters:

Name Type Description Default
slice_request_id UUID

Shared ID for all requests in one planning event. Used by AsyncSlicer as the dict key for the running task — REQUIRED.

required
chunk_request_id UUID

Per-request ID. For points (never tiled) this equals slice_request_id.

required
scale_index int

Always 0 — no LOD levels. Present for slicer logging compat.

required
displayed_axes tuple[int, ...]

Axis indices rendered in the canvas (2 for 2D, 3 for 3D).

required
retained_axes tuple[int, ...]

The data axes this visual's geometry keeps, ascending.

Not the same list as displayed_axes, which indexes the world: a zyx store in a czyx world retains (0, 1, 2) while the world displays (1, 2, 3), and a transform that permutes its axes retains a different set again. Indexing the position array with world axes raises on the first and silently uploads the wrong columns on the second.

required
region ConvexRegion

The selected region, already pulled back into data coordinates (design 3.12). It is the whole filter -- one contains call instead of a per-axis mask loop.

Until v1 was retired this was optional, and a request without one fell back to comparing a world position from slice_indices against data coordinates -- the latent bug D4 exists to fix: on a 2 um z spacing it could show a point 24 um off the slice plane and hide the three that are on it. There is no second path now (R8.3).

required

cellier.data.points.PointsData dataclass

Proximity-filtered points data returned by PointsMemoryStore.get_data().

Parameters:

Name Type Description Default
request_id UUID

Echo of PointsSliceRequest.slice_request_id.

required
positions ndarray

(n_points, n_displayed_dims) float32. Projected onto displayed axes; padded to 3D in the render layer.

required
colors ndarray | None

(n_points, 4) float32 RGBA, index-matched to positions. None when the store carries no per-point colors.

required
sizes ndarray | None

(n_points,) float32 per-point sizes. None when the store carries no per-point sizes.

required
color_mode str

"uniform" or "vertex". Ignored when colors is None.

'uniform'
size_mode str

"uniform" or "vertex". Ignored when sizes is None.

'uniform'
is_empty bool

True when the proximity filter produced zero surviving points and a placeholder geometry was returned.

False
original_indices ndarray | None

(n_points,) int array mapping each row of positions back to its index in the store's full point array. This is the proximity filter's surviving-index list; in a full 3-D view it is the identity arange(N). Used by the render layer to translate a pick's rendered-buffer vertex index into the original point index. None on the empty-placeholder path.

None

shape property

shape: str

Summary string consumed by AsyncSlicer DEBUG logging.

Lines

cellier.data.lines.LinesMemoryStore

Bases: BaseDataStore

In-memory line-segment data store backed by numpy arrays.

Stores a collection of line segments as vertex pairs. For segment n, positions[n * 2] is the start point and positions[n * 2 + 1] is the end point.

Positions are stored in data-axis order: column 0 is axis 0 (z), column 1 is axis 1 (y), column 2 is axis 2 (x). The render layer applies the [:, [2, 1, 0]] reversal before uploading to pygfx.

All reads are synchronous (data is in CPU RAM); get_data is declared async to satisfy the AsyncSlicer contract and to provide a single cancellation checkpoint.

Parameters:

Name Type Description Default
positions ndarray

(n_vertices, ndim) float32 array. Must have an even number of rows.

required
colors ndarray | None

(n_vertices, 4) float32 RGBA, index-matched to positions. Pass None for uniform-color rendering.

required
name str

Human-readable label.

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

The store's coordinate system, as a one-entry list built by the caller, with one axis per positions column. Mark an axis sampling="discrete" when its column holds sample indices, such as frame numbers. Empty by default, in which case the store takes the scene's world axes when it is added to a scene.

required
level_scales list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_translations list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_transforms list[AffineTransform]

The level-0 identity, installed from data_coordinate_systems. Not normally passed.

required

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

ndim property

ndim: int

Number of spatial dimensions per vertex.

axis_extents property

axis_extents: tuple[tuple[float, float], ...] | None

Per-axis (low, high) extents in level-0 data coordinates.

The bounding box of the vertices, with no padding -- a vertex is a point, not a cell, so there is no half-voxel to add. None when the store is empty. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

n_segments property

n_segments: int

Number of line segments (half the number of vertices).

color_mode property

color_mode: str

"vertex" when per-vertex colors are present, else "uniform".

Descriptive only. It reports what this store carries; it does not decide what the material does. Where RGB comes from is declared on the appearance and honoured verbatim (D20) -- the render layer never infers it from the data and never writes it back at commit time.

__setattr__

__setattr__(name: str, value: Any) -> None

Assign a field, announcing the change when it is a data field.

A class-level hook rather than a connection to self.events made in model_post_init: model_copy(deep=True) -- which to_model and from_model use -- runs no model_post_init, so a connection would silently go missing on every copy. Construction assigns through __dict__ and announces nothing.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

model_post_init

model_post_init(__context: Any) -> None

Check the systems passed at construction and install their transforms.

Stores that open array handles in their own model_post_init call this after opening them: the level count and rank it checks against are read off the handles.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

dataset_info

dataset_info() -> DatasetInfo

Describe the segments: count, dimensionality, extent, footprint.

The vertex count is spelled out beside the segment count to make the two-vertices-per-segment layout visible; a reader comparing this block against the raw array would otherwise see twice what they expect. color_mode is absent -- it is a display property.

get_data async

get_data(request: LinesSliceRequest) -> LinesData

Return slab-filtered segment data for request.

Checkpoint

A After the per-vertex slab mask is built but before gathering surviving vertices. Fires if the slider is moved quickly enough to cancel the task before the gather.

If CancelledError fires at the checkpoint the callback is never called, preventing stale geometry from reaching the GPU.

Inclusion rule

A segment survives when both of its endpoints pass the proximity test on every non-displayed axis: slice_index - thickness <= coord <= slice_index + thickness

Parameters:

Name Type Description Default
request LinesSliceRequest

Built by GFXLinesMemoryVisual.build_slice_request[_2d].

required

Returns:

Type Description
LinesData

Filtered, projected segment data ready for GPU upload. is_empty=True when the filter produced zero segments.

cellier.data.lines.LinesSliceRequest

Bases: NamedTuple

Request for one slab-filtered slice of line-segment data.

The first three fields satisfy the AsyncSlicer logging contract: slice_request_id is the task key; chunk_request_id and scale_index appear in INFO/DEBUG log lines.

Parameters:

Name Type Description Default
slice_request_id UUID

Shared ID for all requests in one planning event. Used by AsyncSlicer as the dict key for the running task — REQUIRED.

required
chunk_request_id UUID

Per-request ID. For lines (never tiled) this equals slice_request_id.

required
scale_index int

Always 0 — no LOD levels. Present for slicer logging compat.

required
displayed_axes tuple[int, ...]

Axis indices rendered in the canvas (2 for 2D, 3 for 3D).

required
retained_axes tuple[int, ...]

The data axes this visual's geometry keeps, ascending.

Not the same list as displayed_axes, which indexes the world: a zyx store in a czyx world retains (0, 1, 2) while the world displays (1, 2, 3), and a transform that permutes its axes retains a different set again. Indexing the position array with world axes raises on the first and silently uploads the wrong columns on the second.

required
region ConvexRegion

The selected region, already pulled back into data coordinates (design 3.12). It is the whole filter -- one contains call instead of a per-axis mask loop.

Until v1 was retired this was optional, and a request without one fell back to comparing a world position from slice_indices against data coordinates -- the latent bug D4 exists to fix: on a 2 um z spacing it could show a vertex 24 um off the slice plane and hide the ones that are on it. There is no second path now (R8.3).

required
clip_planes tuple[tuple[tuple[float, ...], float], ...]

Clipping planes the read applies on the CPU, as (normal, offset) pairs in data coordinates, kept where normal . p >= offset. Set only where the shader cannot clip: geometry flattened along an axis a plane has a component on (clipping planes design 5.2). Empty otherwise.

required

cellier.data.lines.LinesData dataclass

Slab-filtered line-segment data returned by LinesMemoryStore.get_data().

Parameters:

Name Type Description Default
request_id UUID

Echo of LinesSliceRequest.slice_request_id.

required
positions ndarray

(n_vertices, n_displayed_dims) float32. n_vertices is always even; pair (2n, 2n+1) defines segment n. Projected onto displayed axes; padded to 3D in the render layer.

required
colors ndarray | None

(n_vertices, 4) float32 RGBA, index-matched to positions. None when the store carries no per-vertex colors.

required
color_mode str

"uniform" or "vertex". Ignored when colors is None.

'uniform'
is_empty bool

True when the slab filter produced zero surviving segments and a placeholder geometry was returned.

False
original_edge_indices ndarray | None

(n_segments,) int array mapping each rendered segment to its edge index in the store's full segment array. This is the slab filter's surviving-segment list; in a full 3-D view it is the identity arange(n_segments). Used by the render layer to translate a pick's rendered-buffer edge index into the original edge index. None on the empty-placeholder path.

None

shape property

shape: str

Summary string consumed by AsyncSlicer DEBUG logging.

Meshes

cellier.data.mesh.MeshMemoryStore

Bases: BaseDataStore

In-memory triangle mesh data store.

Parameters:

Name Type Description Default
positions ndarray

(n_vertices, N) float32 vertex positions for any world dimensionality N ≥ 2. For a 3-D scene use shape (n_vertices, 3); for a 5-D scene (t, z, y, x, c) use shape (n_vertices, 5).

required
indices ndarray

(n_faces, 3) int32 triangle face indices. Must be int32 — pygfx rejects int64 at upload time. int64 input is coerced silently by the validator.

required
colors ndarray | None

Per-vertex (n_vertices, 4) or per-face (n_faces, 4) float32 RGBA. Which of the two is declared by colors_layout, never inferred.

required
colors_layout str | None

"vertex" or "face". Required whenever colors is set, and rejected when it is not.

This used to be inferred by comparing colors.shape[0] against n_faces, which is ambiguous whenever a mesh has as many vertices as faces -- a tetrahedron has four of each, so its per-vertex colours were reported as per-face and gathered wrongly. The layout also decides which rows get_data gathers, so it is not a rendering preference the appearance can supply: it is a fact about the array that only the caller knows.

required
name str

Human-readable label.

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

The store's coordinate system, as a one-entry list built by the caller, with one axis per positions column. Mark an axis sampling="discrete" when its column holds sample indices, such as frame numbers. Empty by default, in which case the store takes the scene's world axes when it is added to a scene.

required
level_scales list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_translations list[tuple[float, ...]]

Unused by this single-resolution store; left empty.

required
level_transforms list[AffineTransform]

The level-0 identity, installed from data_coordinate_systems. Not normally passed.

required

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

ndim property

ndim: int

Number of spatial dimensions per vertex.

Present for parity with the points and lines stores, which the mesh store previously lacked -- every caller had to reach into positions.shape[1] itself.

axis_extents property

axis_extents: tuple[tuple[float, float], ...] | None

Per-axis (low, high) extents in level-0 data coordinates.

The bounding box of the vertices, with no padding -- a vertex is a point, not a cell, so there is no half-voxel to add. None when the store is empty. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

colors_mode property

colors_mode: str

'vertex', 'face', or 'none' -- the declared layout.

Reads colors_layout rather than comparing array lengths. The old inference reported per-vertex colours as per-face on any mesh with as many vertices as faces.

__setattr__

__setattr__(name: str, value: Any) -> None

Assign a field, announcing the change when it is a data field.

A class-level hook rather than a connection to self.events made in model_post_init: model_copy(deep=True) -- which to_model and from_model use -- runs no model_post_init, so a connection would silently go missing on every copy. Construction assigns through __dict__ and announces nothing.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

model_post_init

model_post_init(__context: Any) -> None

Check the systems passed at construction and install their transforms.

Stores that open array handles in their own model_post_init call this after opening them: the level count and rank it checks against are read off the handles.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

dataset_info

dataset_info() -> DatasetInfo

Describe the mesh: vertex and face counts, extent, footprint.

colors_mode is deliberately absent: it describes how the mesh is drawn, not what the store holds.

Closed says whether the surface is watertight, which decides whether a 2D section of it can be filled: an open surface draws its outline only. It is worked out by the first 2D section read, so it reads "not computed" before one.

level_arrays

level_arrays(level: int = 0) -> MeshLevelArrays

The arrays of level; this store has level 0 only.

level_cache

level_cache(level: int = 0) -> LevelCache

What the reads of level share (normals, bounds indexes).

get_data async

get_data(request: MeshSliceRequest) -> MeshData

Return slab-filtered, reindexed, upload-ready mesh data.

The work runs in an executor thread (:func:~cellier.data.mesh._mesh_slicing.slice_mesh), so the event loop stays free. There are no cancellation checkpoints: the chunk scheduler, which issues these reads, never cancels one.

Inclusion rule

A face survives only when all of its vertices are inside the request's region. This is the mesh analogue of the lines store's "both endpoints must pass" rule and avoids projecting off-slice vertices onto the slice plane with the wrong colors.

Parameters:

Name Type Description Default
request MeshSliceRequest

Built by GFXMeshVisual.

required

Returns:

Type Description
MeshData

Filtered, reindexed, projected mesh ready for GPU upload. is_empty=True when the slab contained no faces.

cellier.data.mesh.MultiscaleMeshStore

Bases: BaseDataStore

In-memory triangle mesh with levels of detail.

Parameters:

Name Type Description Default
levels list[MeshLevel]

The mesh at each level, finest first, at least one. Every level is the same surface in the same data coordinates: there is one data coordinate system and no per-level transform. Every level has the same number of position columns. Either every level has colours, all with the same colors_layout, or none has.

required
name str

Human-readable label.

required
id UUID4

Unique identifier. Taken from the datastore_id of data_coordinate_systems[0] when not given; otherwise generated.

required
data_coordinate_systems list[DataCoordinateSystem]

The store's coordinate system, as a one-entry list, with one axis per position column. Empty by default, in which case the store takes the scene's world axes when it is added to a scene.

required
Notes

Level numbers here and on a request (scale_index) are 0-based, 0 the finest. A visual's GeometryLodConfig.coarse_level is 1-based, like the image settings.

The store's extent is level 0's. Build levels with quadric decimation rather than quadric clustering: a decimated level stays watertight, so its 2D section still closes and is filled.

Reassigning levels announces a change. A level is frozen; to change one, assign a new list.

data_coordinate_system property

data_coordinate_system: DataCoordinateSystem

The level-0 (intrinsic) coordinate system.

Returns:

Type Description
DataCoordinateSystem

The finest-resolution system.

Raises:

Type Description
ValueError

If the store has no coordinate systems. The message names the two ways to supply them, because this is the error a caller who built a bare in-memory store outside a viewer will hit.

level_count property

level_count: int

How many levels the mesh has.

ndim property

ndim: int

Number of position columns.

n_vertices property

n_vertices: int

Vertices in the finest level.

n_faces property

n_faces: int

Faces in the finest level.

axis_extents property

axis_extents: tuple[tuple[float, float], ...] | None

Per-axis (low, high) of the finest level's vertices.

None when that level is empty. See :attr:~cellier.data._base_data_store.BaseDataStore.axis_extents.

colors_mode property

colors_mode: str

'vertex', 'face', or 'none': the declared layout.

__setattr__

__setattr__(name: str, value: Any) -> None

Assign a field, announcing the change when it is a data field.

A class-level hook rather than a connection to self.events made in model_post_init: model_copy(deep=True) -- which to_model and from_model use -- runs no model_post_init, so a connection would silently go missing on every copy. Construction assigns through __dict__ and announces nothing.

notify_changed

notify_changed(kind: StoreChangeKind = 'contents', regions: Sequence[DataRegion] | None = None) -> None

Announce that the store's data changed.

Reassigning a data field announces itself; call this after an in-place write, which nothing can see -- store.data[...] = v or store.positions[:] = p.

Parameters:

Name Type Description Default
kind 'extent' or 'contents'

"extent" when the data may now occupy a different region of data space (vertices moved, the shape changed, the store grew); "contents" when only values changed within the same region. When unsure, pass "extent".

'contents'
regions Sequence[DataRegion] or None

Where the data changed, as per-axis (start, stop) in level-0 data coordinates. None (the default) means anywhere.

None

Raises:

Type Description
ValueError

If kind is not one of the two kinds.

model_post_init

model_post_init(__context: Any) -> None

Check the systems passed at construction and install their transforms.

Stores that open array handles in their own model_post_init call this after opening them: the level count and rank it checks against are read off the handles.

set_data_coordinate_systems

set_data_coordinate_systems(systems: list[DataCoordinateSystem], level_transforms: list[AffineTransform] | None = None) -> None

Install the store's coordinate systems and level transforms.

Assignment rather than construction because the systems are sometimes derived from the scene the store is added to, which the store cannot see at construction time.

Parameters:

Name Type Description Default
systems list[DataCoordinateSystem]

One per resolution level, finest first.

required
level_transforms list[AffineTransform] or None

Level k -> level 0. None is allowed only for a single-level store, where the transform is the identity.

None

Raises:

Type Description
ValueError

If systems is empty, if level_transforms has a different length, or if a multi-level store is given no level transforms -- there is no downsampling factor to infer them from here. Also if the systems are not one per resolution level with one axis per data dimension.

dataset_info

dataset_info() -> DatasetInfo

Describe the mesh: its levels, extent and footprint.

Closed says, per level, whether the surface is watertight, which decides whether a 2D section of that level can be filled. It is worked out by the level's first 2D section read.

level_arrays

level_arrays(level: int = 0) -> MeshLevelArrays

The arrays of level (0 is the finest).

level_cache

level_cache(level: int = 0) -> LevelCache

What the reads of level share (normals, bounds indexes).

get_data async

get_data(request: MeshSliceRequest) -> MeshData | MeshSectionData

Return one level, sliced and upload-ready.

The same read as :meth:MeshMemoryStore.get_data, on the level the request names (scale_index, 0 the finest). It runs in an executor thread, with no cancellation checkpoints.

Parameters:

Name Type Description Default
request MeshSliceRequest

Built by GFXMeshVisual.

required

Returns:

Type Description
MeshData or MeshSectionData

The level's faces inside the request's region, or its section. level is the level read.

cellier.data.mesh.MeshLevel pydantic-model

Bases: BaseModel

One level of detail of a mesh.

Parameters:

Name Type Description Default
positions ndarray

(n_vertices, N) float32 vertex positions, in the store's data coordinates. Every level of a store has the same N.

required
indices ndarray

(n_faces, 3) int32 triangle face indices into positions. int64 input is coerced.

required
colors ndarray or None

Per-vertex (n_vertices, 4) or per-face (n_faces, 4) float32 RGBA. Which of the two is declared by colors_layout.

required
colors_layout ('vertex', 'face')

Required whenever colors is set, and rejected when it is not.

"vertex"
A
required
the
required

Config:

  • arbitrary_types_allowed: True
  • frozen: True

Fields:

  • positions (ndarray)
  • indices (ndarray)
  • colors (ndarray | None)
  • colors_layout (Literal['vertex', 'face'] | None)

Validators:

  • _coerce_positions → positions
  • _coerce_indices → indices
  • _coerce_colors → colors
  • _check_shapes

n_vertices property

n_vertices: int

Vertices in this level.

n_faces property

n_faces: int

Faces in this level.

cellier.data.mesh.MeshSliceRequest

Bases: NamedTuple

Request for one slab-filtered slice of one level of a mesh.

Parameters:

Name Type Description Default
slice_request_id UUID

Shared ID for all requests in one planning event.

required
chunk_request_id UUID

Per-request ID. For mesh (never tiled) this equals slice_request_id.

required
scale_index int

The level to read, 0 the finest. A single-level store has level 0 only.

required
displayed_axes tuple[int, ...]

Axis indices rendered in the canvas.

required
retained_axes tuple[int, ...]

The data axes this visual's geometry keeps, ascending.

Not the same list as displayed_axes, which indexes the world: a zyx store in a czyx world retains (0, 1, 2) while the world displays (1, 2, 3), and a transform that permutes its axes retains a different set again. Indexing the position array with world axes raises on the first and silently uploads the wrong columns on the second.

required
region ConvexRegion

The selected region, already pulled back into data coordinates (design 3.12). It is the whole filter: a face survives when all three of its vertices are inside.

required
output_axes tuple[int, ...]

The data axes to emit, in the column order of the result. The render visual passes retained_axes reversed, which is the (x, y, z) order pygfx draws; a 2D result gets a third column of zeros. The store emits this order directly, so the commit on the UI thread copies nothing (plans/mesh_refactor_v3.md L5).

required
section MeshSectionRequest or None

None reads whole faces (a 3D view, or a 2D view of a mesh with no extent across the slice). Otherwise the read returns a :class:MeshSectionData: the mesh cut by the plane or slab, and region holds only the constraints the cut does not replace (a t filter, say).

required

cellier.data.mesh.MeshData dataclass

One level of a mesh at one request, ready to upload.

Returned by a mesh store's get_data. Every array is contiguous and in the dtype and column order the GPU takes, so the render visual builds a gfx.Geometry from it without a copy.

Parameters:

Name Type Description Default
request_id UUID

Echo of MeshSliceRequest.slice_request_id.

required
positions ndarray

(n_vertices, 3) float32, columns in the request's output_axes order; a 2D result has zeros in the third column.

required
indices ndarray

(n_faces, 3) int32. Reindexed to reference only the vertices in positions.

required
normals ndarray | None

(n_vertices, 3) float32 unit normals in the same column order, or None for a 2D result (drawn unlit).

required
colors ndarray | None

Per-vertex (n_vertices, 4) or per-face (n_faces, 4) float32 RGBA. None when the store carries no color data.

required
color_mode str

"vertex" or "face". Ignored when colors is None.

'vertex'
is_empty bool

True when the slab contained no surviving faces and a placeholder geometry was returned.

False
original_face_indices ndarray | None

(n_faces,) int array mapping each row of indices back to its face index in the level's full face array: the slab filter's surviving-face list. None when every face of the level passed (the rows are the level's faces, in order) and on the empty-placeholder path. Used by the render layer to translate a pick's rendered face index into the level's face index.

None
level int

The level the data is of, 0 the finest.

0
bounds ndarray | None

(2, 3) float64 minimum and maximum of positions, computed with the read so the UI thread does not pass over the vertices. None on the empty-placeholder path.

None

shape property

shape: str

Summary string for DEBUG logging.