Skip to content

HCS API reference

Open a plate

ngio.open_ome_zarr_plate

open_ome_zarr_plate(
    store: StoreOrGroup,
    cache: bool = False,
    mode: AccessModeLiteral = "r+",
) -> OmeZarrPlate

Open an OME-Zarr plate.

Parameters:

  • store (StoreOrGroup) –

    The Zarr store or group that stores the plate.

  • cache (bool, default: False ) –

    Whether to use a cache for the zarr group metadata.

  • mode (AccessModeLiteral, default: 'r+' ) –

    The access mode for the image. Defaults to "r+".

Source code in src/ngio/hcs/_plate.py
def open_ome_zarr_plate(
    store: StoreOrGroup,
    cache: bool = False,
    mode: AccessModeLiteral = "r+",
) -> OmeZarrPlate:
    """Open an OME-Zarr plate.

    Args:
        store (StoreOrGroup): The Zarr store or group that stores the plate.
        cache (bool): Whether to use a cache for the zarr group metadata.
        mode (AccessModeLiteral): The
            access mode for the image. Defaults to "r+".
    """
    group_handler = ZarrGroupHandler(store=store, cache=cache, mode=mode)
    return OmeZarrPlate(group_handler)

OmeZarrPlate

ngio.OmeZarrPlate

OmeZarrPlate(
    group_handler: ZarrGroupHandler,
    table_container: TablesContainer | None = None,
)

A class to handle the Plate Sequence in an OME-Zarr file.

Initialize the LabelGroupHandler.

Parameters:

  • group_handler (ZarrGroupHandler) –

    The Zarr group handler that contains the Plate.

  • table_container (TablesContainer | None, default: None ) –

    The tables container that contains plate level tables.

Source code in src/ngio/hcs/_plate.py
def __init__(
    self,
    group_handler: ZarrGroupHandler,
    table_container: TablesContainer | None = None,
) -> None:
    """Initialize the LabelGroupHandler.

    Args:
        group_handler: The Zarr group handler that contains the Plate.
        table_container: The tables container that contains plate level tables.
    """
    self._group_handler = group_handler
    self._meta_handler = PlateMetaHandler(group_handler)
    self._tables_container = table_container
    # Set when a read-only probe found no `/tables`; see
    # `_get_tables_container`.
    self._tables_absent = False
    self._wells_cache: NgioCache[OmeZarrWell] = NgioCache(
        use_cache=self._group_handler.use_cache
    )
    self._images_cache: NgioCache[OmeZarrContainer] = NgioCache(
        use_cache=self._group_handler.use_cache
    )

meta_handler property

meta_handler

Return the metadata handler.

meta property

meta

Return the metadata.

columns property

columns: list[str]

Return the number of columns in the plate.

rows property

rows: list[str]

Return the number of rows in the plate.

acquisitions_names property

acquisitions_names: list[str | None]

Return the acquisitions in the plate.

acquisition_ids property

acquisition_ids: list[int]

Return the acquisitions ids in the plate.

tables_container property

tables_container: TablesContainer

Return the tables container.

refresh

refresh() -> None

Re-read metadata that cache=True holds for the object's lifetime.

The answer to "another worker wrote to this plate and I want to see it". A no-op when the plate was opened with cache=False, where nothing is held. The atomic operations refresh themselves, so this is only needed for plain reads.

Source code in src/ngio/hcs/_plate.py
def refresh(self) -> None:
    """Re-read metadata that `cache=True` holds for the object's lifetime.

    The answer to "another worker wrote to this plate and I want to see it".
    A no-op when the plate was opened with `cache=False`, where nothing is
    held. The atomic operations refresh themselves, so this is only needed
    for plain reads.
    """
    self._group_handler.clean_cache()
    self._wells_cache.clear()
    self._images_cache.clear()
    # Rebuilt on next access against the refreshed handler — it carries a
    # per-table type memo that would otherwise survive the refresh.
    self._tables_container = None
    self._tables_absent = False

wells_paths

wells_paths() -> list[str]

Return the wells paths in the plate.

Source code in src/ngio/hcs/_plate.py
def wells_paths(self) -> list[str]:
    """Return the wells paths in the plate."""
    return self.meta.wells_paths

images_paths

images_paths(
    acquisition: int | None = None,
    max_workers: MaxWorkers = None,
) -> list[str]

Return the images paths in the plate.

If acquisition is None, return all images paths in the plate. Else, return the images paths in the plate for the given acquisition.

Image paths live in each well's own metadata, not the plate's, so this reads one document per well and there is no shortcut. What there is, on a remote store, is concurrency: those reads are round-trip bound and independent.

Parameters:

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

  • max_workers (MaxWorkers, default: None ) –

    How many wells to read concurrently. None (the default) reads them one at a time; that default becomes "auto" in ngio=1.2. Pass 1 to keep reading serially, or "auto" for a pool sized for round-trip-bound work.

Source code in src/ngio/hcs/_plate.py
def images_paths(
    self, acquisition: int | None = None, max_workers: MaxWorkers = None
) -> list[str]:
    """Return the images paths in the plate.

    If acquisition is None, return all images paths in the plate.
    Else, return the images paths in the plate for the given acquisition.

    Image paths live in each well's own metadata, not the plate's, so this
    reads one document per well and there is no shortcut. What there is, on
    a remote store, is concurrency: those reads are round-trip bound and
    independent.

    Args:
        acquisition: The acquisition id to filter the images.
        max_workers: How many wells to read concurrently. `None` (the
            default) reads them one at a time; that default becomes
            `"auto"` in ngio=1.2. Pass `1` to keep reading serially, or
            `"auto"` for a pool sized for round-trip-bound work.
    """
    wells = self.get_wells(max_workers=max_workers)
    images = []
    for well_path, well in wells.items():
        for img_path in well.paths(acquisition):
            images.append(f"{well_path}/{img_path}")
    return images

well_images_paths

well_images_paths(
    row: str,
    column: int | str,
    acquisition: int | None = None,
) -> list[str]

Return the images paths in a well.

If acquisition is None, return all images paths in the well. Else, return the images paths in the well for the given acquisition.

