ngio 0.2.0a2__py3-none-any.whl → 0.5.0b4__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.
Files changed (106) hide show
  1. ngio/__init__.py +40 -12
  2. ngio/common/__init__.py +16 -32
  3. ngio/common/_dimensions.py +270 -48
  4. ngio/common/_masking_roi.py +153 -0
  5. ngio/common/_pyramid.py +267 -73
  6. ngio/common/_roi.py +290 -66
  7. ngio/common/_synt_images_utils.py +101 -0
  8. ngio/common/_zoom.py +54 -22
  9. ngio/experimental/__init__.py +5 -0
  10. ngio/experimental/iterators/__init__.py +15 -0
  11. ngio/experimental/iterators/_abstract_iterator.py +390 -0
  12. ngio/experimental/iterators/_feature.py +189 -0
  13. ngio/experimental/iterators/_image_processing.py +130 -0
  14. ngio/experimental/iterators/_mappers.py +48 -0
  15. ngio/experimental/iterators/_rois_utils.py +126 -0
  16. ngio/experimental/iterators/_segmentation.py +235 -0
  17. ngio/hcs/__init__.py +17 -58
  18. ngio/hcs/_plate.py +1354 -0
  19. ngio/images/__init__.py +30 -9
  20. ngio/images/_abstract_image.py +968 -0
  21. ngio/images/_create_synt_container.py +132 -0
  22. ngio/images/_create_utils.py +423 -0
  23. ngio/images/_image.py +926 -0
  24. ngio/images/_label.py +417 -0
  25. ngio/images/_masked_image.py +531 -0
  26. ngio/images/_ome_zarr_container.py +1235 -0
  27. ngio/images/_table_ops.py +471 -0
  28. ngio/io_pipes/__init__.py +75 -0
  29. ngio/io_pipes/_io_pipes.py +361 -0
  30. ngio/io_pipes/_io_pipes_masked.py +488 -0
  31. ngio/io_pipes/_io_pipes_roi.py +146 -0
  32. ngio/io_pipes/_io_pipes_types.py +56 -0
  33. ngio/io_pipes/_match_shape.py +377 -0
  34. ngio/io_pipes/_ops_axes.py +344 -0
  35. ngio/io_pipes/_ops_slices.py +411 -0
  36. ngio/io_pipes/_ops_slices_utils.py +199 -0
  37. ngio/io_pipes/_ops_transforms.py +104 -0
  38. ngio/io_pipes/_zoom_transform.py +180 -0
  39. ngio/ome_zarr_meta/__init__.py +39 -15
  40. ngio/ome_zarr_meta/_meta_handlers.py +490 -96
  41. ngio/ome_zarr_meta/ngio_specs/__init__.py +24 -10
  42. ngio/ome_zarr_meta/ngio_specs/_axes.py +268 -234
  43. ngio/ome_zarr_meta/ngio_specs/_channels.py +125 -41
  44. ngio/ome_zarr_meta/ngio_specs/_dataset.py +42 -87
  45. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +536 -2
  46. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +202 -198
  47. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +72 -34
  48. ngio/ome_zarr_meta/v04/__init__.py +21 -5
  49. ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
  50. ngio/ome_zarr_meta/v04/{_v04_spec_utils.py → _v04_spec.py} +151 -90
  51. ngio/ome_zarr_meta/v05/__init__.py +27 -0
  52. ngio/ome_zarr_meta/v05/_custom_models.py +18 -0
  53. ngio/ome_zarr_meta/v05/_v05_spec.py +511 -0
  54. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png +0 -0
  55. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
  56. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg +0 -0
  57. ngio/resources/__init__.py +55 -0
  58. ngio/resources/resource_model.py +36 -0
  59. ngio/tables/__init__.py +20 -4
  60. ngio/tables/_abstract_table.py +270 -0
  61. ngio/tables/_tables_container.py +449 -0
  62. ngio/tables/backends/__init__.py +50 -1
  63. ngio/tables/backends/_abstract_backend.py +200 -31
  64. ngio/tables/backends/_anndata.py +139 -0
  65. ngio/tables/backends/_anndata_utils.py +10 -114
  66. ngio/tables/backends/_csv.py +19 -0
  67. ngio/tables/backends/_json.py +92 -0
  68. ngio/tables/backends/_parquet.py +19 -0
  69. ngio/tables/backends/_py_arrow_backends.py +222 -0
  70. ngio/tables/backends/_table_backends.py +162 -38
  71. ngio/tables/backends/_utils.py +608 -0
  72. ngio/tables/v1/__init__.py +19 -4
  73. ngio/tables/v1/_condition_table.py +71 -0
  74. ngio/tables/v1/_feature_table.py +79 -115
  75. ngio/tables/v1/_generic_table.py +21 -90
  76. ngio/tables/v1/_roi_table.py +486 -137
  77. ngio/transforms/__init__.py +5 -0
  78. ngio/transforms/_zoom.py +19 -0
  79. ngio/utils/__init__.py +16 -14
  80. ngio/utils/_cache.py +48 -0
  81. ngio/utils/_datasets.py +121 -13
  82. ngio/utils/_fractal_fsspec_store.py +42 -0
  83. ngio/utils/_zarr_utils.py +374 -218
  84. ngio-0.5.0b4.dist-info/METADATA +147 -0
  85. ngio-0.5.0b4.dist-info/RECORD +88 -0
  86. {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/WHEEL +1 -1
  87. ngio/common/_array_pipe.py +0 -160
  88. ngio/common/_axes_transforms.py +0 -63
  89. ngio/common/_common_types.py +0 -5
  90. ngio/common/_slicer.py +0 -97
  91. ngio/images/abstract_image.py +0 -240
  92. ngio/images/create.py +0 -251
  93. ngio/images/image.py +0 -389
  94. ngio/images/label.py +0 -236
  95. ngio/images/omezarr_container.py +0 -535
  96. ngio/ome_zarr_meta/_generic_handlers.py +0 -320
  97. ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -54
  98. ngio/tables/_validators.py +0 -192
  99. ngio/tables/backends/_anndata_v1.py +0 -75
  100. ngio/tables/backends/_json_v1.py +0 -56
  101. ngio/tables/tables_container.py +0 -300
  102. ngio/tables/v1/_masking_roi_table.py +0 -175
  103. ngio/utils/_logger.py +0 -29
  104. ngio-0.2.0a2.dist-info/METADATA +0 -95
  105. ngio-0.2.0a2.dist-info/RECORD +0 -53
  106. {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,5 @@
1
+ """Concrete IO transformations."""
2
+
3
+ from ngio.transforms._zoom import ZoomTransform
4
+
5
+ __all__ = ["ZoomTransform"]
@@ -0,0 +1,19 @@
1
+ from ngio.common._zoom import (
2
+ InterpolationOrder,
3
+ )
4
+ from ngio.images._abstract_image import AbstractImage
5
+ from ngio.io_pipes._zoom_transform import BaseZoomTransform
6
+
7
+
8
+ class ZoomTransform(BaseZoomTransform):
9
+ def __init__(
10
+ self,
11
+ input_image: AbstractImage,
12
+ target_image: AbstractImage,
13
+ order: InterpolationOrder = "nearest",
14
+ ) -> None:
15
+ super().__init__(
16
+ input_dimensions=input_image.dimensions,
17
+ target_dimensions=target_image.dimensions,
18
+ order=order,
19
+ )
ngio/utils/__init__.py CHANGED
@@ -1,43 +1,45 @@
1
1
  """Various utilities for the ngio package."""
2
2
 
3
- import os
4
-
5
- from ngio.common._common_types import ArrayLike
6
- from ngio.utils._datasets import download_ome_zarr_dataset, list_ome_zarr_datasets
3
+ from ngio.utils._datasets import (
4
+ download_ome_zarr_dataset,
5
+ list_ome_zarr_datasets,
6
+ print_datasets_infos,
7
+ )
7
8
  from ngio.utils._errors import (
9
+ NgioError,
8
10
  NgioFileExistsError,
9
11
  NgioFileNotFoundError,
10
12
  NgioTableValidationError,
11
13
  NgioValidationError,
12
14
  NgioValueError,
13
15
  )
14
- from ngio.utils._logger import ngio_logger, set_logger_level
16
+ from ngio.utils._fractal_fsspec_store import fractal_fsspec_store
15
17
  from ngio.utils._zarr_utils import (
16
18
  AccessModeLiteral,
19
+ NgioCache,
20
+ NgioSupportedStore,
17
21
  StoreOrGroup,
18
22
  ZarrGroupHandler,
23
+ copy_group,
19
24
  open_group_wrapper,
20
25
  )
21
26
 
22
- set_logger_level(os.getenv("NGIO_LOGGER_LEVEL", "WARNING"))
23
-
24
27
  __all__ = [
25
- # Zarr
26
28
  "AccessModeLiteral",
27
- "ArrayLike",
28
- # Errors
29
+ "NgioCache",
30
+ "NgioError",
29
31
  "NgioFileExistsError",
30
32
  "NgioFileNotFoundError",
33
+ "NgioSupportedStore",
31
34
  "NgioTableValidationError",
32
35
  "NgioValidationError",
33
36
  "NgioValueError",
34
37
  "StoreOrGroup",
35
38
  "ZarrGroupHandler",
36
- # Datasets
39
+ "copy_group",
37
40
  "download_ome_zarr_dataset",
41
+ "fractal_fsspec_store",
38
42
  "list_ome_zarr_datasets",
39
- # Logger
40
- "ngio_logger",
41
43
  "open_group_wrapper",
42
- "set_logger_level",
44
+ "print_datasets_infos",
43
45
  ]
ngio/utils/_cache.py ADDED
@@ -0,0 +1,48 @@
1
+ from typing import Generic, TypeVar
2
+
3
+ T = TypeVar("T")
4
+
5
+
6
+ class NgioCache(Generic[T]):
7
+ """A simple cache for NGIO objects."""
8
+
9
+ def __init__(self, use_cache: bool = True):
10
+ self._cache: dict[str, T] = {}
11
+ self._use_cache = use_cache
12
+
13
+ def _cache_sanity_check(self) -> None:
14
+ if len(self._cache) > 0:
15
+ raise RuntimeError(
16
+ "Cache is disabled, but cache contains items. "
17
+ "This indicates a logic error."
18
+ )
19
+
20
+ @property
21
+ def use_cache(self) -> bool:
22
+ return self._use_cache
23
+
24
+ @property
25
+ def cache(self) -> dict[str, T]:
26
+ return self._cache
27
+
28
+ @property
29
+ def is_empty(self) -> bool:
30
+ return len(self._cache) == 0
31
+
32
+ def get(self, key: str, default: T | None = None) -> T | None:
33
+ if not self._use_cache:
34
+ self._cache_sanity_check()
35
+ return default
36
+ return self._cache.get(key, default)
37
+
38
+ def set(self, key: str, value: T, overwrite: bool = True) -> None:
39
+ if not self._use_cache:
40
+ self._cache_sanity_check()
41
+ return
42
+ self._cache[key] = value
43
+
44
+ def clear(self) -> None:
45
+ if not self._use_cache:
46
+ self._cache_sanity_check()
47
+ return
48
+ self._cache.clear()
ngio/utils/_datasets.py CHANGED
@@ -1,33 +1,129 @@
1
1
  """Download testing OME-Zarr datasets."""
2
2
 
3
+ import shutil
3
4
  from pathlib import Path
5
+ from typing import Literal
4
6
 
5
7
  import pooch
6
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
+
7
70
  _ome_zarr_zoo = {
8
71
  "CardiomyocyteTiny": {
9
72
  "url": "https://zenodo.org/records/13305156/files/20200812-CardiomyocyteDifferentiation14-Cycle1.zarr.zip",
10
73
  "known_hash": "md5:efc21fe8d4ea3abab76226d8c166452c",
11
- "fname": "20200812-CardiomyocyteDifferentiation14-Cycle1.zarr.zip",
12
- "processor": pooch.Unzip(extract_dir=""),
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).",
13
88
  },
14
89
  "CardiomyocyteSmallMip": {
15
90
  "url": "https://zenodo.org/records/13305316/files/20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip",
16
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",
17
98
  "fname": "20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip",
18
- "processor": pooch.Unzip(extract_dir=""),
99
+ "description": "Medium cardiomyocyte dataset 2D MIP (30GB).",
19
100
  },
20
101
  }
21
102
 
103
+ AVAILABLE_DATASETS = Literal[
104
+ "CardiomyocyteTiny",
105
+ "CardiomyocyteTinyMip",
106
+ "CardiomyocyteSmall",
107
+ "CardiomyocyteSmallMip",
108
+ "CardiomyocyteMediumMip",
109
+ ]
110
+
22
111
 
23
112
  def list_ome_zarr_datasets() -> list[str]:
24
113
  """List available OME-Zarr datasets."""
25
114
  return list(_ome_zarr_zoo.keys())
26
115
 
27
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
+
28
122
  def download_ome_zarr_dataset(
29
- dataset_name: str,
30
- download_dir: str = "data",
123
+ dataset_name: AVAILABLE_DATASETS | str,
124
+ download_dir: str | Path = "data",
125
+ re_unzip: bool = True,
126
+ progressbar: bool = False,
31
127
  ) -> Path:
32
128
  """Download an OME-Zarr dataset.
33
129
 
@@ -36,16 +132,28 @@ def download_ome_zarr_dataset(
36
132
  Args:
37
133
  dataset_name (str): The dataset name.
38
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.
39
137
  """
40
138
  if dataset_name not in _ome_zarr_zoo:
41
- raise ValueError(f"Dataset {dataset_name} not found in the OME-Zarr zoo.")
42
- ome_zarr_url = _ome_zarr_zoo[dataset_name]
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
+
43
151
  pooch.retrieve(
152
+ url=zenodo_infos["url"],
153
+ known_hash=zenodo_infos["known_hash"],
154
+ fname=fname,
44
155
  path=download_dir,
45
- **ome_zarr_url,
156
+ processor=processor,
157
+ progressbar=progressbar,
46
158
  )
47
- path = Path(download_dir) / ome_zarr_url["fname"]
48
-
49
- if isinstance(ome_zarr_url["processor"], pooch.Unzip):
50
- path = path.with_suffix("")
51
- return path
159
+ return processor.output_file()
@@ -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