Skip to content

API Reference

OME-TIFF and OME-ZARR writer APIs designed for microscopy acquisition.

Classes:

Name Description
AcquisitionSettings

Top-level acquisition settings.

Channel

A single channel in an acquisition.

Dimension

A single dimension in the acquisition.

OMEStream

Object returned by create_stream() for writing OME-TIFF or OME-ZARR data.

OmeTiffFormat

Settings specific to OME-TIFF format.

OmeZarrFormat

Settings specific to OME-Zarr format.

Plate

Plate structure for OME metadata.

Position

A single acquisition position.

PositionDimension

Deprecated: use Dimension(type='position', ...) instead.

StandardAxis

Standard axis names.

Functions:

Name Description
create_stream

Create a stream for writing OME-TIFF or OME-ZARR data.

dims_from_standard_axes

Create dimensions from standard axis names.

dims_from_useq

Convert a useq.MDASequence to a list of Dimension.

useq_to_acquisition_settings

Convert a useq.MDASequence to settings for AcquisitionSettings.

AcquisitionSettings

Top-level acquisition settings.

This is the main schema object for defining an acquisition to be written using ome-writers. It includes the output path, dimensions, data type, compression, storage order, plate structure, and backend selection.

Pass this object to ome_writers.create_stream to create a data stream for writing acquisition data.

Parameters:

Name Type Description Default
root_path str

Root output path for the acquisition data. This may be a directory (for OME-Zarr) or a file path (for OME-TIFF). It is customary to use an .ome.zarr extension for OME-Zarr directories and .ome.tiff for OME-TIFF files.

required
dimensions tuple[Dimension, ...]

List of dimensions in order of acquisition. Must include at least two spatial 'in-frame' dimensions (usually Y and X) at the end. May not include more than 5 non-position dimensions total. May include one position dimension (type='position') to specify multiple acquisition positions. Only the first dimension may be unbounded (count=None).

required
dtype str

Data type of the pixel data to be written, e.g. 'uint8', 'uint16', 'float32', etc. Must be a valid numpy DTypeLike string.

required
format OmeTiffFormat | OmeZarrFormat

Desired output format/backend. Can be a simple string: 'ome-tiff' or 'ome-zarr', in which case the first available format-appropriate backend will be used; Or it may be a full format specification dict/object ([ome_writers.OmeTiff][] or [ome_writers.OmeZarr][]), to configure format-specific options such as backend selection.

'auto'
compression Literal['blosc-zstd', 'blosc-lz4', 'zstd', 'lzw', 'none'] | None

Compression algorithm for the storage backend. Zarr backends support: 'blosc-zstd', 'blosc-lz4', 'zstd', 'none'. TIFF backend supports: 'lzw', 'none'. If None, no compression is applied.

None
storage_order Literal['acquisition', 'ome'] | list[str]

Storage order for non-frame dimensions (if different from acquisition order). May be 'acquisition' (same as acquisition order), a list of dimension names to specify a custom storage order. Or 'ome' to use a format-specific OME-compliant canonical order (e.g. TCZYX for OME-Zarr v0.5), or any [TCZ]YX variation for OME-TIFF. The last two 'frame' dimensions (usually Y and X) may not be reordered. Default is 'ome'.

'ome'
plate Plate | None

Plate structure for OME metadata. If specified, requires a position dimension (type='position') in dimensions, and all positions must have row/column defined. Presence of this field indicates plate mode.

None
overwrite bool

Whether to overwrite existing data at root_path. If False and data already exists at the path, an error will be raised when creating the stream.

False

Attributes:

Name Type Description
array_dimensions tuple[Dimension, ...]

All Dimensions excluding position dimensions.

array_storage_dimensions tuple[Dimension, ...]

All Dimensions (excluding position dimension) in storage order.

frame_dimensions tuple[Dimension, ...]

In-frame dimensions, currently always last two dims (usually (Y,X)).

index_dimensions tuple[Dimension, ...]

All NON-frame Dimensions, excluding position dimensions.

is_unbounded bool

Whether the acquisition has an unbounded (None) dimension.

