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/image.py DELETED
@@ -1,389 +0,0 @@
1
- """Generic class to handle Image-like data in a OME-NGFF file."""
2
-
3
- from collections.abc import Collection
4
- from typing import Literal
5
-
6
- from dask import array as da
7
-
8
- from ngio.common import Dimensions
9
- from ngio.images.abstract_image import AbstractImage, consolidate_image
10
- from ngio.images.create import _create_empty_image
11
- from ngio.ome_zarr_meta import (
12
- ImageMetaHandler,
13
- ImplementedImageMetaHandlers,
14
- NgioImageMeta,
15
- PixelSize,
16
- )
17
- from ngio.ome_zarr_meta.ngio_specs import Channel, ChannelsMeta, ChannelVisualisation
18
- from ngio.utils import (
19
- NgioValidationError,
20
- StoreOrGroup,
21
- ZarrGroupHandler,
22
- )
23
-
24
-
25
- def _check_channel_meta(meta: NgioImageMeta, dimension: Dimensions) -> ChannelsMeta:
26
- """Check the channel metadata."""
27
- c_dim = dimension.get("c", strict=False)
28
- c_dim = 1 if c_dim is None else c_dim
29
-
30
- if meta.channels_meta is None:
31
- return ChannelsMeta.default_init(labels=c_dim)
32
-
33
- if len(meta.channels) != c_dim:
34
- raise NgioValidationError(
35
- "The number of channels does not match the image. "
36
- f"Expected {len(meta.channels)} channels, got {c_dim}."
37
- )
38
-
39
- return meta.channels_meta
40
-
41
-
42
- class Image(AbstractImage[ImageMetaHandler]):
43
- """A class to handle a single image (or level) in an OME-Zarr image.
44
-
45
- This class is meant to be subclassed by specific image types.
46
- """
47
-
48
- def __init__(
49
- self,
50
- group_handler: ZarrGroupHandler,
51
- path: str,
52
- meta_handler: ImageMetaHandler | 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 omezarr file.
59
- meta_handler: The image metadata handler.
60
-
61
- """
62
- if meta_handler is None:
63
- meta_handler = ImplementedImageMetaHandlers().find_meta_handler(
64
- group_handler
65
- )
66
- super().__init__(
67
- group_handler=group_handler, path=path, meta_handler=meta_handler
68
- )
69
- self._channels_meta = _check_channel_meta(self.meta, self.dimensions)
70
-
71
- @property
72
- def meta(self) -> NgioImageMeta:
73
- """Return the metadata."""
74
- return self._meta_handler.meta
75
-
76
- @property
77
- def channel_labels(self) -> list[str]:
78
- """Return the channels of the image."""
79
- channel_labels = []
80
- for c in self._channels_meta.channels:
81
- channel_labels.append(c.label)
82
- return channel_labels
83
-
84
- @property
85
- def wavelength_ids(self) -> list[str | None]:
86
- """Return the list of wavelength of the image."""
87
- wavelength_ids = []
88
- for c in self._channels_meta.channels:
89
- wavelength_ids.append(c.wavelength_id)
90
- return wavelength_ids
91
-
92
- @property
93
- def num_channels(self) -> int:
94
- """Return the number of channels."""
95
- return len(self._channels_meta.channels)
96
-
97
- def consolidate(
98
- self,
99
- order: Literal[0, 1, 2] = 1,
100
- mode: Literal["dask", "numpy", "coarsen"] = "dask",
101
- ) -> None:
102
- """Consolidate the label on disk."""
103
- consolidate_image(self, order=order, mode=mode)
104
-
105
-
106
- class ImagesContainer:
107
- """A class to handle the /labels group in an OME-NGFF file."""
108
-
109
- def __init__(self, group_handler: ZarrGroupHandler) -> None:
110
- """Initialize the LabelGroupHandler."""
111
- self._group_handler = group_handler
112
- self._meta_handler = ImplementedImageMetaHandlers().find_meta_handler(
113
- group_handler
114
- )
115
-
116
- @property
117
- def meta(self) -> NgioImageMeta:
118
- """Return the metadata."""
119
- return self._meta_handler.meta
120
-
121
- @property
122
- def levels(self) -> int:
123
- """Return the number of levels in the image."""
124
- return self._meta_handler.meta.levels
125
-
126
- @property
127
- def levels_paths(self) -> list[str]:
128
- """Return the paths of the levels in the image."""
129
- return self._meta_handler.meta.paths
130
-
131
- @property
132
- def num_channels(self) -> int:
133
- """Return the number of channels."""
134
- image = self.get()
135
- return image.num_channels
136
-
137
- @property
138
- def channel_labels(self) -> list[str]:
139
- """Return the channels of the image."""
140
- image = self.get()
141
- return image.channel_labels
142
-
143
- @property
144
- def wavelength_ids(self) -> list[str | None]:
145
- """Return the wavelength of the image."""
146
- image = self.get()
147
- return image.wavelength_ids
148
-
149
- def initialize_channel_meta(
150
- self,
151
- labels: Collection[str] | int | None = None,
152
- wavelength_id: Collection[str] | None = None,
153
- percentiles: tuple[float, float] | None = None,
154
- colors: Collection[str] | None = None,
155
- active: Collection[bool] | None = None,
156
- **omero_kwargs: dict,
157
- ) -> None:
158
- """Create a ChannelsMeta object with the default unit.
159
-
160
- Args:
161
- labels(Collection[str] | int): The list of channels names in the image.
162
- If an integer is provided, the channels will be named "channel_i".
163
- wavelength_id(Collection[str] | None): The wavelength ID of the channel.
164
- If None, the wavelength ID will be the same as the channel name.
165
- percentiles(tuple[float, float] | None): The start and end percentiles
166
- for each channel. If None, the percentiles will not be computed.
167
- colors(Collection[str, NgioColors] | None): The list of colors for the
168
- channels. If None, the colors will be random.
169
- active (Collection[bool] | None):active(bool): Whether the channel should
170
- be shown by default.
171
- omero_kwargs(dict): Extra fields to store in the omero attributes.
172
- """
173
- ref = self.get()
174
-
175
- if percentiles is not None:
176
- start, end = compute_image_percentile(
177
- ref, start_percentile=percentiles[0], end_percentile=percentiles[1]
178
- )
179
- else:
180
- start, end = None, None
181
-
182
- if labels is None:
183
- labels = ref.num_channels
184
-
185
- channel_meta = ChannelsMeta.default_init(
186
- labels=labels,
187
- wavelength_id=wavelength_id,
188
- colors=colors,
189
- start=start,
190
- end=end,
191
- active=active,
192
- data_type=ref.dtype,
193
- **omero_kwargs,
194
- )
195
-
196
- meta = self.meta
197
- meta.set_channels_meta(channel_meta)
198
- self._meta_handler.write_meta(meta)
199
-
200
- def update_percentiles(
201
- self,
202
- start_percentile: float = 0.1,
203
- end_percentile: float = 99.9,
204
- ) -> None:
205
- """Update the percentiles of the channels."""
206
- if self.meta._channels_meta is None:
207
- raise NgioValidationError("The channels meta is not initialized.")
208
-
209
- image = self.get()
210
- starts, ends = compute_image_percentile(
211
- image, start_percentile=start_percentile, end_percentile=end_percentile
212
- )
213
-
214
- channels = []
215
- for c, channel in enumerate(self.meta._channels_meta.channels):
216
- new_v = ChannelVisualisation(
217
- start=starts[c],
218
- end=ends[c],
219
- **channel.channel_visualisation.model_dump(exclude={"start", "end"}),
220
- )
221
- new_c = Channel(
222
- channel_visualisation=new_v,
223
- **channel.model_dump(exclude={"channel_visualisation"}),
224
- )
225
- channels.append(new_c)
226
-
227
- new_meta = ChannelsMeta(channels=channels)
228
-
229
- meta = self.meta
230
- meta.set_channels_meta(new_meta)
231
- self._meta_handler.write_meta(meta)
232
-
233
- def derive(
234
- self,
235
- store: StoreOrGroup,
236
- ref_path: str | None = None,
237
- shape: Collection[int] | None = None,
238
- chunks: Collection[int] | None = None,
239
- xy_scaling_factor: float = 2.0,
240
- z_scaling_factor: float = 1.0,
241
- overwrite: bool = False,
242
- ) -> "ImagesContainer":
243
- """Create an OME-Zarr image from a numpy array."""
244
- return derive_image_container(
245
- image_container=self,
246
- store=store,
247
- ref_path=ref_path,
248
- shape=shape,
249
- chunks=chunks,
250
- xy_scaling_factor=xy_scaling_factor,
251
- z_scaling_factor=z_scaling_factor,
252
- overwrite=overwrite,
253
- )
254
-
255
- def get(
256
- self,
257
- path: str | None = None,
258
- pixel_size: PixelSize | None = None,
259
- highest_resolution: bool = True,
260
- ) -> Image:
261
- """Get an image at a specific level."""
262
- if path is not None or pixel_size is not None:
263
- highest_resolution = False
264
- dataset = self._meta_handler.meta.get_dataset(
265
- path=path, pixel_size=pixel_size, highest_resolution=highest_resolution
266
- )
267
- return Image(
268
- group_handler=self._group_handler,
269
- path=dataset.path,
270
- meta_handler=self._meta_handler,
271
- )
272
-
273
-
274
- def compute_image_percentile(
275
- image: Image,
276
- start_percentile: float = 0.1,
277
- end_percentile: float = 99.9,
278
- ) -> tuple[list[float], list[float]]:
279
- """Compute the start and end percentiles for each channel of an image.
280
-
281
- Args:
282
- image: The image to compute the percentiles for.
283
- start_percentile: The start percentile to compute.
284
- end_percentile: The end percentile to compute.
285
-
286
- Returns:
287
- A tuple containing the start and end percentiles for each channel.
288
- """
289
- starts, ends = [], []
290
- for c in range(image.num_channels):
291
- if image.num_channels == 1:
292
- data = image.get_array(mode="dask").ravel()
293
- else:
294
- data = image.get_array(c=c, mode="dask").ravel()
295
- # remove all the zeros
296
- mask = data > 1e-16
297
- data = data[mask]
298
- _data = data.compute()
299
- if _data.size == 0:
300
- starts.append(0.0)
301
- ends.append(0.0)
302
- continue
303
-
304
- # compute the percentiles
305
- _s_perc, _e_perc = da.percentile(
306
- data, [start_percentile, end_percentile], method="nearest"
307
- ).compute()
308
-
309
- starts.append(float(_s_perc))
310
- ends.append(float(_e_perc))
311
-
312
- return starts, ends
313
-
314
-
315
- def derive_image_container(
316
- image_container: ImagesContainer,
317
- store: StoreOrGroup,
318
- ref_path: str | None = None,
319
- shape: Collection[int] | None = None,
320
- chunks: Collection[int] | None = None,
321
- xy_scaling_factor: float = 2.0,
322
- z_scaling_factor: float = 1.0,
323
- overwrite: bool = False,
324
- ) -> ImagesContainer:
325
- """Create an OME-Zarr image from a numpy array."""
326
- if ref_path is None:
327
- ref_image = image_container.get()
328
- else:
329
- ref_image = image_container.get(path=ref_path)
330
-
331
- ref_meta = ref_image.meta
332
-
333
- if shape is None:
334
- shape = ref_image.shape
335
- else:
336
- if len(shape) != len(ref_image.shape):
337
- raise NgioValidationError(
338
- "The shape of the new image does not match the reference image."
339
- )
340
-
341
- if chunks is None:
342
- chunks = ref_image.chunks
343
- else:
344
- if len(chunks) != len(ref_image.chunks):
345
- raise NgioValidationError(
346
- "The chunks of the new image does not match the reference image."
347
- )
348
-
349
- handler = _create_empty_image(
350
- store=store,
351
- shape=shape,
352
- xy_pixelsize=ref_image.pixel_size.x,
353
- z_spacing=ref_image.pixel_size.z,
354
- time_spacing=ref_image.pixel_size.t,
355
- levels=ref_meta.levels,
356
- xy_scaling_factor=xy_scaling_factor,
357
- z_scaling_factor=z_scaling_factor,
358
- time_unit=ref_image.pixel_size.time_unit,
359
- space_unit=ref_image.pixel_size.space_unit,
360
- axes_names=ref_image.dataset.axes_mapper.on_disk_axes_names,
361
- chunks=chunks,
362
- dtype=ref_image.dtype,
363
- overwrite=overwrite,
364
- version=ref_meta.version,
365
- )
366
-
367
- image_container = ImagesContainer(handler)
368
-
369
- if ref_image.num_channels == image_container.num_channels:
370
- labels = ref_image.channel_labels
371
- wavelength_id = ref_image.wavelength_ids
372
- colors = [
373
- c.channel_visualisation.color for c in ref_image._channels_meta.channels
374
- ]
375
- active = [
376
- c.channel_visualisation.active for c in ref_image._channels_meta.channels
377
- ]
378
-
379
- image_container.initialize_channel_meta(
380
- labels=labels,
381
- wavelength_id=wavelength_id,
382
- percentiles=None,
383
- colors=colors,
384
- active=active,
385
- )
386
- else:
387
- image_container.initialize_channel_meta()
388
-
389
- return image_container
ngio/images/label.py DELETED
@@ -1,236 +0,0 @@
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