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
ngio/images/_label.py ADDED
@@ -0,0 +1,417 @@
1
+ """A module for handling label images in OME-NGFF files."""
2
+
3
+ from collections.abc import Mapping, Sequence
4
+ from typing import Any, Literal
5
+
6
+ from zarr.core.array import CompressorLike
7
+
8
+ from ngio.common import compute_masking_roi
9
+ from ngio.common._pyramid import ChunksLike, ShardsLike
10
+ from ngio.images._abstract_image import AbstractImage, abstract_derive
11
+ from ngio.images._image import Image
12
+ from ngio.ome_zarr_meta import (
13
+ LabelMetaHandler,
14
+ LabelsGroupMetaHandler,
15
+ NgioLabelMeta,
16
+ NgioLabelsGroupMeta,
17
+ PixelSize,
18
+ update_ngio_labels_group_meta,
19
+ )
20
+ from ngio.ome_zarr_meta.ngio_specs import (
21
+ DefaultSpaceUnit,
22
+ DefaultTimeUnit,
23
+ NgffVersions,
24
+ SpaceUnits,
25
+ TimeUnits,
26
+ )
27
+ from ngio.tables import MaskingRoiTable
28
+ from ngio.utils import (
29
+ NgioValidationError,
30
+ NgioValueError,
31
+ StoreOrGroup,
32
+ ZarrGroupHandler,
33
+ )
34
+
35
+
36
+ class Label(AbstractImage):
37
+ """Placeholder class for a label."""
38
+
39
+ get_as_numpy = AbstractImage._get_as_numpy
40
+ get_as_dask = AbstractImage._get_as_dask
41
+ get_array = AbstractImage._get_array
42
+ get_roi_as_numpy = AbstractImage._get_roi_as_numpy
43
+ get_roi_as_dask = AbstractImage._get_roi_as_dask
44
+ get_roi = AbstractImage._get_roi
45
+ set_array = AbstractImage._set_array
46
+ set_roi = AbstractImage._set_roi
47
+
48
+ def __init__(
49
+ self,
50
+ group_handler: ZarrGroupHandler,
51
+ path: str,
52
+ meta_handler: LabelMetaHandler | None,
53
+ ) -> None:
54
+ """Initialize the Image at a single level.
55
+
56
+ Args:
57
+ group_handler: The Zarr group handler.
58
+ path: The path to the image in the ome_zarr file.
59
+ meta_handler: The image metadata handler.
60
+
61
+ """
62
+ if meta_handler is None:
63
+ meta_handler = LabelMetaHandler(group_handler)
64
+ super().__init__(
65
+ group_handler=group_handler, path=path, meta_handler=meta_handler
66
+ )
67
+
68
+ def __repr__(self) -> str:
69
+ """Return the string representation of the label."""
70
+ return f"Label(path={self.path}, {self.dimensions})"
71
+
72
+ @property
73
+ def meta_handler(self) -> LabelMetaHandler:
74
+ """Return the metadata handler."""
75
+ assert isinstance(self._meta_handler, LabelMetaHandler)
76
+ return self._meta_handler
77
+
78
+ @property
79
+ def meta(self) -> NgioLabelMeta:
80
+ """Return the metadata."""
81
+ meta = self.meta_handler.get_meta()
82
+ assert isinstance(meta, NgioLabelMeta)
83
+ return meta
84
+
85
+ def set_axes_unit(
86
+ self,
87
+ space_unit: SpaceUnits = DefaultSpaceUnit,
88
+ time_unit: TimeUnits = DefaultTimeUnit,
89
+ ) -> None:
90
+ """Set the axes unit of the image.
91
+
92
+ Args:
93
+ space_unit (SpaceUnits): The space unit of the image.
94
+ time_unit (TimeUnits): The time unit of the image.
95
+ """
96
+ meta = self.meta
97
+ meta = meta.to_units(space_unit=space_unit, time_unit=time_unit)
98
+ self.meta_handler.update_meta(meta)
99
+
100
+ def build_masking_roi_table(
101
+ self, axes_order: Sequence[str] | None = None
102
+ ) -> MaskingRoiTable:
103
+ """Compute the masking ROI table."""
104
+ return build_masking_roi_table(self, axes_order=axes_order)
105
+
106
+ def consolidate(
107
+ self,
108
+ mode: Literal["dask", "numpy", "coarsen"] = "dask",
109
+ ) -> None:
110
+ """Consolidate the label on disk."""
111
+ self._consolidate(
112
+ order="nearest",
113
+ mode=mode,
114
+ )
115
+
116
+
117
+ class LabelsContainer:
118
+ """A class to handle the /labels group in an OME-NGFF file."""
119
+
120
+ def __init__(
121
+ self,
122
+ group_handler: ZarrGroupHandler,
123
+ ngff_version: NgffVersions | None = None,
124
+ ) -> None:
125
+ """Initialize the LabelGroupHandler."""
126
+ self._group_handler = group_handler
127
+ # If the group is empty, initialize the metadata
128
+ try:
129
+ self._meta_handler = LabelsGroupMetaHandler(group_handler)
130
+ except NgioValidationError:
131
+ if ngff_version is None:
132
+ raise NgioValueError(
133
+ "The /labels group is missing metadata. "
134
+ "Please provide the ngff_version to initialize it."
135
+ ) from None
136
+ meta = NgioLabelsGroupMeta(labels=[], version=ngff_version)
137
+ update_ngio_labels_group_meta(
138
+ group_handler=group_handler,
139
+ ngio_meta=meta,
140
+ )
141
+ self._group_handler = self._group_handler.reopen_handler()
142
+ self._meta_handler = LabelsGroupMetaHandler(group_handler)
143
+
144
+ @property
145
+ def meta(self) -> NgioLabelsGroupMeta:
146
+ """Return the metadata."""
147
+ meta = self._meta_handler.get_meta()
148
+ return meta
149
+
150
+ def list(self) -> list[str]:
151
+ """Create the /labels group if it doesn't exist."""
152
+ return self.meta.labels
153
+
154
+ def get(
155
+ self,
156
+ name: str,
157
+ path: str | None = None,
158
+ pixel_size: PixelSize | None = None,
159
+ strict: bool = False,
160
+ ) -> Label:
161
+ """Get a label from the group.
162
+
163
+ Args:
164
+ name (str): The name of the label.
165
+ path (str | None): The path to the image in the ome_zarr file.
166
+ pixel_size (PixelSize | None): The pixel size of the image.
167
+ strict (bool): Only used if the pixel size is provided. If True, the
168
+ pixel size must match the image pixel size exactly. If False, the
169
+ closest pixel size level will be returned.
170
+
171
+ """
172
+ if name not in self.list():
173
+ raise NgioValueError(
174
+ f"Label '{name}' not found in the Labels group. "
175
+ f"Available labels: {self.list()}"
176
+ )
177
+
178
+ group_handler = self._group_handler.get_handler(name)
179
+ label_meta_handler = LabelMetaHandler(group_handler)
180
+ path = (
181
+ label_meta_handler.get_meta()
182
+ .get_dataset(path=path, pixel_size=pixel_size, strict=strict)
183
+ .path
184
+ )
185
+ return Label(group_handler, path, label_meta_handler)
186
+
187
+ def delete(self, name: str, missing_ok: bool = False) -> None:
188
+ """Delete a label from the group.
189
+
190
+ Args:
191
+ name (str): The name of the label to delete.
192
+ missing_ok (bool): If True, do not raise an error if the label does not
193
+ exist.
194
+
195
+ """
196
+ existing_labels = self.list()
197
+ if name not in existing_labels:
198
+ if missing_ok:
199
+ return
200
+ raise NgioValueError(
201
+ f"Label '{name}' not found in the Labels group. "
202
+ f"Available labels: {existing_labels}"
203
+ )
204
+
205
+ self._group_handler.delete_group(name)
206
+ existing_labels.remove(name)
207
+ update_meta = NgioLabelsGroupMeta(
208
+ labels=existing_labels, version=self.meta.version
209
+ )
210
+ self._meta_handler.update_meta(update_meta)
211
+
212
+ def derive(
213
+ self,
214
+ name: str,
215
+ ref_image: Image | Label,
216
+ # Metadata parameters
217
+ shape: Sequence[int] | None = None,
218
+ pixelsize: float | tuple[float, float] | None = None,
219
+ z_spacing: float | None = None,
220
+ time_spacing: float | None = None,
221
+ channels_policy: Literal["same", "squeeze", "singleton"] | int = "squeeze",
222
+ ngff_version: NgffVersions | None = None,
223
+ # Zarr Array parameters
224
+ chunks: ChunksLike | None = None,
225
+ shards: ShardsLike | None = None,
226
+ dtype: str | None = None,
227
+ dimension_separator: Literal[".", "/"] | None = None,
228
+ compressors: CompressorLike | None = None,
229
+ extra_array_kwargs: Mapping[str, Any] | None = None,
230
+ overwrite: bool = False,
231
+ # Deprecated arguments
232
+ labels: Sequence[str] | None = None,
233
+ pixel_size: PixelSize | None = None,
234
+ ) -> "Label":
235
+ """Create an empty OME-Zarr image from an existing image.
236
+
237
+ If a kwarg is not provided, the value from the reference image will be used.
238
+
239
+ Args:
240
+ store (StoreOrGroup): The Zarr store or group to create the image in.
241
+ ref_image (Image | Label): The reference image to derive the new image from.
242
+ shape (Sequence[int] | None): The shape of the new image.
243
+ pixelsize (float | tuple[float, float] | None): The pixel size of the new
244
+ image.
245
+ z_spacing (float | None): The z spacing of the new image.
246
+ time_spacing (float | None): The time spacing of the new image.
247
+ scaling_factors (Sequence[float] | Literal["auto"] | None): The scaling
248
+ factors of the new image.
249
+ axes_names (Sequence[str] | None): The axes names of the new image.
250
+ name (str | None): The name of the new image.
251
+ channels_meta (Sequence[str | Channel] | None): The channels metadata
252
+ of the new image.
253
+ channels_policy (Literal["squeeze", "same", "singleton"] | int):
254
+ Possible policies:
255
+ - If "squeeze", the channels axis will be removed (no matter its size).
256
+ - If "same", the channels axis will be kept as is (if it exists).
257
+ - If "singleton", the channels axis will be set to size 1.
258
+ - If an integer is provided, the channels axis will be changed to have
259
+ that size.
260
+ ngff_version (NgffVersions | None): The NGFF version to use.
261
+ chunks (ChunksLike | None): The chunk shape of the new image.
262
+ shards (ShardsLike | None): The shard shape of the new image.
263
+ dtype (str | None): The data type of the new image.
264
+ dimension_separator (DIMENSION_SEPARATOR | None): The separator to use for
265
+ dimensions.
266
+ compressors (CompressorLike | None): The compressors to use.
267
+ extra_array_kwargs (Mapping[str, Any] | None): Extra arguments to pass to
268
+ the zarr array creation.
269
+ overwrite (bool): Whether to overwrite an existing image.
270
+ labels (Sequence[str] | None): The labels of the new image.
271
+ This argument is deprecated please use channels_meta instead.
272
+ pixel_size (PixelSize | None): The pixel size of the new image.
273
+ This argument is deprecated please use pixelsize, z_spacing,
274
+ and time_spacing instead.
275
+
276
+ Returns:
277
+ Label: The new derived label.
278
+
279
+ """
280
+ existing_labels = self.list()
281
+ if name in existing_labels and not overwrite:
282
+ raise NgioValueError(
283
+ f"Label '{name}' already exists in the group. "
284
+ "Use overwrite=True to replace it."
285
+ )
286
+
287
+ label_group = self._group_handler.get_group(name, create_mode=True)
288
+
289
+ derive_label(
290
+ ref_image=ref_image,
291
+ store=label_group,
292
+ shape=shape,
293
+ pixelsize=pixelsize,
294
+ z_spacing=z_spacing,
295
+ time_spacing=time_spacing,
296
+ name=name,
297
+ channels_policy=channels_policy,
298
+ ngff_version=ngff_version,
299
+ chunks=chunks,
300
+ shards=shards,
301
+ dtype=dtype,
302
+ dimension_separator=dimension_separator,
303
+ compressors=compressors,
304
+ extra_array_kwargs=extra_array_kwargs,
305
+ overwrite=overwrite,
306
+ labels=labels,
307
+ pixel_size=pixel_size,
308
+ )
309
+
310
+ if name not in existing_labels:
311
+ existing_labels.append(name)
312
+
313
+ update_meta = NgioLabelsGroupMeta(
314
+ labels=existing_labels, version=self.meta.version
315
+ )
316
+ self._meta_handler.update_meta(update_meta)
317
+ return self.get(name)
318
+
319
+
320
+ def derive_label(
321
+ *,
322
+ store: StoreOrGroup,
323
+ ref_image: Image | Label,
324
+ # Metadata parameters
325
+ shape: Sequence[int] | None = None,
326
+ pixelsize: float | tuple[float, float] | None = None,
327
+ z_spacing: float | None = None,
328
+ time_spacing: float | None = None,
329
+ name: str | None = None,
330
+ channels_policy: Literal["same", "squeeze", "singleton"] | int = "squeeze",
331
+ ngff_version: NgffVersions | None = None,
332
+ # Zarr Array parameters
333
+ chunks: ChunksLike | None = None,
334
+ shards: ShardsLike | None = None,
335
+ dtype: str | None = None,
336
+ dimension_separator: Literal[".", "/"] | None = None,
337
+ compressors: CompressorLike | None = None,
338
+ extra_array_kwargs: Mapping[str, Any] | None = None,
339
+ overwrite: bool = False,
340
+ # Deprecated arguments
341
+ labels: Sequence[str] | None = None,
342
+ pixel_size: PixelSize | None = None,
343
+ ) -> ZarrGroupHandler:
344
+ """Derive a new OME-Zarr label from an existing image or label.
345
+
346
+ If a kwarg is not provided, the value from the reference image will be used.
347
+
348
+ Args:
349
+ store (StoreOrGroup): The Zarr store or group to create the label in.
350
+ ref_image (Image | Label): The reference image to derive the new label from.
351
+ shape (Sequence[int] | None): The shape of the new label.
352
+ pixelsize (float | tuple[float, float] | None): The pixel size of the new label.
353
+ z_spacing (float | None): The z spacing of the new label.
354
+ time_spacing (float | None): The time spacing of the new label.
355
+ name (str | None): The name of the new label.
356
+ channels_policy (Literal["squeeze", "same", "singleton"] | int): Possible
357
+ policies:
358
+ - If "squeeze", the channels axis will be removed (no matter its size).
359
+ - If "same", the channels axis will be kept as is (if it exists).
360
+ - If "singleton", the channels axis will be set to size 1.
361
+ - If an integer is provided, the channels axis will be changed to have that
362
+ size.
363
+ ngff_version (NgffVersions | None): The NGFF version to use.
364
+ chunks (ChunksLike | None): The chunk shape of the new label.
365
+ shards (ShardsLike | None): The shard shape of the new label.
366
+ dtype (str | None): The data type of the new label.
367
+ dimension_separator (Literal[".", "/"] | None): The separator to use for
368
+ dimensions.
369
+ compressors (CompressorLike | None): The compressors to use.
370
+ extra_array_kwargs (Mapping[str, Any] | None): Extra arguments to pass to
371
+ the zarr array creation.
372
+ overwrite (bool): Whether to overwrite an existing label. Defaults to False.
373
+ labels (Sequence[str] | None): Deprecated. This argument is deprecated,
374
+ please use channels_meta instead.
375
+ pixel_size (PixelSize | None): Deprecated. The pixel size of the new label.
376
+ This argument is deprecated, please use pixelsize, z_spacing,
377
+ and time_spacing instead.
378
+
379
+ Returns:
380
+ ZarrGroupHandler: The group handler of the new label.
381
+
382
+ """
383
+ if dtype is None and isinstance(ref_image, Image):
384
+ dtype = "uint32"
385
+ group_handler = abstract_derive(
386
+ ref_image=ref_image,
387
+ meta_type=NgioLabelMeta,
388
+ store=store,
389
+ shape=shape,
390
+ pixelsize=pixelsize,
391
+ z_spacing=z_spacing,
392
+ time_spacing=time_spacing,
393
+ name=name,
394
+ channels_meta=None,
395
+ channels_policy=channels_policy,
396
+ ngff_version=ngff_version,
397
+ chunks=chunks,
398
+ shards=shards,
399
+ dtype=dtype,
400
+ dimension_separator=dimension_separator,
401
+ compressors=compressors,
402
+ extra_array_kwargs=extra_array_kwargs,
403
+ overwrite=overwrite,
404
+ labels=labels,
405
+ pixel_size=pixel_size,
406
+ )
407
+ return group_handler
408
+
409
+
410
+ def build_masking_roi_table(
411
+ label: Label, axes_order: Sequence[str] | None = None
412
+ ) -> MaskingRoiTable:
413
+ """Compute the masking ROI table for a label."""
414
+ axes_order = axes_order or label.axes
415
+ array = label.get_as_dask(axes_order=axes_order)
416
+ rois = compute_masking_roi(array, label.pixel_size, axes_order=axes_order)
417
+ return MaskingRoiTable(rois, reference_label=label.meta.name)