diff --git a/pyproject.toml b/pyproject.toml index 860a20625..30d7843d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ "multiscale_spatial_image==0.11.2", "networkx", "numpy", - "ome_zarr>=0.7.0", + "ome_zarr>=0.8.4", "pandas", "pooch", "pyarrow", diff --git a/src/spatialdata/_io/format.py b/src/spatialdata/_io/format.py index 4fa4f6d0c..47b467b6a 100644 --- a/src/spatialdata/_io/format.py +++ b/src/spatialdata/_io/format.py @@ -1,14 +1,11 @@ from typing import Any, Optional, Union from anndata import AnnData -from multiscale_spatial_image.multiscale_spatial_image import MultiscaleSpatialImage from ome_zarr.format import CurrentFormat from pandas.api.types import CategoricalDtype from shapely import GeometryType -from spatial_image import SpatialImage from spatialdata.models import PointsModel, ShapesModel -from spatialdata.models._utils import get_channels CoordinateTransform_t = list[dict[str, Any]] @@ -72,29 +69,6 @@ def validate_coordinate_transformations( assert np.all([j0 == j1 for j0, j1 in zip(json0, json1)]) - def channels_to_metadata( - self, - data: Union[SpatialImage, MultiscaleSpatialImage], - channels_metadata: Optional[dict[str, Any]] = None, - ) -> dict[str, Union[int, str]]: - """Convert channels to omero metadata.""" - channels = get_channels(data) - metadata: dict[str, Any] = {"channels": []} - if channels_metadata is not None: - if set(channels_metadata.keys()).symmetric_difference(set(channels)): - for c in channels: - metadata["channels"].append({"label": c} | channels_metadata[c]) - else: - raise ValueError("Channels metadata must contain all channels.") - else: - for c in channels: - metadata["channels"].append({"label": c}) - return metadata - - def channels_from_metadata(self, omero_metadata: dict[str, Any]) -> list[Any]: - """Convert channels from omero metadata.""" - return [d["label"] for d in omero_metadata["channels"]] - class ShapesFormatV01(SpatialDataFormatV01): """Formatter for shapes.""" diff --git a/src/spatialdata/_io/io_raster.py b/src/spatialdata/_io/io_raster.py index 57a6069c6..dd3a57429 100644 --- a/src/spatialdata/_io/io_raster.py +++ b/src/spatialdata/_io/io_raster.py @@ -23,6 +23,7 @@ overwrite_coordinate_transformations_raster, ) from spatialdata._io.format import CurrentRasterFormat +from spatialdata.models._utils import get_channels from spatialdata.transformations._utils import ( _get_transformations, _get_transformations_xarray, @@ -58,7 +59,8 @@ def _read_multiscale( node = nodes[0] datasets = node.load(Multiscales).datasets multiscales = node.load(Multiscales).zarr.root_attrs["multiscales"] - channels_metadata = node.load(Multiscales).zarr.root_attrs.get("channels_metadata", None) + omero_metadata = node.load(Multiscales).zarr.root_attrs.get("omero", None) + legacy_channels_metadata = node.load(Multiscales).zarr.root_attrs.get("channels_metadata", None) # legacy v0.1 assert len(multiscales) == 1 # checking for multiscales[0]["coordinateTransformations"] would make fail # something that doesn't have coordinateTransformations in top level @@ -70,8 +72,11 @@ def _read_multiscale( # name = os.path.basename(node.metadata["name"]) # if image, read channels metadata channels: Optional[list[Any]] = None - if raster_type == "image" and channels_metadata is not None: - channels = fmt.channels_from_metadata(channels_metadata) + if raster_type == "image": + if legacy_channels_metadata is not None: + channels = [d["label"] for d in legacy_channels_metadata["channels"]] + if omero_metadata is not None: + channels = [d["label"] for d in omero_metadata["channels"]] axes = [i["name"] for i in node.metadata["axes"]] if len(datasets) > 1: multiscale_image = {} @@ -105,7 +110,6 @@ def _write_raster( fmt: Format = CurrentRasterFormat(), storage_options: Optional[Union[JSONDict, list[JSONDict]]] = None, label_metadata: Optional[JSONDict] = None, - channels_metadata: Optional[JSONDict] = None, **metadata: Union[str, JSONDict, list[JSONDict]], ) -> None: assert raster_type in ["image", "labels"] @@ -130,9 +134,12 @@ def _get_group_for_writing_transformations() -> zarr.Group: return group.require_group(name) return group["labels"][name] - # convert channel names to channel metadata + # convert channel names to channel metadata in omero if raster_type == "image": - group_data.attrs["channels_metadata"] = fmt.channels_to_metadata(raster_data, channels_metadata) + metadata["metadata"] = {"omero": {"channels": []}} + channels = get_channels(raster_data) + for c in channels: + metadata["metadata"]["omero"]["channels"].append({"label": c}) # type: ignore[union-attr, index, call-overload] if isinstance(raster_data, SpatialImage): data = raster_data.data