ngio 0.1.6__py3-none-any.whl → 0.2.0a2__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 (84) hide show
  1. ngio/__init__.py +31 -5
  2. ngio/common/__init__.py +44 -0
  3. ngio/common/_array_pipe.py +160 -0
  4. ngio/common/_axes_transforms.py +63 -0
  5. ngio/common/_common_types.py +5 -0
  6. ngio/common/_dimensions.py +113 -0
  7. ngio/common/_pyramid.py +223 -0
  8. ngio/{core/roi.py → common/_roi.py} +22 -23
  9. ngio/common/_slicer.py +97 -0
  10. ngio/{pipes/_zoom_utils.py → common/_zoom.py} +2 -78
  11. ngio/hcs/__init__.py +60 -0
  12. ngio/images/__init__.py +23 -0
  13. ngio/images/abstract_image.py +240 -0
  14. ngio/images/create.py +251 -0
  15. ngio/images/image.py +389 -0
  16. ngio/images/label.py +236 -0
  17. ngio/images/omezarr_container.py +535 -0
  18. ngio/ome_zarr_meta/__init__.py +35 -0
  19. ngio/ome_zarr_meta/_generic_handlers.py +320 -0
  20. ngio/ome_zarr_meta/_meta_handlers.py +142 -0
  21. ngio/ome_zarr_meta/ngio_specs/__init__.py +63 -0
  22. ngio/ome_zarr_meta/ngio_specs/_axes.py +481 -0
  23. ngio/ome_zarr_meta/ngio_specs/_channels.py +378 -0
  24. ngio/ome_zarr_meta/ngio_specs/_dataset.py +134 -0
  25. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +5 -0
  26. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +434 -0
  27. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +84 -0
  28. ngio/ome_zarr_meta/v04/__init__.py +11 -0
  29. ngio/ome_zarr_meta/v04/_meta_handlers.py +54 -0
  30. ngio/ome_zarr_meta/v04/_v04_spec_utils.py +412 -0
  31. ngio/tables/__init__.py +21 -5
  32. ngio/tables/_validators.py +192 -0
  33. ngio/tables/backends/__init__.py +8 -0
  34. ngio/tables/backends/_abstract_backend.py +71 -0
  35. ngio/tables/backends/_anndata_utils.py +194 -0
  36. ngio/tables/backends/_anndata_v1.py +75 -0
  37. ngio/tables/backends/_json_v1.py +56 -0
  38. ngio/tables/backends/_table_backends.py +102 -0
  39. ngio/tables/tables_container.py +300 -0
  40. ngio/tables/v1/__init__.py +6 -5
  41. ngio/tables/v1/_feature_table.py +161 -0
  42. ngio/tables/v1/_generic_table.py +99 -182
  43. ngio/tables/v1/_masking_roi_table.py +175 -0
  44. ngio/tables/v1/_roi_table.py +226 -0
  45. ngio/utils/__init__.py +23 -10
  46. ngio/utils/_datasets.py +51 -0
  47. ngio/utils/_errors.py +10 -4
  48. ngio/utils/_zarr_utils.py +378 -0
  49. {ngio-0.1.6.dist-info → ngio-0.2.0a2.dist-info}/METADATA +18 -39
  50. ngio-0.2.0a2.dist-info/RECORD +53 -0
  51. ngio/core/__init__.py +0 -7
  52. ngio/core/dimensions.py +0 -122
  53. ngio/core/image_handler.py +0 -228
  54. ngio/core/image_like_handler.py +0 -549
  55. ngio/core/label_handler.py +0 -410
  56. ngio/core/ngff_image.py +0 -387
  57. ngio/core/utils.py +0 -287
  58. ngio/io/__init__.py +0 -19
  59. ngio/io/_zarr.py +0 -88
  60. ngio/io/_zarr_array_utils.py +0 -0
  61. ngio/io/_zarr_group_utils.py +0 -60
  62. ngio/iterators/__init__.py +0 -1
  63. ngio/ngff_meta/__init__.py +0 -27
  64. ngio/ngff_meta/fractal_image_meta.py +0 -1267
  65. ngio/ngff_meta/meta_handler.py +0 -92
  66. ngio/ngff_meta/utils.py +0 -235
  67. ngio/ngff_meta/v04/__init__.py +0 -6
  68. ngio/ngff_meta/v04/specs.py +0 -158
  69. ngio/ngff_meta/v04/zarr_utils.py +0 -376
  70. ngio/pipes/__init__.py +0 -7
  71. ngio/pipes/_slicer_transforms.py +0 -176
  72. ngio/pipes/_transforms.py +0 -33
  73. ngio/pipes/data_pipe.py +0 -52
  74. ngio/tables/_ad_reader.py +0 -80
  75. ngio/tables/_utils.py +0 -301
  76. ngio/tables/tables_group.py +0 -252
  77. ngio/tables/v1/feature_tables.py +0 -182
  78. ngio/tables/v1/masking_roi_tables.py +0 -243
  79. ngio/tables/v1/roi_tables.py +0 -285
  80. ngio/utils/_common_types.py +0 -5
  81. ngio/utils/_pydantic_utils.py +0 -52
  82. ngio-0.1.6.dist-info/RECORD +0 -44
  83. {ngio-0.1.6.dist-info → ngio-0.2.0a2.dist-info}/WHEEL +0 -0
  84. {ngio-0.1.6.dist-info → ngio-0.2.0a2.dist-info}/licenses/LICENSE +0 -0