Parameters:

  • row (str) –

    The row of the well.

  • column (int | str) –

    The column of the well.

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

Source code in src/ngio/hcs/_plate.py
def well_images_paths(
    self, row: str, column: int | str, acquisition: int | None = None
) -> list[str]:
    """Return the images paths in a well.

    If acquisition is None, return all images paths in the well.
    Else, return the images paths in the well for the given acquisition.

    Args:
        row (str): The row of the well.
        column (int | str): The column of the well.
        acquisition (int | None): The acquisition id to filter the images.
    """
    # Resolved once, not once per image: a per-image `_image_path` call
    # re-opens the well and re-reads the plate document, so the cost would
    # grow with the square of the well's image
    # count, to re-derive a prefix already in hand. The membership check
    # `_image_path` performs is vacuous here: these paths come from
    # `well.paths()` itself.
    well_path = self._well_path(row=row, column=column)
    well = self._get_well(well_path=well_path)
    return [f"{well_path}/{path}" for path in well.paths(acquisition)]

get_image_acquisition_id

get_image_acquisition_id(
    row: str, column: int | str, image_path: str
) -> int | None

Get the acquisition id of an image in a well.

Parameters:

  • row (str) –

    The row of the well.

  • column (int | str) –

    The column of the well.

  • image_path (str) –

    The path of the image.

Returns:

  • int | None –

    int | None: The acquisition id of the image.

Source code in src/ngio/hcs/_plate.py
def get_image_acquisition_id(
    self, row: str, column: int | str, image_path: str
) -> int | None:
    """Get the acquisition id of an image in a well.

    Args:
        row (str): The row of the well.
        column (int | str): The column of the well.
        image_path (str): The path of the image.

    Returns:
        int | None: The acquisition id of the image.
    """
    well = self.get_well(row=row, column=column)
    return well.get_image_acquisition_id(image_path=image_path)

get_well

get_well(row: str, column: int | str) -> OmeZarrWell

Get a well from the plate.

Parameters:

  • row (str) –

    The row of the well.

  • column (int | str) –

    The column of the well.

Returns:

Source code in src/ngio/hcs/_plate.py
def get_well(self, row: str, column: int | str) -> OmeZarrWell:
    """Get a well from the plate.

    Args:
        row (str): The row of the well.
        column (int | str): The column of the well.

    Returns:
        OmeZarrWell: The well.
    """
    well_path = self._well_path(row=row, column=column)
    return self._get_well(well_path=well_path)

get_wells

get_wells(
    max_workers: MaxWorkers = None,
) -> dict[str, OmeZarrWell]

Get all wells in the plate.

Parameters:

  • max_workers (MaxWorkers, default: None ) –

    How many wells to open concurrently. None (the default) opens them one at a time; that default becomes "auto" in ngio=1.2. Pass 1 to keep it serial, or "auto" for a pool sized for round-trip-bound work.

Returns:

  • dict[str, OmeZarrWell] –

    A dictionary of wells, keyed by well path.

Source code in src/ngio/hcs/_plate.py
def get_wells(self, max_workers: MaxWorkers = None) -> dict[str, OmeZarrWell]:
    """Get all wells in the plate.

    Args:
        max_workers: How many wells to open concurrently. `None` (the
            default) opens them one at a time; that default becomes
            `"auto"` in ngio=1.2. Pass `1` to keep it serial, or
            `"auto"` for a pool sized for round-trip-bound work.

    Returns:
        A dictionary of wells, keyed by well path.
    """
    paths = self.wells_paths()
    wells = _map_workers(self._get_well, paths, max_workers=max_workers)
    return dict(zip(paths, wells, strict=True))

get_images

get_images(
    acquisition: int | None = None,
    max_workers: MaxWorkers = None,
) -> dict[str, OmeZarrContainer]

Get all images in the plate.

Parameters:

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

  • max_workers (MaxWorkers, default: None ) –

    How many images to open concurrently. None (the default) opens them one at a time; that default becomes "auto" in ngio=1.2. Pass 1 to keep it serial, or "auto" for a pool sized for round-trip-bound work.

Returns:

Source code in src/ngio/hcs/_plate.py
def get_images(
    self, acquisition: int | None = None, max_workers: MaxWorkers = None
) -> dict[str, OmeZarrContainer]:
    """Get all images in the plate.

    Args:
        acquisition: The acquisition id to filter the images.
        max_workers: How many images to open concurrently. `None` (the
            default) opens them one at a time; that default becomes
            `"auto"` in ngio=1.2. Pass `1` to keep it serial, or
            `"auto"` for a pool sized for round-trip-bound work.

    Returns:
        A dictionary of images, keyed by image path.
    """
    paths = self.images_paths(acquisition=acquisition, max_workers=max_workers)
    images = _map_workers(self._get_image, paths, max_workers=max_workers)
    return dict(zip(paths, images, strict=True))

get_image

get_image(
    row: str, column: int | str, image_path: str
) -> OmeZarrContainer

Get an image from the plate.

Parameters:

  • row (str) –

    The row of the well.

  • column (int | str) –

    The column of the well.

  • image_path (str) –

    The path of the image.

Returns:

Source code in src/ngio/hcs/_plate.py
def get_image(
    self, row: str, column: int | str, image_path: str
) -> OmeZarrContainer:
    """Get an image from the plate.

    Args:
        row (str): The row of the well.
        column (int | str): The column of the well.
        image_path (str): The path of the image.

    Returns:
        OmeZarrContainer: The image.
    """
    image_path = self._image_path(row=row, column=column, path=image_path)
    return self._get_image(image_path)

get_image_store

get_image_store(
    row: str, column: int | str, image_path: str
) -> StoreOrGroup

Get the image store from the plate.

Parameters:

  • row (str) –

    The row of the well.

  • column (int | str) –

    The column of the well.

  • image_path (str) –

    The path of the image.