num_frames int | None

Return total number of frames, or None if unlimited dimension present.

output_path str

Output path for the acquisition data.

position_dimension_index int | None

Index of position dimension in dimensions, or None if not present.

positions tuple[Position, ...]

Position objects in acquisition order.

shape tuple[int | None, ...]

Shape of the array (count for each dimension).

storage_index_dimensions tuple[Dimension, ...]

NON-frame Dimensions in storage order.

storage_index_permutation tuple[int, ...] | None

Permutation to convert acquisition index to storage index, if different.

array_dimensions property

array_dimensions: tuple[Dimension, ...]

All Dimensions excluding position dimensions.

array_storage_dimensions property

array_storage_dimensions: tuple[Dimension, ...]

All Dimensions (excluding position dimension) in storage order.

frame_dimensions property

frame_dimensions: tuple[Dimension, ...]

In-frame dimensions, currently always last two dims (usually (Y,X)).

index_dimensions property

index_dimensions: tuple[Dimension, ...]

All NON-frame Dimensions, excluding position dimensions.

is_unbounded property

is_unbounded: bool

Whether the acquisition has an unbounded (None) dimension.

num_frames property

num_frames: int | None

Return total number of frames, or None if unlimited dimension present.

output_path property

output_path: str

Output path for the acquisition data.

This is the root_path provided by the user, resolved by the format, possibly with appropriate suffix/extension added.

position_dimension_index property

position_dimension_index: int | None

Index of position dimension in dimensions, or None if not present.

positions property

positions: tuple[Position, ...]

Position objects in acquisition order.

shape property

shape: tuple[int | None, ...]

Shape of the array (count for each dimension).

storage_index_dimensions property

storage_index_dimensions: tuple[Dimension, ...]

NON-frame Dimensions in storage order.

storage_index_permutation property

storage_index_permutation: tuple[int, ...] | None

Permutation to convert acquisition index to storage index, if different.

Channel

A single channel in an acquisition.

This object may be used (instead of a plain string) in the Dimension.coords list for dimensions of type='channel' when you want to specify more than just channel name.

This metadata is propagated to OME.Image.Pixels.Channel for OME-XML, and to omero.channels for OME-Zarr.

Parameters:

Name Type Description Default
name str

A name for the channel, suitable for presentation to the user.

required
excitation_wavelength_nm int | None

Excitation wavelength in nanometers.

None
emission_wavelength_nm int | None

Emission wavelength in nanometers.

None
fluorophore str | None

Name of the fluorophore used in this channel. No validation done, prefer names from FPbase where possible.

None
color Color | None

A color recommended when rendering this channel. Input may be a string, or a 3-4 tuple of RGB(A) values (0-255).

None

Dimension

A single dimension in the acquisition.

Dimensions define the shape and order of axis iteration during the acquisition.

Parameters:

Name Type Description Default
name str

User-defined name. Can be anything, but prefer using standard names like 'x', 'y', 'z', 'c', 't' where possible. Must be unique across all dimensions in an acquisition.

required
count int | None

Size of this dimension (in number of elements/pixels).None indicates an unbounded (unlimited) 'append' dimension. Only the first dimension in may be unbounded.

None
type Literal['space', 'time', 'channel', 'position', 'other'] | None

Type of this dimension. Must be one of 'space', 'time', 'channel', 'position', or 'other'. If not provided, type will be inferred from:

  1. coords if it contains Channel or Position objects
  2. unit if it's a recognized spatial or temporal unit
  3. standard dimension name like 'x', 'y', 'z', 'c', 't', 'p'. Note: If both coords and unit would infer conflicting types, an error is raised.
None
coords list[str | float | Channel | Position] | None

Explicit coordinate values for each element along this dimension. This is primarily a convenience for specifying categorical coordinates, such as channels or positions, and may also be used to explicitly list non-uniform spatial or temporal coordinates. If provided, the length of this list must match the count of this dimension. If count is missing, the length of this list will be used as the count. If coords contains Channel objects, type will be inferred as 'channel' (if not already set). If coords contains Position objects, type will be inferred as 'position'. Mixing Channel/Position objects with incompatible types (including each other) raises an error.