ngio/images/label.py ADDED
@@ -0,0 +1,236 @@
1
+ """A module for handling label images in OME-NGFF files."""
2
+
3
+ from collections.abc import Collection
4
+ from typing import Literal
5
+
6
+ from ngio.images.abstract_image import AbstractImage, consolidate_image
7
+ from ngio.images.create import _create_empty_label
8
+ from ngio.images.image import Image
9
+ from ngio.ome_zarr_meta import (
10
+ ImplementedLabelMetaHandlers,
11
+ LabelMetaHandler,
12
+ NgioLabelMeta,
13
+ )
14
+ from ngio.ome_zarr_meta.ngio_specs import SpaceUnits, TimeUnits
15
+ from ngio.utils import (
16
+ NgioValidationError,
17
+ NgioValueError,
18
+ StoreOrGroup,
19
+ ZarrGroupHandler,
20
+ )
21
+
22
+
23
+ class Label(AbstractImage[LabelMetaHandler]):
24
+ """Placeholder class for a label."""
25
+
26
+ def __init__(
27
+ self,
28
+ group_handler: ZarrGroupHandler,
29
+ path: str,
30
+ meta_handler: LabelMetaHandler | None,
31
+ ) -> None:
32
+ """Initialize the Image at a single level.
33
+
34
+ Args:
35
+ group_handler: The Zarr group handler.
36
+ path: The path to the image in the omezarr file.
37
+ meta_handler: The image metadata handler.
38
+
39
+ """
40
+ if meta_handler is None:
41
+ meta_handler = ImplementedLabelMetaHandlers().find_meta_handler(
42
+ group_handler
43
+ )
44
+ super().__init__(
45
+ group_handler=group_handler, path=path, meta_handler=meta_handler
46
+ )
47
+
48
+ @property
49
+ def meta(self) -> NgioLabelMeta:
50
+ """Return the metadata."""
51
+ return self._meta_handler.meta
52
+
53
+ def consolidate(
54
+ self,
55
+ mode: Literal["dask", "numpy", "coarsen"] = "dask",
56
+ ) -> None:
57
+ """Consolidate the label on disk."""
58
+ consolidate_image(self, mode=mode, order=0)
59
+
60
+
61
+ class LabelsContainer:
62
+ """A class to handle the /labels group in an OME-NGFF file."""
63
+
64
+ def __init__(self, group_handler: ZarrGroupHandler) -> None:
65
+ """Initialize the LabelGroupHandler."""
66
+ self._group_handler = group_handler
67
+
68
+ # Validate the group
69
+ # Either contains a labels attribute or is empty
70
+ attrs = self._group_handler.load_attrs()
71
+ if len(attrs) == 0:
72
+ # It's an empty group
73
+ pass
74
+ elif "labels" in attrs and isinstance(attrs["labels"], list):
75
+ # It's a valid group
76
+ pass
77
+ else:
78
+ raise NgioValidationError(
79
+ f"Invalid /labels group. "
80
+ f"Expected a single labels attribute with a list of label names. "
81
+ f"Found: {attrs}"
82
+ )
83
+
84
+ def list(self) -> list[str]:
85
+ """Create the /labels group if it doesn't exist."""
86
+ attrs = self._group_handler.load_attrs()
87
+ return attrs.get("labels", [])
88
+
89
+ def get(self, name: str, path: str) -> Label:
90
+ """Get a label from the group."""
91
+ group_handler = self._group_handler.derive_handler(name)
92
+ return Label(group_handler, path, None)
93
+
94
+ def derive(
95
+ self,
96
+ name: str,
97
+ ref_image: Image,
98
+ shape: Collection[int] | None = None,
99
+ chunks: Collection[int] | None = None,
100
+ dtype: str = "uint16",
101
+ xy_scaling_factor=2.0,
102
+ z_scaling_factor=1.0,
103
+ overwrite: bool = False,
104
+ ) -> None:
105
+ """Add a label to the group."""
106
+ existing_labels = self.list()
107
+ if name in existing_labels and not overwrite:
108
+ raise NgioValueError(
109
+ f"Table '{name}' already exists in the group. "
110
+ "Use overwrite=True to replace it."
111
+ )
112
+
113
+ label_group = self._group_handler.get_group(name, create_mode=True)
114
+
115
+ _derive_label(
116
+ ref_image=ref_image,
117
+ store=label_group,
118
+ shape=shape,
119
+ chunks=chunks,
120
+ dtype=dtype,
121
+ xy_scaling_factor=xy_scaling_factor,
122
+ z_scaling_factor=z_scaling_factor,
123
+ overwrite=overwrite,
124
+ )
125
+
126
+ if name not in existing_labels:
127
+ existing_labels.append(name)
128
+ self._group_handler.write_attrs({"labels": existing_labels})
129
+
130
+ def new(
131
+ self,
132
+ name: str,
133
+ shape: Collection[int],
134
+ xy_pixelsize: float,
135
+ z_spacing: float = 1.0,
136
+ time_spacing: float = 1.0,
137
+ levels: "int | list[str]" = 5,
138
+ xy_scaling_factor: float = 2.0,
139
+ z_scaling_factor: float = 1.0,
140
+ space_unit: SpaceUnits | str | None = None,
141
+ time_unit: TimeUnits | str | None = None,
142
+ axes_names: Collection[str] | None = None,
143
+ chunks: Collection[int] | None = None,
144
+ dtype: str = "uint16",
145
+ overwrite: bool = False,
146
+ version: str = "0.4",
147
+ ) -> None:
148
+ """Add a label to the group."""
149
+ existing_labels = self.list()
150
+ if name in existing_labels and not overwrite:
151
+ raise NgioValueError(
152
+ f"Table '{name}' already exists in the group. "
153
+ "Use overwrite=True to replace it."
154
+ )
155
+
156
+ label_group = self._group_handler.get_group(name, create_mode=True)
157
+
158
+ _create_empty_label(
159
+ store=label_group,
160
+ shape=shape,
161
+ xy_pixelsize=xy_pixelsize,
162
+ z_spacing=z_spacing,
163
+ time_spacing=time_spacing,
164
+ levels=levels,
165
+ xy_scaling_factor=xy_scaling_factor,
166
+ z_scaling_factor=z_scaling_factor,
167
+ space_unit=space_unit,
168
+ time_unit=time_unit,
169
+ axes_names=axes_names,
170
+ chunks=chunks,
171
+ dtype=dtype,
172
+ overwrite=overwrite,
173
+ version=version,
174
+ )
175
+
176
+ if name not in existing_labels:
177
+ existing_labels.append(name)
178
+ self._group_handler.write_attrs({"labels": existing_labels})
179
+
180
+
181
+ def _derive_label(
182
+ ref_image: Image,
183
+ store: StoreOrGroup,
184
+ shape: Collection[int] | None = None,
185
+ chunks: Collection[int] | None = None,
186
+ dtype: str = "uint16",
187
+ xy_scaling_factor=2.0,
188
+ z_scaling_factor=1.0,
189
+ overwrite: bool = False,
190
+ ) -> None:
191
+ """Create an OME-Zarr image from a numpy array."""
192
+ ref_meta = ref_image.meta
193
+ # remove channls if present
194
+ shape_ref = ref_image.shape
195
+ chunks_ref = ref_image.chunks
196
+ axes_names_ref = ref_image.dataset.axes_mapper.on_disk_axes_names
197
+ c_axis = ref_image.dataset.axes_mapper.get_index("c")
198
+ if c_axis is not None:
199
+ shape_ref = shape_ref[:c_axis] + shape_ref[c_axis + 1 :]
200
+ chunks_ref = chunks_ref[:c_axis] + chunks_ref[c_axis + 1 :]
201
+ axes_names_ref = axes_names_ref[:c_axis] + axes_names_ref[c_axis + 1 :]
202
+
203
+ if shape is None:
204
+ shape = shape_ref
205
+
206
+ if chunks is None:
207
+ chunks = chunks_ref
208
+
209
+ if len(shape) != len(shape_ref):
210
+ raise NgioValidationError(
211
+ "The shape of the new image does not match the reference image."
212
+ )
213
+
214
+ if len(chunks) != len(chunks_ref):
215
+ raise NgioValidationError(
216
+ "The chunks of the new image does not match the reference image."
217
+ )
218
+
219
+ _ = _create_empty_label(
220
+ store=store,
221
+ shape=shape,
222
+ xy_pixelsize=ref_image.pixel_size.x,
223
+ z_spacing=ref_image.pixel_size.z,
224
+ time_spacing=ref_image.pixel_size.t,
225
+ levels=ref_meta.levels,
226
+ xy_scaling_factor=xy_scaling_factor,
227
+ z_scaling_factor=z_scaling_factor,
228
+ time_unit=ref_image.pixel_size.time_unit,
229
+ space_unit=ref_image.pixel_size.space_unit,
230
+ axes_names=axes_names_ref,
231
+ chunks=chunks,
232
+ dtype=dtype,
233
+ overwrite=overwrite,
234
+ version=ref_meta.version,
235
+ )
236
+ return None