Source code in src/ngio/hcs/_plate.py
def get_image_store(
    self, row: str, column: int | str, image_path: str
) -> StoreOrGroup:
    """Get the image store from the plate.

    Args:
        row (str): The row of the well.
        column (int | str): The column of the well.
        image_path (str): The path of the image.
    """
    well = self.get_well(row=row, column=column)
    return well.get_image_store(image_path=image_path)

get_well_images

get_well_images(
    row: str,
    column: str | int,
    acquisition: int | None = None,
) -> dict[str, OmeZarrContainer]

Get all images in a well.

Parameters:

  • row (str) –

    The row of the well.

  • column (str | int) –

    The column of the well.

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

Source code in src/ngio/hcs/_plate.py
def get_well_images(
    self, row: str, column: str | int, acquisition: int | None = None
) -> dict[str, OmeZarrContainer]:
    """Get all images in a well.

    Args:
        row: The row of the well.
        column: The column of the well.
        acquisition: The acquisition id to filter the images.
    """
    # `_get_image`, not a fresh container per call: this duplicated it minus
    # the `_images_cache` lookup, so under `cache=True` it rebuilt the same
    # container every time and handed back a different object than
    # `get_images` did for the same path.
    return {
        image_path: self._get_image(image_path)
        for image_path in self.well_images_paths(
            row=row, column=column, acquisition=acquisition
        )
    }

atomic_add_image

atomic_add_image(
    row: str,
    column: int | str,
    image_path: str,
    acquisition_id: int | None = None,
    acquisition_name: str | None = None,
) -> str

Parallel safe version of add_image.

Every worker adding to a plate contends on the same two metadata files, the plate's for the well list and the well's for the image list. This serialises both read-modify-writes behind a file lock, so concurrent workers cannot lose each other's updates. The lock is an OS file lock: it holds across threads and processes on one machine, and on a shared network filesystem only if the mount honours flock.

Note

On Windows the lock is best-effort and warns: filelock can hand the same lock to two workers at once, so a single writer is safe but concurrent ones can still lose an update. Run those on Linux/macOS.

Raises:

  • NgioValueError –

    If the store is not local. The lock is an OS file lock, so there is nothing to take on a remote store.

Source code in src/ngio/hcs/_plate.py
def atomic_add_image(
    self,
    row: str,
    column: int | str,
    image_path: str,
    acquisition_id: int | None = None,
    acquisition_name: str | None = None,
) -> str:
    """Parallel safe version of `add_image`.

    Every worker adding to a plate contends on the same two metadata files,
    the plate's for the well list and the well's for the image list. This
    serialises both read-modify-writes behind a file lock, so concurrent
    workers cannot lose each other's updates. The lock is an OS file lock:
    it holds across threads and processes on one machine, and on a shared
    network filesystem only if the mount honours `flock`.

    Note:
        On Windows the lock is best-effort and warns: `filelock` can hand
        the same lock to two workers at once, so a single writer is safe but
        concurrent ones can still lose an update. Run those on Linux/macOS.

    Raises:
        NgioValueError: If the store is not local. The lock is an OS
            file lock, so there is nothing to take on a remote store.
    """
    if image_path is None:
        raise NgioValueError(
            "Image path cannot be None for atomic_add_image. "
            "If your intent is to add a well, use add_well instead."
        )
    path = self._add_image(
        row=row,
        column=column,
        image_path=image_path,
        acquisition_id=acquisition_id,
        acquisition_name=acquisition_name,
        atomic=True,
    )
    return path

add_image

add_image(
    row: str,
    column: int | str,
    image_path: str,
    acquisition_id: int | None = None,
    acquisition_name: str | None = None,
) -> str

Add an image to an ome-zarr plate.

Source code in src/ngio/hcs/_plate.py
def add_image(
    self,
    row: str,
    column: int | str,
    image_path: str,
    acquisition_id: int | None = None,
    acquisition_name: str | None = None,
) -> str:
    """Add an image to an ome-zarr plate."""
    if image_path is None:
        raise NgioValueError(
            "Image path cannot be None for add_image. "
            "If your intent is to add a well, use add_well instead."
        )
    path = self._add_image(
        row=row,
        column=column,
        image_path=image_path,
        acquisition_id=acquisition_id,
        acquisition_name=acquisition_name,
        atomic=False,
    )
    return path

add_well

add_well(row: str, column: int | str) -> OmeZarrWell

Add a well to an ome-zarr plate.

Source code in src/ngio/hcs/_plate.py
def add_well(
    self,
    row: str,
    column: int | str,
) -> OmeZarrWell:
    """Add a well to an ome-zarr plate."""
    _ = self._add_image(
        row=row,
        column=column,
        image_path=None,
        acquisition_id=None,
        acquisition_name=None,
        atomic=False,
    )
    return self.get_well(row=row, column=column)

add_column

add_column(column: int | str) -> OmeZarrPlate

Add a column to an ome-zarr plate.

Source code in src/ngio/hcs/_plate.py
def add_column(
    self,
    column: int | str,
) -> "OmeZarrPlate":
    """Add a column to an ome-zarr plate."""
    meta, _ = self.meta.add_column(column)
    self.meta_handler.update_meta(meta)
    self.meta_handler._group_handler.invalidate_meta()
    return self

add_row

add_row(row: str) -> OmeZarrPlate

Add a row to an ome-zarr plate.

Source code in src/ngio/hcs/_plate.py
def add_row(
    self,
    row: str,
) -> "OmeZarrPlate":
    """Add a row to an ome-zarr plate."""
    meta, _ = self.meta.add_row(row)
    self.meta_handler.update_meta(meta)
    self.meta_handler._group_handler.invalidate_meta()
    return self

add_acquisition

add_acquisition(
    acquisition_id: int, acquisition_name: str
) -> OmeZarrPlate

Add an acquisition to an ome-zarr plate.

Be aware that this is not a parallel safe operation.

Parameters:

  • acquisition_id (int) –

    The acquisition id.

  • acquisition_name (str) –

    The acquisition name.