None
chunk_size int | None

Number of elements in a chunk for this dimension, for storage backends that support chunking (e.g. Zarr). If None, defaults to full size (i.e. count) for the last two 'frame' dimensions, and 1 for others.

None
shard_size_chunks int | None

Number of chunks per shard (NOT number of pixels per shard), for storage backends that support sharding (e.g. Zarr v3). If not specified, no sharding is used (i.e. chunks are the unit of storage).

None
unit str | None

Physical unit for this dimension. If type is 'space' or 'time', this MUST be a valid unit of length or time. Both OME-NGFF unit names (e.g., 'micrometer', 'millisecond'), and OME-XML abbreviations (e.g., 'um', 'ms') are accepted. If type is not provided, it will be inferred from unit if it's a recognized spatial or temporal unit. Note: If coords also implies a type (via Channel/Position objects), both must agree or an error is raised.

None
scale float | None

Physical size of a single element along this dimension, in the specified unit. For spatial dimensions, this is often refers to the pixel size. For time dimensions, this would be the time interval.

None
translation float | None

Physical offset of the first element along this dimension, in the specified unit. (e.g. the physical coordinate of the first pixel or timepoint, in some XYZ stage or other coordinate system).

None

OMEStream

OMEStream(
    backend: ArrayBackend,
    router: FrameRouter,
    expected_frames: int | None,
)

Object returned by create_stream() for writing OME-TIFF or OME-ZARR data.

Important

This class should be instantiated via the create_stream() factory function, not directly. It is made public here only for type checking and usage API documentation.

Outside of AcquisitionSettings, this is the main public interface.

This class manages the iteration through frames in acquisition order and delegates writing to the backend in storage order.

Usage
with create_stream(settings) as stream:
    for frame in frames:
        stream.append(frame)

Warning

If not used as a context manager, you must call close() to ensure all data is flushed and resources are released. A warning will be emitted if the object is garbage collected without being closed.

Methods:

Name Description
__enter__

Enter context manager.

__exit__

Exit context manager, finalizing the backend.

append

Write the next frame in acquisition order.

close

Finalize the backend, flush any pending writes, and release resources.

get_metadata

Retrieve metadata from the backend. Meaning is format-dependent.

skip

Skip N frames in acquisition order without writing data.

update_metadata

Update metadata in the backend. Meaning is format-dependent.

__enter__

__enter__() -> OMEStream

Enter context manager.

__exit__

__exit__(
    exc_type: object, exc_val: object, exc_tb: object
) -> None

Exit context manager, finalizing the backend.

append

append(
    frame: ndarray, *, frame_metadata: dict | None = None
) -> None

Write the next frame in acquisition order.

Parameters:

Name Type Description Default
frame ndarray

2D array containing the frame data (Y, X).

required
frame_metadata dict

Optional per-frame metadata. All data must be JSON-serializable (or will fail to be stored and a warning will be issued). The following special keys are recognized and will be mapped to format-specific locations:

  • delta_t : float Time delta in seconds since the start of the acquisition.
  • exposure_time : float Exposure time in seconds for this frame.
  • position_x, position_y, position_z : float Stage position in microns for this frame.

All other keys will be stored as unstructured metadata. For OME-Tiff, you can find this data in the structured annotations of the OME-XML. For OME-Zarr, this data will be stored in the "attributes.ome_writers" key in the zarr.json document in the multiscales group of each position.

None

Raises:

Type Description
IndexError

If attempting to append more frames than expected based on dimensions (for finite dimensions only). Unlimited dimensions never raise this error.

close

close() -> None

Finalize the backend, flush any pending writes, and release resources.

get_metadata

get_metadata() -> Any

Retrieve metadata from the backend. Meaning is format-dependent.

skip

skip(*, frames: int = 1) -> None

Skip N frames in acquisition order without writing data.

