ngio 0.1.6__py3-none-any.whl → 0.2.0a1__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 +222 -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 +383 -0
  16. ngio/images/label.py +96 -0
  17. ngio/images/omezarr_container.py +512 -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.0a1.dist-info}/METADATA +18 -39
  50. ngio-0.2.0a1.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.0a1.dist-info}/WHEEL +0 -0
  84. {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/licenses/LICENSE +0 -0
ngio/core/ngff_image.py DELETED
@@ -1,387 +0,0 @@
1
- """Abstract class for handling OME-NGFF images."""
2
-
3
- from typing import Any
4
-
5
- import dask.array as da
6
- import numpy as np
7
- import zarr
8
-
9
- from ngio.core.image_handler import Image
10
- from ngio.core.label_handler import LabelGroup
11
- from ngio.core.utils import create_empty_ome_zarr_image
12
- from ngio.io import AccessModeLiteral, StoreLike, open_group_wrapper
13
- from ngio.ngff_meta import get_ngff_image_meta_handler
14
- from ngio.ngff_meta.fractal_image_meta import ImageMeta, PixelSize
15
- from ngio.tables.tables_group import TableGroup
16
- from ngio.utils import ngio_logger
17
-
18
-
19
- class NgffImage:
20
- """A class to handle OME-NGFF images."""
21
-
22
- def __init__(
23
- self, store: StoreLike, cache: bool = False, mode: AccessModeLiteral = "r+"
24
- ) -> None:
25
- """Initialize the NGFFImage in read mode."""
26
- self.store = store
27
- self._mode = mode
28
- self._group = open_group_wrapper(store=store, mode=self._mode)
29
-
30
- if self._group.read_only:
31
- self._mode = "r"
32
-
33
- self._image_meta = get_ngff_image_meta_handler(
34
- self._group, meta_mode="image", cache=cache
35
- )
36
- self._metadata_cache = cache
37
- self.tables = TableGroup(self._group, mode=self._mode)
38
- self.labels = LabelGroup(
39
- self._group, image_ref=self.get_image(), mode=self._mode
40
- )
41
-
42
- ngio_logger.info(f"Opened image located in store: {store}")
43
- ngio_logger.info(f"- Image number of levels: {self.num_levels}")
44
-
45
- def __repr__(self) -> str:
46
- """Get the string representation of the image."""
47
- name = "NGFFImage("
48
- len_name = len(name)
49
- return (
50
- f"{name}"
51
- f"group_path={self.group_path}, \n"
52
- f"{' ':>{len_name}}paths={self.levels_paths}, \n"
53
- f"{' ':>{len_name}}labels={self.labels.list()}, \n"
54
- f"{' ':>{len_name}}tables={self.tables.list()}, \n"
55
- ")"
56
- )
57
-
58
- @property
59
- def group(self) -> zarr.Group:
60
- """Get the group of the image."""
61
- return self._group
62
-
63
- @property
64
- def root_path(self) -> str:
65
- """Get the root path of the image."""
66
- return str(self._group.store.path)
67
-
68
- @property
69
- def group_path(self) -> str:
70
- """Get the path of the group."""
71
- root = self.root_path
72
- if root.endswith("/"):
73
- root = root[:-1]
74
- return f"{root}/{self._group.path}"
75
-
76
- @property
77
- def image_meta(self) -> ImageMeta:
78
- """Get the image metadata."""
79
- meta = self._image_meta.load_meta()
80
- assert isinstance(meta, ImageMeta)
81
- return meta
82
-
83
- @property
84
- def num_levels(self) -> int:
85
- """Get the number of levels in the image."""
86
- return self.image_meta.num_levels
87
-
88
- @property
89
- def levels_paths(self) -> list[str]:
90
- """Get the paths of the levels in the image."""
91
- return self.image_meta.levels_paths
92
-
93
- def get_image(
94
- self,
95
- *,
96
- path: str | None = None,
97
- pixel_size: PixelSize | None = None,
98
- highest_resolution: bool = True,
99
- ) -> Image:
100
- """Get an image handler for the given level.
101
-
102
- Args:
103
- path (str | None, optional): The path to the level.
104
- pixel_size (tuple[float, ...] | list[float] | None, optional): The pixel
105
- size of the level.
106
- highest_resolution (bool, optional): Whether to get the highest
107
- resolution level
108
-
109
- Returns:
110
- ImageHandler: The image handler.
111
- """
112
- if path is not None or pixel_size is not None:
113
- highest_resolution = False
114
-
115
- image = Image(
116
- store=self._group,
117
- path=path,
118
- pixel_size=pixel_size,
119
- highest_resolution=highest_resolution,
120
- label_group=LabelGroup(self._group, image_ref=None, mode=self._mode),
121
- cache=self._metadata_cache,
122
- mode=self._mode,
123
- )
124
- ngio_logger.info(f"Opened image at path: {image.path}")
125
- ngio_logger.info(f"- {image.dimensions}")
126
- ngio_logger.info(f"- {image.pixel_size}")
127
- return image
128
-
129
- def _compute_percentiles(
130
- self, start_percentile: float, end_percentile: float
131
- ) -> tuple[list[float], list[float]]:
132
- """Compute the percentiles for the window.
133
-
134
- This will setup percentiles based values for the window of each channel.
135
-
136
- Args:
137
- start_percentile (int): The start percentile.
138
- end_percentile (int): The end percentile
139
-
140
- """
141
- meta = self.image_meta
142
-
143
- lowest_res_image = self.get_image(highest_resolution=True)
144
- lowest_res_shape = lowest_res_image.shape
145
- for path in self.levels_paths:
146
- image = self.get_image(path=path)
147
- if np.prod(image.shape) < np.prod(lowest_res_shape):
148
- lowest_res_shape = image.shape
149
- lowest_res_image = image
150
-
151
- num_c = lowest_res_image.dimensions.get("c", 1)
152
-
153
- if meta.omero is None:
154
- raise NotImplementedError(
155
- "OMERO metadata not found. Please add OMERO metadata to the image."
156
- )
157
-
158
- channel_list = meta.omero.channels
159
- if len(channel_list) != num_c:
160
- raise ValueError("The number of channels does not match the image.")
161
-
162
- starts, ends = [], []
163
- for c in range(num_c):
164
- data = lowest_res_image.get_array(c=c, mode="dask").ravel()
165
- _start_percentile, _end_percentile = da.percentile(
166
- data, [start_percentile, end_percentile], method="nearest"
167
- ).compute()
168
-
169
- starts.append(_start_percentile)
170
- ends.append(_end_percentile)
171
-
172
- return starts, ends
173
-
174
- def lazy_init_omero(
175
- self,
176
- labels: list[str] | int | None = None,
177
- wavelength_ids: list[str] | None = None,
178
- colors: list[str] | None = None,
179
- active: list[bool] | None = None,
180
- start_percentile: float | None = 1,
181
- end_percentile: float | None = 99,
182
- data_type: Any = np.uint16,
183
- consolidate: bool = True,
184
- ) -> None:
185
- """Set the OMERO metadata for the image.
186
-
187
- Args:
188
- labels (list[str] | int | None): The labels of the channels.
189
- wavelength_ids (list[str] | None): The wavelengths of the channels.
190
- colors (list[str] | None): The colors of the channels.
191
- active (list[bool] | None): Whether the channels are active.
192
- start_percentile (float | None): The start percentile for computing the data
193
- range. If None, the start is the same as the min value of the data type.
194
- end_percentile (float | None): The end percentile for for computing the data
195
- range. If None, the start is the same as the max value of the data type.
196
- data_type (Any): The data type of the image.
197
- consolidate (bool): Whether to consolidate the metadata.
198
- """
199
- if labels is None:
200
- ref = self.get_image()
201
- labels = ref.num_channels
202
-
203
- if start_percentile is not None and end_percentile is not None:
204
- start, end = self._compute_percentiles(
205
- start_percentile=start_percentile, end_percentile=end_percentile
206
- )
207
- elif start_percentile is None and end_percentile is None:
208
- raise ValueError("Both start and end percentiles cannot be None.")
209
- elif end_percentile is None and start_percentile is not None:
210
- raise ValueError(
211
- "End percentile cannot be None if start percentile is not."
212
- )
213
- else:
214
- start, end = None, None
215
-
216
- self.image_meta.lazy_init_omero(
217
- labels=labels,
218
- wavelength_ids=wavelength_ids,
219
- colors=colors,
220
- start=start,
221
- end=end,
222
- active=active,
223
- data_type=data_type,
224
- )
225
-
226
- if consolidate:
227
- self._image_meta.write_meta(self.image_meta)
228
-
229
- def update_omero_window(
230
- self,
231
- start_percentile: int = 1,
232
- end_percentile: int = 99,
233
- min_value: int | float | None = None,
234
- max_value: int | float | None = None,
235
- ) -> None:
236
- """Update the OMERO window.
237
-
238
- This will setup percentiles based values for the window of each channel.
239
-
240
- Args:
241
- start_percentile (int): The start percentile.
242
- end_percentile (int): The end percentile
243
- min_value (int | float | None): The minimum value of the window.
244
- max_value (int | float | None): The maximum value of the window.
245
-
246
- """
247
- start, ends = self._compute_percentiles(
248
- start_percentile=start_percentile, end_percentile=end_percentile
249
- )
250
- meta = self.image_meta
251
- ref_image = self.get_image()
252
-
253
- for func in [np.iinfo, np.finfo]:
254
- try:
255
- type_max = func(ref_image.on_disk_array.dtype).max
256
- type_min = func(ref_image.on_disk_array.dtype).min
257
- break
258
- except ValueError:
259
- continue
260
- else:
261
- raise ValueError("Data type not recognized.")
262
-
263
- if min_value is None:
264
- min_value = type_min
265
- if max_value is None:
266
- max_value = type_max
267
-
268
- num_c = ref_image.dimensions.get("c", 1)
269
-
270
- if meta.omero is None:
271
- raise NotImplementedError(
272
- "OMERO metadata not found. Please add OMERO metadata to the image."
273
- )
274
-
275
- channel_list = meta.omero.channels
276
- if len(channel_list) != num_c:
277
- raise ValueError("The number of channels does not match the image.")
278
-
279
- if len(channel_list) != len(start):
280
- raise ValueError("The number of channels does not match the image.")
281
-
282
- for c, (channel, s, e) in enumerate(
283
- zip(channel_list, start, ends, strict=True)
284
- ):
285
- channel.channel_visualisation.start = s
286
- channel.channel_visualisation.end = e
287
- channel.channel_visualisation.min = min_value
288
- channel.channel_visualisation.max = max_value
289
-
290
- ngio_logger.info(
291
- f"Updated window for channel {channel.label}. "
292
- f"Start: {start_percentile}, End: {end_percentile}"
293
- )
294
- meta.omero.channels[c] = channel
295
-
296
- self._image_meta.write_meta(meta)
297
-
298
- def derive_new_image(
299
- self,
300
- store: StoreLike,
301
- name: str,
302
- overwrite: bool = True,
303
- copy_labels: bool = False,
304
- copy_tables: bool = False,
305
- **kwargs: dict,
306
- ) -> "NgffImage":
307
- """Derive a new image from the current image.
308
-
309
- Args:
310
- store (StoreLike): The store to create the new image in.
311
- name (str): The name of the new image.
312
- overwrite (bool): Whether to overwrite the image if it exists
313
- copy_labels (bool): Whether to copy the labels from the current image
314
- to the new image.
315
- copy_tables (bool): Whether to copy the tables from the current image
316
- to the new image.
317
- **kwargs: Additional keyword arguments.
318
- Follow the same signature as `create_empty_ome_zarr_image`.
319
-
320
- Returns:
321
- NgffImage: The new image.
322
- """
323
- image_0 = self.get_image(highest_resolution=True)
324
-
325
- # Get the channel information if it exists
326
- omero = self.image_meta.omero
327
- if omero is not None:
328
- channels = omero.channels
329
- omero_kwargs = omero.extra_fields
330
- else:
331
- channels = []
332
- omero_kwargs = {}
333
-
334
- default_kwargs = {
335
- "store": store,
336
- "on_disk_shape": image_0.on_disk_shape,
337
- "chunks": image_0.on_disk_array.chunks,
338
- "dtype": image_0.on_disk_array.dtype,
339
- "on_disk_axis": image_0.dataset.on_disk_axes_names,
340
- "pixel_sizes": image_0.pixel_size,
341
- "xy_scaling_factor": self.image_meta.xy_scaling_factor,
342
- "z_scaling_factor": self.image_meta.z_scaling_factor,
343
- "time_spacing": image_0.dataset.time_spacing,
344
- "time_units": image_0.dataset.time_axis_unit,
345
- "levels": self.num_levels,
346
- "name": name,
347
- "channel_labels": image_0.channel_labels,
348
- "channel_wavelengths": [ch.wavelength_id for ch in channels],
349
- "channel_visualization": [ch.channel_visualisation for ch in channels],
350
- "omero_kwargs": omero_kwargs,
351
- "overwrite": overwrite,
352
- "version": self.image_meta.version,
353
- }
354
-
355
- default_kwargs.update(kwargs)
356
-
357
- create_empty_ome_zarr_image(
358
- **default_kwargs,
359
- )
360
-
361
- new_image = NgffImage(store=store)
362
-
363
- if copy_tables:
364
- # TODO: to be refactored when the table location is changed in the spec
365
- source_tables_group = self.tables._table_group
366
-
367
- if source_tables_group is None:
368
- raise ValueError("No tables group found in the source image.")
369
-
370
- zarr.copy(source=source_tables_group, dest=new_image.group)
371
-
372
- # Reopen the image to get the new tables
373
- new_image = NgffImage(store=store)
374
-
375
- if copy_labels:
376
- # TODO: to be refactored when the label location is changed in the spec
377
- source_labels_group = self.labels._label_group
378
-
379
- if source_labels_group is None:
380
- raise ValueError("No labels group found in the source image.")
381
-
382
- zarr.copy(source=source_labels_group, dest=new_image.group)
383
-
384
- # Reopen the image to get the new labels
385
- new_image = NgffImage(store=store)
386
-
387
- return new_image
ngio/core/utils.py DELETED
@@ -1,287 +0,0 @@
1
- """Utility functions for creating and manipulating images."""
2
-
3
- import math
4
- from collections.abc import Collection
5
- from enum import Enum
6
- from typing import Any
7
-
8
- import fsspec.implementations.http
9
-
10
- from ngio.io import Group, StoreLike
11
- from ngio.ngff_meta import (
12
- ImageLabelMeta,
13
- create_image_metadata,
14
- create_label_metadata,
15
- get_ngff_image_meta_handler,
16
- )
17
- from ngio.ngff_meta.fractal_image_meta import (
18
- ChannelVisualisation,
19
- PixelSize,
20
- TimeUnits,
21
- )
22
-
23
-
24
- def get_fsspec_http_store(
25
- url: str, client_kwargs: dict | None = None
26
- ) -> fsspec.mapping.FSMap:
27
- """Simple function to get an http fsspec store from a url."""
28
- client_kwargs = {} if client_kwargs is None else client_kwargs
29
- fs = fsspec.implementations.http.HTTPFileSystem(client_kwargs=client_kwargs)
30
- store = fs.get_mapper(url)
31
- return store
32
-
33
-
34
- class State(Enum):
35
- """The state of an object.
36
-
37
- It can either be:
38
- - "Memory"
39
- - "Consolidated"
40
- If the state is "Memory" means that some data/metadata is not stored on disk.
41
- The state can be write on disk using .consolidate()
42
- """
43
-
44
- MEMORY = "Memory"
45
- CONSOLIDATED = "Consolidated"
46
-
47
-
48
- def _build_empty_pyramid(
49
- group: Group,
50
- image_meta: ImageLabelMeta,
51
- on_disk_shape: Collection[int],
52
- chunks: Collection[int] | None = None,
53
- dtype: str = "uint16",
54
- on_disk_axis: Collection[str] = ("t", "c", "z", "y"),
55
- xy_scaling_factor: float = 2.0,
56
- z_scaling_factor: float = 1.0,
57
- ) -> None:
58
- # Return the an Image object
59
- scaling_factor = []
60
- for ax in on_disk_axis:
61
- if ax in ["x", "y"]:
62
- scaling_factor.append(xy_scaling_factor)
63
- elif ax == "z":
64
- scaling_factor.append(z_scaling_factor)
65
- else:
66
- scaling_factor.append(1.0)
67
-
68
- if chunks is not None and len(on_disk_shape) != len(chunks):
69
- raise ValueError(
70
- "The shape and chunks must have the same number of dimensions."
71
- )
72
-
73
- if len(on_disk_shape) != len(scaling_factor):
74
- raise ValueError(
75
- "The shape and scaling factor must have the same number of dimensions."
76
- )
77
-
78
- if len(on_disk_shape) != len(on_disk_axis):
79
- raise ValueError(
80
- "The shape and on-disk axis must have the same number of dimensions."
81
- )
82
-
83
- for dataset in image_meta.datasets:
84
- path = dataset.path
85
-
86
- # V3
87
- # group.create_array(
88
- # name=path, fill_value=0, shape=shape, dtype=dtype, chunks=chunks,
89
- # )
90
-
91
- group.zeros(
92
- name=path,
93
- shape=on_disk_shape,
94
- dtype=dtype,
95
- chunks=chunks,
96
- dimension_separator="/",
97
- )
98
-
99
- # Todo redo this with when a proper build of pyramid is implemented
100
- _shape = []
101
- for s, sc in zip(on_disk_shape, scaling_factor, strict=True):
102
- if math.floor(s / sc) % 2 == 0:
103
- _shape.append(math.floor(s / sc))
104
- else:
105
- _shape.append(math.ceil(s / sc))
106
- on_disk_shape = list(_shape)
107
-
108
- if chunks is not None:
109
- chunks = [min(c, s) for c, s in zip(chunks, on_disk_shape, strict=True)]
110
- return None
111
-
112
-
113
- def create_empty_ome_zarr_image(
114
- store: StoreLike,
115
- on_disk_shape: Collection[int],
116
- on_disk_axis: Collection[str] = ("t", "c", "z", "y", "x"),
117
- chunks: Collection[int] | None = None,
118
- dtype: str = "uint16",
119
- pixel_sizes: PixelSize | None = None,
120
- xy_scaling_factor: float = 2.0,
121
- z_scaling_factor: float = 1.0,
122
- time_spacing: float = 1.0,
123
- time_units: TimeUnits | str = TimeUnits.s,
124
- levels: int | list[str] = 5,
125
- name: str | None = None,
126
- channel_labels: list[str] | None = None,
127
- channel_wavelengths: list[str] | None = None,
128
- channel_visualization: list[ChannelVisualisation] | None = None,
129
- omero_kwargs: dict[str, Any] | None = None,
130
- overwrite: bool = True,
131
- version: str = "0.4",
132
- ) -> None:
133
- """Create an empty OME-Zarr image with the given shape and metadata.
134
-
135
- Args:
136
- store (StoreLike): The store to create the image in.
137
- on_disk_shape (Collection[int]): The shape of the image on disk.
138
- on_disk_axis (Collection[str]): The order of the axes on disk.
139
- chunks (Collection[int] | None): The chunk shape for the image.
140
- dtype (str): The data type of the image.
141
- pixel_sizes (PixelSize | None): The pixel size of the image.
142
- xy_scaling_factor (float): The scaling factor in the x and y dimensions.
143
- z_scaling_factor (float): The scaling factor in the z dimension.
144
- time_spacing (float): The spacing between time points.
145
- time_units (TimeUnits | str): The units of the time axis.
146
- levels (int | list[str]): The number of levels in the pyramid.
147
- path_names (list[str] | None): The names of the paths in the image.
148
- name (str | None): The name of the image.
149
- channel_labels (list[str] | None): The labels of the channels.
150
- channel_wavelengths (list[str] | None): The wavelengths of the channels.
151
- channel_visualization (list[ChannelVisualisation] | None): A list of
152
- channel visualisation objects.
153
- omero_kwargs (dict[str, Any] | None): The extra fields for the image.
154
- overwrite (bool): Whether to overwrite the image if it exists.
155
- version (str): The version of the OME-Zarr format.
156
-
157
- """
158
- if len(on_disk_shape) != len(on_disk_axis):
159
- raise ValueError(
160
- "The number of dimensions in the shape must match the number of "
161
- "axes in the on-disk axis."
162
- )
163
-
164
- if "c" in on_disk_axis:
165
- on_disk_shape = tuple(on_disk_shape)
166
- on_disk_axis = tuple(on_disk_axis)
167
- num_channels = on_disk_shape[on_disk_axis.index("c")]
168
- if channel_labels is None:
169
- channel_labels = [f"C{i:02d}" for i in range(num_channels)]
170
- else:
171
- if len(channel_labels) != num_channels:
172
- raise ValueError(
173
- "The number of channel labels must match the number "
174
- f"of channels in the shape. Got {len(channel_labels)} "
175
- f"labels for {num_channels} channels."
176
- )
177
-
178
- image_meta = create_image_metadata(
179
- on_disk_axis=on_disk_axis,
180
- pixel_sizes=pixel_sizes,
181
- xy_scaling_factor=xy_scaling_factor,
182
- z_scaling_factor=z_scaling_factor,
183
- time_spacing=time_spacing,
184
- time_units=time_units,
185
- levels=levels,
186
- name=name,
187
- channel_labels=channel_labels,
188
- channel_wavelengths=channel_wavelengths,
189
- channel_visualization=channel_visualization,
190
- omero_kwargs=omero_kwargs,
191
- version=version,
192
- )
193
-
194
- # Open the store (if it is not empty, fail)
195
- mode = "w" if overwrite else "w-"
196
- meta_handler = get_ngff_image_meta_handler(
197
- store=store, version=version, meta_mode="image", mode=mode
198
- )
199
- meta_handler.write_meta(image_meta)
200
- group = meta_handler.group
201
-
202
- # Create the empty image at each level in the pyramid
203
- _build_empty_pyramid(
204
- group=group,
205
- image_meta=image_meta,
206
- on_disk_shape=on_disk_shape,
207
- chunks=chunks,
208
- dtype=dtype,
209
- on_disk_axis=on_disk_axis,
210
- xy_scaling_factor=xy_scaling_factor,
211
- z_scaling_factor=z_scaling_factor,
212
- )
213
-
214
-
215
- def create_empty_ome_zarr_label(
216
- store: StoreLike,
217
- on_disk_shape: Collection[int],
218
- chunks: Collection[int] | None = None,
219
- dtype: str = "uint16",
220
- on_disk_axis: Collection[str] = ("t", "z", "y", "x"),
221
- pixel_sizes: PixelSize | None = None,
222
- xy_scaling_factor: float = 2.0,
223
- z_scaling_factor: float = 1.0,
224
- time_spacing: float = 1.0,
225
- time_units: TimeUnits | str | None = None,
226
- levels: int | list[str] = 5,
227
- name: str | None = None,
228
- overwrite: bool = True,
229
- version: str = "0.4",
230
- ) -> None:
231
- """Create an empty OME-Zarr image with the given shape and metadata.
232
-
233
- Args:
234
- store (StoreLike): The store to create the image in.
235
- on_disk_shape (Collection[int]): The shape of the image on disk.
236
- chunks (Collection[int] | None): The chunk shape for the image.
237
- dtype (str): The data type of the image.
238
- on_disk_axis (Collection[str]): The order of the axes on disk.
239
- pixel_sizes (PixelSize | None): The pixel size of the image.
240
- xy_scaling_factor (float): The scaling factor in the x and y dimensions.
241
- z_scaling_factor (float): The scaling factor in the z dimension.
242
- time_spacing (float): The spacing between time points.
243
- time_units (TimeUnits | str | None): The units of the time axis.
244
- levels (int | list[str]): The number of levels in the pyramid.
245
- name (str | None): The name of the image.
246
- overwrite (bool): Whether to overwrite the image if it exists.
247
- version (str): The version of the OME-Zarr format
248
-
249
- """
250
- if len(on_disk_shape) != len(on_disk_axis):
251
- raise ValueError(
252
- "The number of dimensions in the shape must match the number of "
253
- "axes in the on-disk axis."
254
- )
255
-
256
- image_meta = create_label_metadata(
257
- on_disk_axis=on_disk_axis,
258
- pixel_sizes=pixel_sizes,
259
- xy_scaling_factor=xy_scaling_factor,
260
- z_scaling_factor=z_scaling_factor,
261
- time_spacing=time_spacing,
262
- time_units=time_units,
263
- levels=levels,
264
- name=name,
265
- version=version,
266
- )
267
-
268
- # Open the store (if it is not empty, fail)
269
- mode = "w" if overwrite else "w-"
270
- meta_handler = get_ngff_image_meta_handler(
271
- store=store, version=version, meta_mode="label", mode=mode
272
- )
273
- meta_handler.write_meta(image_meta)
274
- group = meta_handler.group
275
- group.attrs["image-label"] = {"version": version, "source": {"image": "../../"}}
276
-
277
- # Create the empty image at each level in the pyramid
278
- _build_empty_pyramid(
279
- group=group,
280
- image_meta=image_meta,
281
- on_disk_shape=on_disk_shape,
282
- chunks=chunks,
283
- dtype=dtype,
284
- on_disk_axis=on_disk_axis,
285
- xy_scaling_factor=xy_scaling_factor,
286
- z_scaling_factor=z_scaling_factor,
287
- )
ngio/io/__init__.py DELETED
@@ -1,19 +0,0 @@
1
- """Collection of helper functions to work with Zarr groups."""
2
-
3
- from zarr import Group
4
-
5
- from ngio.io._zarr import AccessModeLiteral, StoreLike, StoreOrGroup
6
- from ngio.io._zarr_group_utils import (
7
- open_group_wrapper,
8
- )
9
-
10
- # Zarr V3 imports
11
- # from zarr.store.common import StoreLike
12
-
13
- __all__ = [
14
- "Group",
15
- "StoreLike",
16
- "AccessModeLiteral",
17
- "StoreOrGroup",
18
- "open_group_wrapper",
19
- ]