Source code in src/ngio/hcs/_plate.py
def add_acquisition(
    self,
    acquisition_id: int,
    acquisition_name: str,
) -> "OmeZarrPlate":
    """Add an acquisition to an ome-zarr plate.

    Be aware that this is not a parallel safe operation.

    Args:
        acquisition_id (int): The acquisition id.
        acquisition_name (str): The acquisition name.
    """
    meta = self.meta.add_acquisition(
        acquisition_id=acquisition_id, acquisition_name=acquisition_name
    )
    self.meta_handler.update_meta(meta)
    self.meta_handler._group_handler.invalidate_meta()
    return self

atomic_remove_image

atomic_remove_image(
    row: str, column: int | str, image_path: str
)

Parallel safe version of remove_image.

Serialises the read-modify-write of the plate and well metadata behind a file lock, so concurrent workers cannot lose each other's updates. The lock is an OS file lock: it holds across threads and processes on one machine, and on a shared network filesystem only if the mount honours flock.

Note

On Windows the lock is best-effort and warns: filelock can hand the same lock to two workers at once, so a single writer is safe but concurrent ones can still lose an update. Run those on Linux/macOS.

Raises:

  • NgioValueError –

    If the store is not local. The lock is an OS file lock, so there is nothing to take on a remote store.

Source code in src/ngio/hcs/_plate.py
def atomic_remove_image(
    self,
    row: str,
    column: int | str,
    image_path: str,
):
    """Parallel safe version of `remove_image`.

    Serialises the read-modify-write of the plate and well metadata behind a
    file lock, so concurrent workers cannot lose each other's updates. The
    lock is an OS file lock: it holds across threads and processes on one
    machine, and on a shared network filesystem only if the mount honours
    `flock`.

    Note:
        On Windows the lock is best-effort and warns: `filelock` can hand
        the same lock to two workers at once, so a single writer is safe but
        concurrent ones can still lose an update. Run those on Linux/macOS.

    Raises:
        NgioValueError: If the store is not local. The lock is an OS
            file lock, so there is nothing to take on a remote store.
    """
    return self._remove_image(
        row=row,
        column=column,
        image_path=image_path,
        atomic=True,
    )

remove_image

remove_image(row: str, column: int | str, image_path: str)

Remove an image from an ome-zarr plate.

Source code in src/ngio/hcs/_plate.py
def remove_image(
    self,
    row: str,
    column: int | str,
    image_path: str,
):
    """Remove an image from an ome-zarr plate."""
    return self._remove_image(
        row=row,
        column=column,
        image_path=image_path,
        atomic=False,
    )

derive_plate

derive_plate(
    store: StoreOrGroup,
    plate_name: str | None = None,
    ngff_version: NgffVersions | None = None,
    keep_acquisitions: bool = False,
    cache: bool = False,
    overwrite: bool = False,
) -> OmeZarrPlate

Derive a new OME-Zarr plate from an existing one.

Parameters:

  • store (StoreOrGroup) –

    The Zarr store or group that stores the plate.

  • plate_name (str | None, default: None ) –

    The name of the new plate.

  • ngff_version (NgffVersion, default: None ) –

    The NGFF version to use for the new plate.

  • keep_acquisitions (bool, default: False ) –

    Whether to keep the acquisitions in the new plate.

  • cache (bool, default: False ) –

    Whether to use a cache for the zarr group metadata.

  • overwrite (bool, default: False ) –

    Whether to overwrite the existing plate.

Source code in src/ngio/hcs/_plate.py
def derive_plate(
    self,
    store: StoreOrGroup,
    plate_name: str | None = None,
    ngff_version: NgffVersions | None = None,
    keep_acquisitions: bool = False,
    cache: bool = False,
    overwrite: bool = False,
) -> "OmeZarrPlate":
    """Derive a new OME-Zarr plate from an existing one.

    Args:
        store (StoreOrGroup): The Zarr store or group that stores the plate.
        plate_name (str | None): The name of the new plate.
        ngff_version (NgffVersion): The NGFF version to use for the new plate.
        keep_acquisitions (bool): Whether to keep the acquisitions in the new plate.
        cache (bool): Whether to use a cache for the zarr group metadata.
        overwrite (bool): Whether to overwrite the existing plate.
    """
    return derive_ome_zarr_plate(
        ome_zarr_plate=self,
        store=store,
        plate_name=plate_name,
        ngff_version=ngff_version,
        keep_acquisitions=keep_acquisitions,
        cache=cache,
        overwrite=overwrite,
    )

list_tables

list_tables(
    filter_types: TypedTable | str | None = None,
) -> list[str]

List all tables in the plate.

Source code in src/ngio/hcs/_plate.py
def list_tables(self, filter_types: TypedTable | str | None = None) -> list[str]:
    """List all tables in the plate."""
    tables_container = self._get_tables_container(create_mode=False)
    if tables_container is None:
        return []
    return tables_container.list(filter_types=filter_types)

list_roi_tables

list_roi_tables() -> list[str]

List all ROI tables in the plate.

Returns [] when the plate has no tables, matching list_tables.

Source code in src/ngio/hcs/_plate.py
def list_roi_tables(self) -> list[str]:
    """List all ROI tables in the plate.

    Returns `[]` when the plate has no tables, matching `list_tables`.
    """
    tables_container = self._get_tables_container(create_mode=False)
    if tables_container is None:
        return []

    # One pass, not one per type: each `list(filter_types=...)` opens every
    # table to read its type, so asking twice read every document twice to
    # sort names the first pass had already sorted.
    types = tables_container.table_types()
    return [
        name for name, table_type in types.items() if table_type in ROI_TABLE_TYPES
    ]

get_roi_table

get_roi_table(name: str) -> RoiTable

Get a ROI table from the image.

Parameters:

  • name (str) –

    The name of the table.

Source code in src/ngio/hcs/_plate.py
def get_roi_table(self, name: str) -> RoiTable:
    """Get a ROI table from the image.

    Args:
        name (str): The name of the table.
    """
    table = self.tables_container.get(name=name, strict=True)
    if not isinstance(table, RoiTable):
        raise NgioValueError(f"Table {name} is not a ROI table. Got {type(table)}")
    return table

get_masking_roi_table

get_masking_roi_table(name: str) -> MaskingRoiTable

Get a masking ROI table from the image.