This method advances the stream's position by the specified number of frames without writing any actual data. The behavior depends on the backend:

  • Zarr backends: Skipped regions use the array's fill_value (default 0). For unlimited dimensions, the array is resized to accommodate the skip.
  • TIFF backend: Writes zero-filled placeholder frames to maintain the sequential IFD structure required by the format.

Parameters:

Name Type Description Default
frames int

(Keyword only). Number of frames to skip, by default 1. Must be positive.

1

Raises:

Type Description
ValueError

If frames <= 0

IndexError

If skipping would exceed the total number of frames expected based on dimensions (for finite dimensions only). Unlimited dimensions never raise this error.

Examples:

>>> with create_stream(settings) as stream:
...     stream.append(frame1)  # Write frame at index 0
...     stream.skip(frames=1)  # Skip frame at index 1
...     # try something that may fail
...     try:
...         frame_generator = setup_next_10_frames()
...     except SomeError:
...         stream.skip(frames=10)  # Skip next 10 frames
...     else:
...         for frameN in frame_generator:
...             stream.append(frameN)
...     stream.append(frame_last)  # Continue writing at next index

update_metadata

update_metadata(metadata: Any) -> None

Update metadata in the backend. Meaning is format-dependent.

OmeTiffFormat

Settings specific to OME-TIFF format.

Parameters:

Name Type Description Default
name Literal['ome-tiff']

File format identifier for OME-TIFF.

'ome-tiff'
backend Literal['tifffile'] | Literal['auto']

Storage backend to use for writing data. Must be one of 'auto', or 'tifffile'. If 'auto' (the default), the backend will be chosen based on available dependencies. Currently, 'tifffile' is the only supported backend.

'auto'
suffix str

File suffix/extension to use for OME-TIFF files. Default is '.ome.tiff'.

'.ome.tiff'

OmeZarrFormat

Settings specific to OME-Zarr format.

Parameters:

Name Type Description Default
name Literal['ome-zarr']

File format identifier for OME-Zarr.

'ome-zarr'
backend Literal['acquire-zarr', 'tensorstore', 'zarrs-python', 'zarr-python'] | Literal['auto']

Storage backend to use for writing data. Must be one of 'auto', 'tensorstore', 'acquire-zarr', 'zarrs-python', or 'zarr-python'. If 'auto' (the default), the backend will be chosen based on the available dependencies, in the order: tensorstore, acquire-zarr, zarrs-python, zarr-python.

'auto'
suffix str

Directory suffix/extension to use for OME-Zarr directories. Default is '.ome.zarr'.

'.ome.zarr'

Plate

Plate structure for OME metadata.

This defines the plate geometry (rows/columns) for metadata generation. Acquisition order is determined by position dimension in AcquisitionSettings, not by this class.

Parameters:

Name Type Description Default
row_names list[str]

List of all row names in the plate, e.g. ['A', 'B', 'C', ...]. This is used to indicate the full plate structure in OME metadata, even if not all wells are acquired.

required
column_names list[str]

List of all column names in the plate, e.g. ['1', '2', '3', ...]. This is used to indicate the full plate structure in OME metadata, even if not all wells are acquired.

required
name str | None

Optional name for the plate.

None

Methods:

Name Description
from_standard_wells

Convenience constructor to create a plate from standard well counts or shape.

from_standard_wells classmethod

from_standard_wells(
    num_wells_or_shape: int | tuple[int, int],
) -> Self

Convenience constructor to create a plate from standard well counts or shape.

Parameters:

Name Type Description Default
num_wells_or_shape int | tuple[int, int]

If an integer is provided, it is interpreted as a "standard" n-well plate with common dimensions (e.g. 24 -> 4x6, 96 -> 8x12, 384 -> 16x24). If a tuple of (rows, columns) is provided, it is used directly.

required

Position

A single acquisition position.

This object may be used (instead of a plain string) in the Dimension.coords list for dimensions of type='position' when you want to specify more than just position name.

This represents a physical position in space associated with a single camera frame or field of view. Optional fields such as grid/plate_row/column indicate that the position is a member of a larger coordinate system (e.g. well plate or grid). The x_coord, y_coord, and z_coord fields represent physical coordinates. Units should match those used in the spatial Dimensions of the acquisition.

