Skip to content

Added ISS support of Sanger data format #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning][].
### Added

- (Xenium) support reading multi-polygon selection files from the Xenium Explorer
- (ISS) An experimental loader to load elemental ISS data objects, e.g. raw.tif, label.tif and anndata.h5ad

### Fixed

Expand Down
31 changes: 25 additions & 6 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,26 @@ I/O for the `spatialdata` project.
xenium
```

### Conversion functions

### Utility functions
### Experimental readers

```{eval-rst}
.. currentmodule:: spatialdata_io.experimental

.. autosummary::
:toctree: generated

xenium_aligned_image
xenium_explorer_selection
iss
```

### Experimental readers
### Conversion functions

```{eval-rst}
.. currentmodule:: spatialdata_io

.. autosummary::
:toctree: generated

```

### Experimental conversion functions

Expand All @@ -51,3 +58,15 @@ I/O for the `spatialdata` project.
from_legacy_anndata
to_legacy_anndata
```

### Utility functions

```{eval-rst}
.. currentmodule:: spatialdata_io

.. autosummary::
:toctree: generated

xenium_aligned_image
xenium_explorer_selection
```
3 changes: 2 additions & 1 deletion src/spatialdata_io/experimental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
from_legacy_anndata,
to_legacy_anndata,
)
from spatialdata_io.readers.iss import iss

__all__ = ["from_legacy_anndata", "to_legacy_anndata"]
__all__ = ["from_legacy_anndata", "to_legacy_anndata", "iss"]
109 changes: 109 additions & 0 deletions src/spatialdata_io/readers/iss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from __future__ import annotations

from collections.abc import Mapping
from pathlib import Path
from types import MappingProxyType
from typing import Any

import anndata as ad
from dask_image.imread import imread
from spatialdata import SpatialData
from spatialdata.models import Image2DModel, Labels2DModel, TableModel
from spatialdata.transformations.transformations import Identity
from xarray import DataArray

from spatialdata_io._docs import inject_docs

__all__ = ["iss"]


@inject_docs()
def iss(
path: str | Path,
raw_relative_path: str | Path,
labels_relative_path: str | Path,
h5ad_relative_path: str | Path,
instance_key: str,
dataset_id: str = "region",
multiscale_image: bool = True,
multiscale_labels: bool = True,
imread_kwargs: Mapping[str, Any] = MappingProxyType({}),
image_models_kwargs: Mapping[str, Any] = MappingProxyType({}),
labels_models_kwargs: Mapping[str, Any] = MappingProxyType({}),
) -> SpatialData:
"""
Read *Sanger ISS* formatted dataset.

This function reads the following files:

- ``<dataset_id>``: Counts and metadata file.
- ``<raw_relative_path>``: Raw raster image.
- ``<labels_relative_path>``: Label image.

Parameters
----------
path
Path to the directory containing the data.
raw_relative_path
Relative path to the raw raster image file.
labels_relative_path
Relative path to the label image file.
h5ad_relative_path
Relative path to the counts and metadata file.
instance_key
The name of the column that contains the instance identifiers.
Must be specified to link the table with the labels image (e.g. `cell_id`).
dataset_id
Dataset identifier.
multiscale_image
Whether to process the raw image into a multiscale image.
multiscale_labels
Whether to process the label image into a multiscale image.
imread_kwargs
Keyword arguments passed to :func:`dask_image.imread.imread`.
image_models_kwargs
Keyword arguments passed to :class:`spatialdata.models.Image2DModel`.
labels_models_kwargs
Keyword arguments passed to :class:`spatialdata.models.Labels2DModel`.

Returns
-------
The spatial data object containing the ISS data.
"""
REGION = f"{dataset_id}_labels_image"
REGION_KEY = "region"
path = Path(path)

adata = ad.read(path / h5ad_relative_path)
adata.obs[instance_key] = adata.obs.index.astype(int)
adata.var_names_make_unique()
adata.obs[REGION_KEY] = REGION
table = TableModel.parse(adata, region=REGION, region_key=REGION_KEY, instance_key=instance_key)

transform_original = Identity()

labels_image = imread(path / labels_relative_path, **imread_kwargs).squeeze()
labels_image = DataArray(labels_image[2, :, :], dims=("y", "x"))

labels_image_parsed = Labels2DModel.parse(
labels_image,
scale_factors=[2, 2, 2, 2] if multiscale_labels else None,
transformations={"global": transform_original},
**labels_models_kwargs,
)

raw_image = imread(path / raw_relative_path, **imread_kwargs)
raw_image = DataArray(raw_image, dims=("c", "y", "x"))

raw_image_parsed = Image2DModel.parse(
raw_image,
scale_factors=[2, 2, 2, 2] if multiscale_image else None,
transformations={"global": transform_original},
**image_models_kwargs,
)

return SpatialData(
images={f"{dataset_id}_raw_image": raw_image_parsed},
labels={REGION: labels_image_parsed},
table=table,
)