ngio 0.5.0b6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ngio/__init__.py +69 -0
- ngio/common/__init__.py +28 -0
- ngio/common/_dimensions.py +335 -0
- ngio/common/_masking_roi.py +153 -0
- ngio/common/_pyramid.py +408 -0
- ngio/common/_roi.py +315 -0
- ngio/common/_synt_images_utils.py +101 -0
- ngio/common/_zoom.py +188 -0
- ngio/experimental/__init__.py +5 -0
- ngio/experimental/iterators/__init__.py +15 -0
- ngio/experimental/iterators/_abstract_iterator.py +390 -0
- ngio/experimental/iterators/_feature.py +189 -0
- ngio/experimental/iterators/_image_processing.py +130 -0
- ngio/experimental/iterators/_mappers.py +48 -0
- ngio/experimental/iterators/_rois_utils.py +126 -0
- ngio/experimental/iterators/_segmentation.py +235 -0
- ngio/hcs/__init__.py +19 -0
- ngio/hcs/_plate.py +1354 -0
- ngio/images/__init__.py +44 -0
- ngio/images/_abstract_image.py +967 -0
- ngio/images/_create_synt_container.py +132 -0
- ngio/images/_create_utils.py +423 -0
- ngio/images/_image.py +926 -0
- ngio/images/_label.py +411 -0
- ngio/images/_masked_image.py +531 -0
- ngio/images/_ome_zarr_container.py +1237 -0
- ngio/images/_table_ops.py +471 -0
- ngio/io_pipes/__init__.py +75 -0
- ngio/io_pipes/_io_pipes.py +361 -0
- ngio/io_pipes/_io_pipes_masked.py +488 -0
- ngio/io_pipes/_io_pipes_roi.py +146 -0
- ngio/io_pipes/_io_pipes_types.py +56 -0
- ngio/io_pipes/_match_shape.py +377 -0
- ngio/io_pipes/_ops_axes.py +344 -0
- ngio/io_pipes/_ops_slices.py +411 -0
- ngio/io_pipes/_ops_slices_utils.py +199 -0
- ngio/io_pipes/_ops_transforms.py +104 -0
- ngio/io_pipes/_zoom_transform.py +180 -0
- ngio/ome_zarr_meta/__init__.py +65 -0
- ngio/ome_zarr_meta/_meta_handlers.py +536 -0
- ngio/ome_zarr_meta/ngio_specs/__init__.py +77 -0
- ngio/ome_zarr_meta/ngio_specs/_axes.py +515 -0
- ngio/ome_zarr_meta/ngio_specs/_channels.py +462 -0
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +89 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +539 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +438 -0
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +122 -0
- ngio/ome_zarr_meta/v04/__init__.py +27 -0
- ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v04/_v04_spec.py +473 -0
- ngio/ome_zarr_meta/v05/__init__.py +27 -0
- ngio/ome_zarr_meta/v05/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v05/_v05_spec.py +511 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png +0 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg +0 -0
- ngio/resources/__init__.py +55 -0
- ngio/resources/resource_model.py +36 -0
- ngio/tables/__init__.py +43 -0
- ngio/tables/_abstract_table.py +270 -0
- ngio/tables/_tables_container.py +449 -0
- ngio/tables/backends/__init__.py +57 -0
- ngio/tables/backends/_abstract_backend.py +240 -0
- ngio/tables/backends/_anndata.py +139 -0
- ngio/tables/backends/_anndata_utils.py +90 -0
- ngio/tables/backends/_csv.py +19 -0
- ngio/tables/backends/_json.py +92 -0
- ngio/tables/backends/_parquet.py +19 -0
- ngio/tables/backends/_py_arrow_backends.py +222 -0
- ngio/tables/backends/_table_backends.py +226 -0
- ngio/tables/backends/_utils.py +608 -0
- ngio/tables/v1/__init__.py +23 -0
- ngio/tables/v1/_condition_table.py +71 -0
- ngio/tables/v1/_feature_table.py +125 -0
- ngio/tables/v1/_generic_table.py +49 -0
- ngio/tables/v1/_roi_table.py +575 -0
- ngio/transforms/__init__.py +5 -0
- ngio/transforms/_zoom.py +19 -0
- ngio/utils/__init__.py +45 -0
- ngio/utils/_cache.py +48 -0
- ngio/utils/_datasets.py +165 -0
- ngio/utils/_errors.py +37 -0
- ngio/utils/_fractal_fsspec_store.py +42 -0
- ngio/utils/_zarr_utils.py +534 -0
- ngio-0.5.0b6.dist-info/METADATA +148 -0
- ngio-0.5.0b6.dist-info/RECORD +88 -0
- ngio-0.5.0b6.dist-info/WHEEL +4 -0
- ngio-0.5.0b6.dist-info/licenses/LICENSE +28 -0
ngio/utils/_datasets.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Download testing OME-Zarr datasets."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
import pooch
|
|
8
|
+
|
|
9
|
+
from ngio.utils._errors import NgioValueError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UnzipAndRename(pooch.Unzip):
|
|
13
|
+
"""Unzip and rename the extracted directory."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
extract_dir: str = "",
|
|
18
|
+
out_name: str = "ome-zarr.zarr",
|
|
19
|
+
re_unzip: bool = True,
|
|
20
|
+
**kwargs,
|
|
21
|
+
):
|
|
22
|
+
super().__init__(extract_dir=extract_dir, **kwargs)
|
|
23
|
+
self.out_name = out_name
|
|
24
|
+
self.re_unzip = re_unzip
|
|
25
|
+
|
|
26
|
+
def output_file(self) -> Path:
|
|
27
|
+
"""Return the output file path."""
|
|
28
|
+
if self.extract_dir is None:
|
|
29
|
+
raise NgioValueError("extract_dir must be set for UnzipAndRename.")
|
|
30
|
+
|
|
31
|
+
return Path(self.extract_dir) / self.out_name
|
|
32
|
+
|
|
33
|
+
def _extract_file(self, fname, extract_dir):
|
|
34
|
+
"""Extract the file and rename it."""
|
|
35
|
+
output_path = self.output_file()
|
|
36
|
+
if output_path.exists() and not self.re_unzip:
|
|
37
|
+
# Nothing to do, the file already exists and we are not re-unzipping
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
tmp_dir = Path(extract_dir) / "tmp"
|
|
41
|
+
# If tmp_dir exists, remove it
|
|
42
|
+
if tmp_dir.exists():
|
|
43
|
+
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
44
|
+
tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
super()._extract_file(fname, tmp_dir)
|
|
47
|
+
|
|
48
|
+
list_extracted_dirs = tmp_dir.iterdir()
|
|
49
|
+
# Keep only if ends with .zarr
|
|
50
|
+
list_extracted_dirs = filter(
|
|
51
|
+
lambda x: x.name.endswith(".zarr"),
|
|
52
|
+
list_extracted_dirs,
|
|
53
|
+
)
|
|
54
|
+
list_extracted_dirs = list(list_extracted_dirs)
|
|
55
|
+
if len(list_extracted_dirs) != 1:
|
|
56
|
+
raise NgioValueError(
|
|
57
|
+
"Expected one directory to be extracted, "
|
|
58
|
+
f"got {len(list_extracted_dirs)}."
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
extracted_dir = list_extracted_dirs[0]
|
|
62
|
+
if output_path.exists():
|
|
63
|
+
shutil.rmtree(output_path, ignore_errors=True)
|
|
64
|
+
|
|
65
|
+
extracted_dir.rename(output_path)
|
|
66
|
+
# Clean up the temporary directory
|
|
67
|
+
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
_ome_zarr_zoo = {
|
|
71
|
+
"CardiomyocyteTiny": {
|
|
72
|
+
"url": "https://zenodo.org/records/13305156/files/20200812-CardiomyocyteDifferentiation14-Cycle1.zarr.zip",
|
|
73
|
+
"known_hash": "md5:efc21fe8d4ea3abab76226d8c166452c",
|
|
74
|
+
"fname": "20200812-CardiomyocyteDifferentiation14-Cycle1-tiny.zarr.zip",
|
|
75
|
+
"description": "Tiny cardiomyocyte dataset 3D (32MB).",
|
|
76
|
+
},
|
|
77
|
+
"CardiomyocyteTinyMip": {
|
|
78
|
+
"url": "https://zenodo.org/records/13305156/files/20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip",
|
|
79
|
+
"known_hash": "md5:51809479777cafbe9ac0f9fa5636aa95",
|
|
80
|
+
"fname": "20200812-CardiomyocyteDifferentiation14-Cycle1-tiny-mip.zarr.zip",
|
|
81
|
+
"description": "Tiny cardiomyocyte dataset 2D MIP (16.4MB).",
|
|
82
|
+
},
|
|
83
|
+
"CardiomyocyteSmall": {
|
|
84
|
+
"url": "https://zenodo.org/records/13305316/files/20200812-CardiomyocyteDifferentiation14-Cycle1.zarr.zip",
|
|
85
|
+
"known_hash": "md5:d5752ed4b72a9092a0290b3c04c0b9c2",
|
|
86
|
+
"fname": "20200812-CardiomyocyteDifferentiation14-Cycle1-small.zarr.zip",
|
|
87
|
+
"description": "Small cardiomyocyte dataset 3D (750MB).",
|
|
88
|
+
},
|
|
89
|
+
"CardiomyocyteSmallMip": {
|
|
90
|
+
"url": "https://zenodo.org/records/13305316/files/20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip",
|
|
91
|
+
"known_hash": "md5:3ed3ea898e0ed42d397da2e1dbe40750",
|
|
92
|
+
"fname": "20200812-CardiomyocyteDifferentiation14-Cycle1-small-mip.zarr.zip",
|
|
93
|
+
"description": "Small cardiomyocyte dataset 2D MIP (106MB).",
|
|
94
|
+
},
|
|
95
|
+
"CardiomyocyteMediumMip": {
|
|
96
|
+
"url": "https://zenodo.org/records/14826000/files/20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip",
|
|
97
|
+
"known_hash": "md5:3f932bbf7fc0577f58b97471707816a1",
|
|
98
|
+
"fname": "20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip",
|
|
99
|
+
"description": "Medium cardiomyocyte dataset 2D MIP (30GB).",
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
AVAILABLE_DATASETS = Literal[
|
|
104
|
+
"CardiomyocyteTiny",
|
|
105
|
+
"CardiomyocyteTinyMip",
|
|
106
|
+
"CardiomyocyteSmall",
|
|
107
|
+
"CardiomyocyteSmallMip",
|
|
108
|
+
"CardiomyocyteMediumMip",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def list_ome_zarr_datasets() -> list[str]:
|
|
113
|
+
"""List available OME-Zarr datasets."""
|
|
114
|
+
return list(_ome_zarr_zoo.keys())
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def print_datasets_infos() -> None:
|
|
118
|
+
for dataset_name, dataset_info in _ome_zarr_zoo.items():
|
|
119
|
+
print(f"{dataset_name} - Description: {dataset_info['description']}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def download_ome_zarr_dataset(
|
|
123
|
+
dataset_name: AVAILABLE_DATASETS | str,
|
|
124
|
+
download_dir: str | Path = "data",
|
|
125
|
+
re_unzip: bool = True,
|
|
126
|
+
progressbar: bool = False,
|
|
127
|
+
) -> Path:
|
|
128
|
+
"""Download an OME-Zarr dataset.
|
|
129
|
+
|
|
130
|
+
To list available datasets, use `list_ome_zarr_datasets`.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
dataset_name (str): The dataset name.
|
|
134
|
+
download_dir (str): The download directory. Defaults to "data".
|
|
135
|
+
re_unzip (bool): If True, it will unzip the dataset even if it already exists.
|
|
136
|
+
progressbar (bool): If True, show a progress bar during download.
|
|
137
|
+
"""
|
|
138
|
+
if dataset_name not in _ome_zarr_zoo:
|
|
139
|
+
raise NgioValueError(f"Dataset {dataset_name} not found in the OME-Zarr zoo.")
|
|
140
|
+
zenodo_infos = _ome_zarr_zoo[dataset_name]
|
|
141
|
+
|
|
142
|
+
fname = zenodo_infos["fname"]
|
|
143
|
+
zarrname = fname.replace(".zip", "")
|
|
144
|
+
|
|
145
|
+
processor = UnzipAndRename(
|
|
146
|
+
extract_dir="",
|
|
147
|
+
out_name=zarrname,
|
|
148
|
+
re_unzip=re_unzip,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
pooch.retrieve(
|
|
152
|
+
url=zenodo_infos["url"],
|
|
153
|
+
known_hash=zenodo_infos["known_hash"],
|
|
154
|
+
fname=fname,
|
|
155
|
+
path=download_dir,
|
|
156
|
+
processor=processor,
|
|
157
|
+
progressbar=progressbar,
|
|
158
|
+
# Add User-Agent to avoid 403 errors from Zenodo
|
|
159
|
+
downloader=pooch.HTTPDownloader(
|
|
160
|
+
headers={
|
|
161
|
+
"User-Agent": f"pooch/{pooch.__version__} (https://github.com/BioVisionCenter/ngio)"
|
|
162
|
+
}
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
return processor.output_file()
|
ngio/utils/_errors.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Create a generic error class for the NGFF project
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class NgioError(Exception):
|
|
5
|
+
"""Base class for all errors in the NGFF project."""
|
|
6
|
+
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NgioFileNotFoundError(NgioError, FileNotFoundError):
|
|
11
|
+
"""Error raised when a file is not found."""
|
|
12
|
+
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NgioFileExistsError(NgioError, FileExistsError):
|
|
17
|
+
"""Error raised when a file already exists."""
|
|
18
|
+
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class NgioValidationError(NgioError, ValueError):
|
|
23
|
+
"""Generic error raised when a file does not pass validation."""
|
|
24
|
+
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NgioTableValidationError(NgioError):
|
|
29
|
+
"""Error raised when a table does not pass validation."""
|
|
30
|
+
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NgioValueError(NgioError, ValueError):
|
|
35
|
+
"""Error raised when a value does not pass a run time test."""
|
|
36
|
+
|
|
37
|
+
pass
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fsspec.implementations.http
|
|
2
|
+
from aiohttp import ClientResponseError
|
|
3
|
+
|
|
4
|
+
from ngio.utils import NgioValueError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def fractal_fsspec_store(
|
|
8
|
+
url: str, fractal_token: str | None = None, client_kwargs: dict | None = None
|
|
9
|
+
) -> fsspec.mapping.FSMap:
|
|
10
|
+
"""Simple function to get an http fsspec store from a url."""
|
|
11
|
+
client_kwargs = {} if client_kwargs is None else client_kwargs
|
|
12
|
+
if fractal_token is not None:
|
|
13
|
+
client_kwargs["headers"] = {"Authorization": f"Bearer {fractal_token}"}
|
|
14
|
+
fs = fsspec.implementations.http.HTTPFileSystem(client_kwargs=client_kwargs)
|
|
15
|
+
|
|
16
|
+
store = fs.get_mapper(url)
|
|
17
|
+
|
|
18
|
+
possible_keys = [".zgroup", ".zarray"]
|
|
19
|
+
for key in possible_keys:
|
|
20
|
+
try:
|
|
21
|
+
value = store.get(key)
|
|
22
|
+
if value is not None:
|
|
23
|
+
break
|
|
24
|
+
except ClientResponseError as e:
|
|
25
|
+
if e.status == 401 and fractal_token is None:
|
|
26
|
+
raise NgioValueError(
|
|
27
|
+
"No auto token is provided. You need a valid "
|
|
28
|
+
f"'fractal_token' to access: {url}."
|
|
29
|
+
) from e
|
|
30
|
+
elif e.status == 401 and fractal_token is not None:
|
|
31
|
+
raise NgioValueError(
|
|
32
|
+
f"The 'fractal_token' provided is invalid for: {url}."
|
|
33
|
+
) from e
|
|
34
|
+
else:
|
|
35
|
+
raise e
|
|
36
|
+
else:
|
|
37
|
+
raise NgioValueError(
|
|
38
|
+
f"Store {url} can not be read. Possible problems are: \n"
|
|
39
|
+
"- The url does not exist. \n"
|
|
40
|
+
"- The url is not a valid .zarr. \n"
|
|
41
|
+
)
|
|
42
|
+
return store
|