Parameters:

Name Type Description Default
name str

Unique name for this position. Within a list of positions, names must be unique within each (plate_row, plate_column) or (grid_row, grid_column) pair.

required
plate_row str | None

Row name for plate position.

None
plate_column str | None

Column name for plate position.

None
grid_row int | None

Row index for this position in a grid layout (if any).

None
grid_column int | None

Column index for this position in a grid layout (if any).

None
x_coord float | None

Physical X coordinate of this position (e.g., stage coordinate).

None
y_coord float | None

Physical Y coordinate of this position (e.g., stage coordinate).

None
z_coord float | None

Physical Z coordinate of this position (e.g., stage coordinate).

None

PositionDimension

Deprecated: use Dimension(type='position', ...) instead.

Parameters:

Name Type Description Default
name str
'p'
type Literal['position']
'position'
coords list[Position] | None
None

StandardAxis

Standard axis names.

Dimension names are fundamentally arbitrary strings, but these standard names are commonly used and have well-defined meanings in terms of dimension type and units. This is used in dims_from_standard_axes helper function.

Methods:

Name Description
dimension_type

Return dimension type for this standard axis.

to_dimension

Convert to Dimension with given count.

unit

Return unit for this standard axis, or None if unknown.

dimension_type

dimension_type() -> DimensionType

Return dimension type for this standard axis.

to_dimension

to_dimension(
    *,
    count: int | None = None,
    coords: list[str | Position] | None = None,
    chunk_size: int | None = None,
    shard_size_chunks: int | None = None,
    scale: float | None = None,
) -> Dimension

Convert to Dimension with given count.

unit

unit() -> str | None

Return unit for this standard axis, or None if unknown.

create_stream

create_stream(settings: AcquisitionSettings) -> OMEStream

Create a stream for writing OME-TIFF or OME-ZARR data.

Warning

If not used as a context manager, you must call stream.close() to ensure all data is flushed and resources are released. A warning will be emitted if the object is garbage collected without being closed.

Parameters:

Name Type Description Default
settings AcquisitionSettings

Acquisition settings containing array configuration, path, backend, etc.

required

Returns:

Type Description
OMEStream

A configured stream ready for writing frames via append().

Raises:

Type Description
ValueError

If settings are invalid or backend is incompatible.

NotImplementedError

If requesting unsupported features (e.g., plate mode).

Examples:

>>> settings = AcquisitionSettings(
...     root_path="output.zarr",
...     dimensions=dims_from_standard_axes({"t": 10, "c": 2, "y": 512, "x": 512}),
...     dtype="uint16",
...     overwrite=True,
... )
>>> with create_stream(settings) as stream:
...     for i in range(20):  # 10 timepoints x 2 channels
...         stream.append(np.zeros((512, 512), dtype=np.uint16))

dims_from_standard_axes

dims_from_standard_axes(
    sizes: Mapping[
        str, int | Sequence[str | Position] | None
    ],
    chunk_shapes: Mapping[str | StandardAxis, int]
    | None = None,
    shard_shapes: Mapping[str | StandardAxis, int]
    | None = None,
) -> list[Dimension]

Create dimensions from standard axis names.

Standard axes are {'x', 'y', 'z', 'c', 't', 'p'}. Dimension types and units are inferred from these names. Chunk shapes default to 1 for non-XY dimensions.

For positions ('p'), the value can be: - int: creates a position Dimension (type='position') with names "0", "1", ... - list[str | Position]: creates a position Dimension with those names or Position objects

Parameters:

Name Type Description Default
sizes Mapping[str, int | Sequence[str | Position] | None]

Mapping of axis name to size. Order determines dimension order. For 'p', value can be int or list of position names.

required
chunk_shapes Mapping[str | StandardAxis, int] | None

Optional mapping of axis_name to chunk size. Defaults to full size for X/Y, 1 for others.

None
shard_shapes Mapping[str | StandardAxis, int] | None

Optional mapping of axis_name to shard size (in number of chunks). Defaults to None (no sharding).