Parameters:

  • name (str) –

    The name of the table.

Source code in src/ngio/hcs/_plate.py
def get_masking_roi_table(self, name: str) -> MaskingRoiTable:
    """Get a masking ROI table from the image.

    Args:
        name (str): The name of the table.
    """
    table = self.tables_container.get(name=name, strict=True)
    if not isinstance(table, MaskingRoiTable):
        raise NgioValueError(
            f"Table {name} is not a masking ROI table. Got {type(table)}"
        )
    return table

get_feature_table

get_feature_table(name: str) -> FeatureTable

Get a feature table from the image.

Parameters:

  • name (str) –

    The name of the table.

Source code in src/ngio/hcs/_plate.py
def get_feature_table(self, name: str) -> FeatureTable:
    """Get a feature table from the image.

    Args:
        name (str): The name of the table.
    """
    table = self.tables_container.get(name=name, strict=True)
    if not isinstance(table, FeatureTable):
        raise NgioValueError(
            f"Table {name} is not a feature table. Got {type(table)}"
        )
    return table

get_generic_roi_table

get_generic_roi_table(name: str) -> GenericRoiTable

Get a generic ROI table from the image.

Parameters:

  • name (str) –

    The name of the table.

Source code in src/ngio/hcs/_plate.py
def get_generic_roi_table(self, name: str) -> GenericRoiTable:
    """Get a generic ROI table from the image.

    Args:
        name (str): The name of the table.
    """
    table = self.tables_container.get(name=name, strict=True)
    if not isinstance(table, GenericRoiTable):
        raise NgioValueError(
            f"Table {name} is not a generic ROI table. Got {type(table)}"
        )
    return table

get_condition_table

get_condition_table(name: str) -> ConditionTable

Get a condition table from the image.

Parameters:

  • name (str) –

    The name of the table.

Source code in src/ngio/hcs/_plate.py
def get_condition_table(self, name: str) -> ConditionTable:
    """Get a condition table from the image.

    Args:
        name (str): The name of the table.
    """
    table = self.tables_container.get(name=name, strict=True)
    if not isinstance(table, ConditionTable):
        raise NgioValueError(
            f"Table {name} is not a condition table. Got {type(table)}"
        )
    return table

get_table

get_table(name: str) -> Table

Get a table from the image.

Parameters:

  • name (str) –

    The name of the table.

Source code in src/ngio/hcs/_plate.py
def get_table(self, name: str) -> Table:
    """Get a table from the image.

    Args:
        name (str): The name of the table.
    """
    return self.tables_container.get(name=name, strict=False)

get_table_as

get_table_as(
    name: str,
    table_cls: type[TableType],
    backend: TableBackend | None = None,
) -> TableType

Get a table from the image as a specific type.

Parameters:

  • name (str) –

    The name of the table.

  • table_cls (type[TableType]) –

    The type of the table.

  • backend (TableBackend | None, default: None ) –

    The backend to use. If None, the default backend is used.

Source code in src/ngio/hcs/_plate.py
def get_table_as(
    self,
    name: str,
    table_cls: type[TableType],
    backend: TableBackend | None = None,
) -> TableType:
    """Get a table from the image as a specific type.

    Args:
        name (str): The name of the table.
        table_cls (type[TableType]): The type of the table.
        backend (TableBackend | None): The backend to use. If None,
            the default backend is used.
    """
    return self.tables_container.get_as(
        name=name,
        table_cls=table_cls,
        backend=backend,
    )

add_table

add_table(
    name: str,
    table: Table,
    backend: TableBackend | None = None,
    overwrite: bool = False,
) -> None

Add a table to the plate.

If backend is None (default), the table's own backend is preserved.

Source code in src/ngio/hcs/_plate.py
def add_table(
    self,
    name: str,
    table: Table,
    backend: TableBackend | None = None,
    overwrite: bool = False,
) -> None:
    """Add a table to the plate.

    If `backend` is `None` (default), the table's own backend is preserved.
    """
    self.tables_container.add(
        name=name, table=table, backend=backend, overwrite=overwrite
    )

delete_table

delete_table(name: str, missing_ok: bool = False) -> None

Delete a table from the group.

Parameters:

  • name (str) –

    The name of the table to delete.

  • missing_ok (bool, default: False ) –

    If True, do not raise an error if the table does not exist.

Source code in src/ngio/hcs/_plate.py
def delete_table(self, name: str, missing_ok: bool = False) -> None:
    """Delete a table from the group.

    Args:
        name (str): The name of the table to delete.
        missing_ok (bool): If True, do not raise an error if the table does not
            exist.

    """
    table_container = self._get_tables_container(create_mode=False)
    if table_container is None and missing_ok:
        return
    if table_container is None:
        raise NgioValueError(
            f"No tables found in the image, cannot delete {name}. "
            "Set missing_ok=True to ignore this error."
        )
    table_container.delete(name=name, missing_ok=missing_ok)

list_image_tables

list_image_tables(
    acquisition: int | None = None,
    filter_types: str | None = None,
    mode: Literal["common", "all"] = "common",
    max_workers: MaxWorkers = None,
) -> list[str]

List all image tables in the plate.

Parameters:

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

  • filter_types (str | None, default: None ) –

    The type of tables to filter. If None, return all tables.

  • mode (Literal['common', 'all'], default: 'common' ) –

    Whether to return only tables common to every image ("common") or the union across them ("all").

  • max_workers (MaxWorkers, default: None ) –

    How many images to read concurrently. None (the default) reads them one at a time; that default becomes "auto" in ngio=1.2. Pass 1 to keep it serial, or "auto" for a pool sized for round-trip-bound work.

Source code in src/ngio/hcs/_plate.py
def list_image_tables(
    self,
    acquisition: int | None = None,
    filter_types: str | None = None,
    mode: Literal["common", "all"] = "common",
    max_workers: MaxWorkers = None,
) -> list[str]:
    """List all image tables in the plate.

    Args:
        acquisition: The acquisition id to filter the images.
        filter_types: The type of tables to filter. If None, return all
            tables.
        mode: Whether to return only tables common to every image
            (`"common"`) or the union across them (`"all"`).
        max_workers: How many images to read concurrently. `None` (the
            default) reads them one at a time; that default becomes
            `"auto"` in ngio=1.2. Pass `1` to keep it serial, or
            `"auto"` for a pool sized for round-trip-bound work.
    """
    images = tuple(
        self.get_images(acquisition=acquisition, max_workers=max_workers).values()
    )
    return list_image_tables(
        images=images,
        filter_types=filter_types,
        mode=mode,
        max_workers=max_workers,
    )

concatenate_image_tables

concatenate_image_tables(
    name: str,
    acquisition: int | None = None,
    strict: bool = True,
    index_key: str | None = None,
    mode: Literal["eager", "lazy"] = "eager",
    max_workers: MaxWorkers = None,
) -> Table

Concatenate tables from all images in the plate.