None

Returns:

Type Description
list[Dimension]

Dimensions in the order specified by sizes.

Examples:

>>> dims = dims_from_standard_axes({"t": 10, "c": 2, "y": 512, "x": 512})
>>> dims = dims_from_standard_axes({"t": 10, "p": ["A1", "B2"], "y": 512, "x": 512})

dims_from_useq

dims_from_useq(
    seq: MDASequence,
    image_width: int,
    image_height: int,
    *,
    units: Mapping[str, UnitTuple | None] | None = None,
    pixel_size_um: float | None = None,
    chunk_shapes: Mapping[str, int] | None = None,
    shard_shapes: Mapping[str, int] | None = None,
) -> list[Dimension]

Convert a useq.MDASequence to a list of Dimension.

Deprecated

This function is deprecated and will be removed in a future version. Use useq_to_acquisition_settings instead. Dimensions can be obtained from the returned dictionary.

useq_to_acquisition_settings

useq_to_acquisition_settings(
    seq: MDASequence,
    image_width: int,
    image_height: int,
    *,
    units: Mapping[str, UnitTuple | None] | None = None,
    pixel_size_um: float | None = None,
    chunk_shapes: Mapping[str, int] | None = None,
    shard_shapes: Mapping[str, int] | None = None,
) -> AcquisitionSettingsDict

Convert a useq.MDASequence to settings for AcquisitionSettings.

Important

useq-schema has a very expressive API that can generate complex, irregular multi-dimensional acquisition sequences. However, not all of these patterns can be represented in a regular N-dimensional image data structure as used by OME-TIFF/OME-NGFF. Sequences that result in ragged dimensions will raise NotImplementedError when passed to this function.

The following restrictions apply:

Grid and Position handling:

  • Position and grid axes must be adjacent in axis_order (e.g., "pgcz", not "pcgz").
  • When both stage_positions and grid_plan are specified, position must come before grid in axis_order (e.g., "pgtcz" not "gptcz"). Grid-first order is only supported when using grid_plan alone without stage_positions.
  • Position subsequences may only contain a grid_plan, not time/channel/z-plans. Different positions may have different grid shapes.
  • If stage_positions is a WellPlatePlan, it cannot be combined with an outer grid_plan. Use well_points_plan on the WellPlatePlan instead.

Channel, Z, and Time handling:

  • All channels must have the same do_stack value when a z_plan is present.
  • All channels must have acquire_every=1. Skipping timepoints on some channels creates ragged dimensions.
  • Unbounded time plans (duration-based plans with interval=0) are not supported.

Parameters:

Name Type Description Default
seq MDASequence

The useq.MDASequence to convert.

required
image_width int

The expected width of the images in the stream.

required
image_height int

The expected height of the images in the stream.

required
units Mapping[str, UnitTuple | None] | None

An optional mapping of dimension labels to their units.

None
pixel_size_um float | None

The size of a pixel in micrometers. If provided, it will be used to set the scale for the spatial dimensions.

None
chunk_shapes Mapping[str, int] | None

An optional mapping of dimension names ("tczyx") to their chunk sizes. (In number of pixels per chunk)

None
shard_shapes Mapping[str, int] | None

An optional mapping of dimension names ("tczyx") to their shard sizes (in number of chunks per shard)

None

Returns:

Type Description
dict

A dictionary suitable for passing as keyword arguments to AcquisitionSettings. Currently contains:

  • dimensions: A list of Dimension objects.
  • plate: An Plate object if the sequence includes a WellPlatePlan, otherwise None.

Raises:

Type Description
NotImplementedError

If the sequence contains any of the unsupported patterns listed above.

Examples:

import useq
from ome_writers import useq_to_acquisition_settings, AcquisitionSettings

seq = useq.MDASequence(time_plan={"interval": 10, "loops": 5})
settings = AcquisitionSettings(
    root_path="/data/acquisitions/acq1.ome.zarr",
    **useq_to_acquisition_settings(seq, image_width=1024, image_height=1024),
    dtype="uint16",
)