Parameters:

  • name (str) –

    The name of the table to concatenate.

  • index_key (str | None, default: None ) –

    The key to use for the index of the concatenated table.

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

  • strict (bool, default: True ) –

    If True, raise an error if the table is not found in the image.

  • index_key (str | None, default: None ) –

    If a string is provided, a new index column will be created new_index_pattern = {row}{column}}_{label

  • mode (Literal['eager', 'lazy'], default: 'eager' ) –

    The mode to use for concatenation. Can be 'eager' or 'lazy'. if 'eager', the table will be loaded into memory. if 'lazy', the table will be loaded as a lazy frame.

  • max_workers (MaxWorkers, default: None ) –

    How many images to read concurrently. None (the default) reads them one at a time; that default becomes "auto" in ngio=1.2. Pass 1 to keep it serial, or "auto" for a pool sized for round-trip-bound work.

Source code in src/ngio/hcs/_plate.py
def concatenate_image_tables(
    self,
    name: str,
    acquisition: int | None = None,
    strict: bool = True,
    index_key: str | None = None,
    mode: Literal["eager", "lazy"] = "eager",
    max_workers: MaxWorkers = None,
) -> Table:
    """Concatenate tables from all images in the plate.

    Args:
        name: The name of the table to concatenate.
        index_key: The key to use for the index of the concatenated table.
        acquisition: The acquisition id to filter the images.
        strict: If True, raise an error if the table is not found in the image.
        index_key: If a string is provided, a new index column will be created
            new_index_pattern = {row}_{column}_{path_in_well}_{label}
        mode: The mode to use for concatenation. Can be 'eager' or 'lazy'.
            if 'eager', the table will be loaded into memory.
            if 'lazy', the table will be loaded as a lazy frame.
        max_workers: How many images to read concurrently. `None` (the
            default) reads them one at a time; that default becomes
            `"auto"` in ngio=1.2. Pass `1` to keep it serial, or
            `"auto"` for a pool sized for round-trip-bound work.
    """
    images = self.get_images(acquisition=acquisition, max_workers=max_workers)
    extras = _build_extras(tuple(images.keys()))
    return concatenate_image_tables(
        images=tuple(images.values()),
        extras=extras,
        name=name,
        index_key=index_key,
        strict=strict,
        mode=mode,
        max_workers=max_workers,
    )

concatenate_image_tables_as

concatenate_image_tables_as(
    name: str,
    table_cls: type[TableType],
    acquisition: int | None = None,
    index_key: str | None = None,
    strict: bool = True,
    mode: Literal["eager", "lazy"] = "eager",
    max_workers: MaxWorkers = None,
) -> TableType

Concatenate tables from all images in the plate as a specific type.

Parameters:

  • name (str) –

    The name of the table to concatenate.

  • table_cls (type[TableType]) –

    The type of the table to concatenate.

  • index_key (str | None, default: None ) –

    The key to use for the index of the concatenated table.

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

  • index_key (str | None, default: None ) –

    If a string is provided, a new index column will be created new_index_pattern = {row}{column}}_{label

  • strict (bool, default: True ) –

    If True, raise an error if the table is not found in the image.

  • mode (Literal['eager', 'lazy'], default: 'eager' ) –

    The mode to use for concatenation. Can be 'eager' or 'lazy'. if 'eager', the table will be loaded into memory. if 'lazy', the table will be loaded as a lazy frame.

  • max_workers (MaxWorkers, default: None ) –

    How many images to read concurrently. None (the default) reads them one at a time; that default becomes "auto" in ngio=1.2. Pass 1 to keep it serial, or "auto" for a pool sized for round-trip-bound work.

Source code in src/ngio/hcs/_plate.py
def concatenate_image_tables_as(
    self,
    name: str,
    table_cls: type[TableType],
    acquisition: int | None = None,
    index_key: str | None = None,
    strict: bool = True,
    mode: Literal["eager", "lazy"] = "eager",
    max_workers: MaxWorkers = None,
) -> TableType:
    """Concatenate tables from all images in the plate as a specific type.

    Args:
        name: The name of the table to concatenate.
        table_cls: The type of the table to concatenate.
        index_key: The key to use for the index of the concatenated table.
        acquisition: The acquisition id to filter the images.
        index_key: If a string is provided, a new index column will be created
            new_index_pattern = {row}_{column}_{path_in_well}_{label}
        strict: If True, raise an error if the table is not found in the image.
        mode: The mode to use for concatenation. Can be 'eager' or 'lazy'.
            if 'eager', the table will be loaded into memory.
            if 'lazy', the table will be loaded as a lazy frame.
        max_workers: How many images to read concurrently. `None` (the
            default) reads them one at a time; that default becomes
            `"auto"` in ngio=1.2. Pass `1` to keep it serial, or
            `"auto"` for a pool sized for round-trip-bound work.
    """
    images = self.get_images(acquisition=acquisition, max_workers=max_workers)
    extras = _build_extras(tuple(images.keys()))
    return concatenate_image_tables_as(
        images=tuple(images.values()),
        extras=extras,
        name=name,
        table_cls=table_cls,
        index_key=index_key,
        strict=strict,
        mode=mode,
        max_workers=max_workers,
    )

Open a well

ngio.open_ome_zarr_well

open_ome_zarr_well(
    store: StoreOrGroup,
    cache: bool = False,
    mode: AccessModeLiteral = "r+",
) -> OmeZarrWell

Open an OME-Zarr well.

Parameters:

  • store (StoreOrGroup) –

    The Zarr store or group that stores the plate.

  • cache (bool, default: False ) –

    Whether to use a cache for the zarr group metadata.

  • mode (AccessModeLiteral, default: 'r+' ) –

    The access mode for the image. Defaults to "r+".

Source code in src/ngio/hcs/_plate.py
def open_ome_zarr_well(
    store: StoreOrGroup,
    cache: bool = False,
    mode: AccessModeLiteral = "r+",
) -> OmeZarrWell:
    """Open an OME-Zarr well.

    Args:
        store (StoreOrGroup): The Zarr store or group that stores the plate.
        cache (bool): Whether to use a cache for the zarr group metadata.
        mode (AccessModeLiteral): The access mode for the image. Defaults to "r+".
    """
    group_handler = ZarrGroupHandler(
        store=store,
        cache=cache,
        mode=mode,
    )
    return OmeZarrWell(group_handler)

OmeZarrWell

ngio.OmeZarrWell

OmeZarrWell(
    group_handler: ZarrGroupHandler,
    version: NgffVersions | None = None,
)

A class to handle the Well Sequence in an OME-Zarr file.

Initialize the LabelGroupHandler.

Parameters:

  • group_handler (ZarrGroupHandler) –

    The Zarr group handler that contains the Well.

  • version (NgffVersions | None, default: None ) –

    The NGFF version of the well, when the caller already knows it. The decoder registry is 0.4-first and falls through on a failed validation, so a 0.5 well costs one wasted pydantic decode per handler unless it is told. A plate knows its own version and its wells share it.

Source code in src/ngio/hcs/_plate.py
def __init__(
    self,
    group_handler: ZarrGroupHandler,
    version: NgffVersions | None = None,
) -> None:
    """Initialize the LabelGroupHandler.

    Args:
        group_handler: The Zarr group handler that contains the Well.
        version: The NGFF version of the well, when the caller already
            knows it. The decoder registry is 0.4-first and falls through on
            a failed validation, so a 0.5 well costs one wasted pydantic
            decode per handler unless it is told. A plate knows its own
            version and its wells share it.
    """
    self._group_handler = group_handler
    self._meta_handler = WellMetaHandler(group_handler, version=version)

meta_handler property

meta_handler

Return the metadata handler.

meta property

meta

Return the metadata.

acquisition_ids property

acquisition_ids: list[int]

Return the acquisitions ids in the well.

paths

paths(acquisition: int | None = None) -> list[str]

Return the images paths in the well.

If acquisition is None, return all images paths in the well. Else, return the images paths in the well for the given acquisition.

Parameters:

  • acquisition (int | None, default: None ) –

    The acquisition id to filter the images.

Source code in src/ngio/hcs/_plate.py
def paths(self, acquisition: int | None = None) -> list[str]:
    """Return the images paths in the well.

    If acquisition is None, return all images paths in the well.
    Else, return the images paths in the well for the given acquisition.

    Args:
        acquisition (int | None): The acquisition id to filter the images.
    """
    return self.meta.paths(acquisition)

get_image_store

get_image_store(image_path: str) -> StoreOrGroup

Get the image store from the well.

Parameters:

  • image_path (str) –

    The path of the image.

Source code in src/ngio/hcs/_plate.py
def get_image_store(self, image_path: str) -> StoreOrGroup:
    """Get the image store from the well.

    Args:
        image_path (str): The path of the image.
    """
    return self._group_handler.get_group(image_path, create_mode=True)

get_image_acquisition_id

get_image_acquisition_id(image_path: str) -> int | None

Get the acquisition id of an image in the well.

Parameters:

  • image_path (str) –

    The path of the image.

Returns:

  • int | None –

    int | None: The acquisition id of the image.

Source code in src/ngio/hcs/_plate.py
def get_image_acquisition_id(self, image_path: str) -> int | None:
    """Get the acquisition id of an image in the well.

    Args:
        image_path (str): The path of the image.

    Returns:
        int | None: The acquisition id of the image.
    """
    return self.meta.get_image_acquisition_id(image_path=image_path)

get_image

get_image(image_path: str) -> OmeZarrContainer

Get an image from the well.

Parameters:

  • image_path (str) –

    The path of the image.

Returns:

Source code in src/ngio/hcs/_plate.py
def get_image(self, image_path: str) -> OmeZarrContainer:
    """Get an image from the well.

    Args:
        image_path (str): The path of the image.

    Returns:
        OmeZarrContainer: The image.
    """
    handler = self._group_handler.get_handler(image_path)
    return OmeZarrContainer(handler)

atomic_add_image

atomic_add_image(
    image_path: str,
    acquisition_id: int | None = None,
    strict: bool = True,
) -> StoreOrGroup

Parallel safe version of add_image.

Serialises the read-modify-write of the well metadata behind a file lock, so concurrent workers cannot lose each other's updates. The lock is an OS file lock: it holds across threads and processes on one machine, and on a shared network filesystem only if the mount honours flock.

Note

On Windows the lock is best-effort and warns: filelock can hand the same lock to two workers at once, so a single writer is safe but concurrent ones can still lose an update. Run those on Linux/macOS.

Raises:

  • NgioValueError –

    If the store is not local. The lock is an OS file lock, so there is nothing to take on a remote store.

Source code in src/ngio/hcs/_plate.py
def atomic_add_image(
    self,
    image_path: str,
    acquisition_id: int | None = None,
    strict: bool = True,
) -> StoreOrGroup:
    """Parallel safe version of `add_image`.

    Serialises the read-modify-write of the well metadata behind a file
    lock, so concurrent workers cannot lose each other's updates. The lock
    is an OS file lock: it holds across threads and processes on one
    machine, and on a shared network filesystem only if the mount honours
    `flock`.

    Note:
        On Windows the lock is best-effort and warns: `filelock` can hand
        the same lock to two workers at once, so a single writer is safe but
        concurrent ones can still lose an update. Run those on Linux/macOS.

    Raises:
        NgioValueError: If the store is not local. The lock is an OS
            file lock, so there is nothing to take on a remote store.
    """
    return self._add_image(
        image_path=image_path,
        acquisition_id=acquisition_id,
        atomic=True,
        strict=strict,
    )

add_image

add_image(
    image_path: str,
    acquisition_id: int | None = None,
    strict: bool = True,
) -> StoreOrGroup

Add an image to an ome-zarr well.

Parameters:

  • image_path (str) –

    The path of the image.

  • acquisition_id (int | None, default: None ) –

    The acquisition id to filter the images.

  • strict (bool, default: True ) –

    Whether to check if the acquisition id is already exists in the well. Defaults to True. If False this might lead to acquisition in a well that does not exist at the plate level.

Source code in src/ngio/hcs/_plate.py
def add_image(
    self,
    image_path: str,
    acquisition_id: int | None = None,
    strict: bool = True,
) -> StoreOrGroup:
    """Add an image to an ome-zarr well.

    Args:
        image_path (str): The path of the image.
        acquisition_id (int | None): The acquisition id to filter the images.
        strict (bool): Whether to check if the acquisition id is already exists
            in the well. Defaults to True. If False this might lead to
            acquisition in a well that does not exist at the plate level.
    """
    return self._add_image(
        image_path=image_path,
        acquisition_id=acquisition_id,
        atomic=False,
        strict=strict,
    )

Create a plate or a well

ngio.create_empty_plate

create_empty_plate(
    store: StoreOrGroup,
    name: str,
    images: list[ImageInWellPath] | None = None,
    ngff_version: NgffVersions = DefaultNgffVersion,
    cache: bool = False,
    overwrite: bool = False,
) -> OmeZarrPlate

Initialize and create an empty OME-Zarr plate.

Parameters:

  • store (StoreOrGroup) –

    The Zarr store or group that stores the plate.

  • name (str) –

    The name of the plate.

  • images (list[ImageInWellPath] | None, default: None ) –

    A list of images to add to the plate. If None, no images are added. Defaults to None.

  • ngff_version (NgffVersion, default: DefaultNgffVersion ) –

    The NGFF version to use for the new plate.

  • cache (bool, default: False ) –

    Whether to use a cache for the zarr group metadata.

  • overwrite (bool, default: False ) –

    Whether to overwrite the existing plate.

Source code in src/ngio/hcs/_plate.py
def create_empty_plate(
    store: StoreOrGroup,
    name: str,
    images: list[ImageInWellPath] | None = None,
    ngff_version: NgffVersions = DefaultNgffVersion,
    cache: bool = False,
    overwrite: bool = False,
) -> OmeZarrPlate:
    """Initialize and create an empty OME-Zarr plate.

    Args:
        store (StoreOrGroup): The Zarr store or group that stores the plate.
        name (str): The name of the plate.
        images (list[ImageInWellPath] | None): A list of images to add to the plate.
            If None, no images are added. Defaults to None.
        ngff_version (NgffVersion): The NGFF version to use for the new plate.
        cache (bool): Whether to use a cache for the zarr group metadata.
        overwrite (bool): Whether to overwrite the existing plate.
    """
    # Built in one pass rather than by looping `add_image`. That loop re-read
    # the plate document, rewrote it whole, and rewrote the well document, once
    # per image — so the bytes written grew with the square of the plate. Here
    # the plate document is written once and each well document once, whatever
    # the field count.
    plate_meta = NgioPlateMeta.default_init(
        images=images,
        name=name,
        ngff_version=ngff_version,
    )
    group_handler = _create_empty_plate_from_meta(
        store=store,
        meta=plate_meta,
        overwrite=overwrite,
    )

    if images is not None:
        images_by_well: dict[str, list[ImageInWellPath]] = {}
        for image in images:
            well_path = plate_meta.get_well_path(row=image.row, column=image.column)
            images_by_well.setdefault(well_path, []).append(image)

        for well_path, well_images in images_by_well.items():
            well_meta = NgioWellMeta.default_init(ngff_version=ngff_version)
            for image in well_images:
                well_meta = well_meta.add_image(
                    path=path_in_well_validation(path=image.path),
                    acquisition=image.acquisition_id,
                    strict=False,
                )
            well_handler = group_handler.get_handler(well_path, create_mode=True)
            update_ngio_well_meta(well_handler, well_meta)

    return open_ome_zarr_plate(
        store=store,
        cache=cache,
        mode="r+",
    )

ngio.create_empty_well

create_empty_well(
    store: StoreOrGroup,
    ngff_version: NgffVersions = DefaultNgffVersion,
    cache: bool = False,
    overwrite: bool = False,
) -> OmeZarrWell

Create an empty OME-Zarr well.

Parameters:

  • store (StoreOrGroup) –

    The Zarr store or group that stores the well.

  • ngff_version (NgffVersion, default: DefaultNgffVersion ) –

    The version of the new well.

  • cache (bool, default: False ) –

    Whether to use a cache for the zarr group metadata.

  • overwrite (bool, default: False ) –

    Whether to overwrite the existing well.

Source code in src/ngio/hcs/_plate.py
def create_empty_well(
    store: StoreOrGroup,
    ngff_version: NgffVersions = DefaultNgffVersion,
    cache: bool = False,
    overwrite: bool = False,
) -> OmeZarrWell:
    """Create an empty OME-Zarr well.

    Args:
        store (StoreOrGroup): The Zarr store or group that stores the well.
        ngff_version (NgffVersion): The version of the new well.
        cache (bool): Whether to use a cache for the zarr group metadata.
        overwrite (bool): Whether to overwrite the existing well.
    """
    group_handler = ZarrGroupHandler(
        store=store, cache=True, mode="w" if overwrite else "w-"
    )
    update_ngio_well_meta(
        group_handler, NgioWellMeta.default_init(ngff_version=ngff_version)
    )

    return open_ome_zarr_well(
        store=store,
        cache=cache,
        mode="r+",
    )