ngio 0.4.0a3__py3-none-any.whl → 0.4.0b1__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 (54) hide show
  1. ngio/__init__.py +1 -2
  2. ngio/common/__init__.py +2 -51
  3. ngio/common/_dimensions.py +253 -74
  4. ngio/common/_pyramid.py +42 -23
  5. ngio/common/_roi.py +49 -413
  6. ngio/common/_zoom.py +32 -7
  7. ngio/experimental/iterators/__init__.py +0 -2
  8. ngio/experimental/iterators/_abstract_iterator.py +246 -26
  9. ngio/experimental/iterators/_feature.py +90 -52
  10. ngio/experimental/iterators/_image_processing.py +24 -63
  11. ngio/experimental/iterators/_mappers.py +48 -0
  12. ngio/experimental/iterators/_rois_utils.py +4 -4
  13. ngio/experimental/iterators/_segmentation.py +38 -85
  14. ngio/images/_abstract_image.py +192 -95
  15. ngio/images/_create.py +16 -0
  16. ngio/images/_create_synt_container.py +10 -0
  17. ngio/images/_image.py +35 -9
  18. ngio/images/_label.py +26 -3
  19. ngio/images/_masked_image.py +45 -61
  20. ngio/images/_ome_zarr_container.py +33 -0
  21. ngio/io_pipes/__init__.py +75 -0
  22. ngio/io_pipes/_io_pipes.py +361 -0
  23. ngio/io_pipes/_io_pipes_masked.py +488 -0
  24. ngio/io_pipes/_io_pipes_roi.py +152 -0
  25. ngio/io_pipes/_io_pipes_types.py +56 -0
  26. ngio/io_pipes/_match_shape.py +376 -0
  27. ngio/io_pipes/_ops_axes.py +344 -0
  28. ngio/io_pipes/_ops_slices.py +446 -0
  29. ngio/io_pipes/_ops_slices_utils.py +196 -0
  30. ngio/io_pipes/_ops_transforms.py +104 -0
  31. ngio/io_pipes/_zoom_transform.py +175 -0
  32. ngio/ome_zarr_meta/__init__.py +4 -2
  33. ngio/ome_zarr_meta/ngio_specs/__init__.py +4 -4
  34. ngio/ome_zarr_meta/ngio_specs/_axes.py +129 -141
  35. ngio/ome_zarr_meta/ngio_specs/_dataset.py +47 -121
  36. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +30 -22
  37. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +17 -1
  38. ngio/ome_zarr_meta/v04/_v04_spec_utils.py +33 -30
  39. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
  40. ngio/resources/__init__.py +1 -0
  41. ngio/resources/resource_model.py +1 -0
  42. ngio/{common/transforms → transforms}/__init__.py +1 -1
  43. ngio/transforms/_zoom.py +19 -0
  44. ngio/utils/_datasets.py +5 -0
  45. ngio/utils/_zarr_utils.py +5 -1
  46. {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/METADATA +1 -1
  47. ngio-0.4.0b1.dist-info/RECORD +85 -0
  48. ngio/common/_array_io_pipes.py +0 -554
  49. ngio/common/_array_io_utils.py +0 -508
  50. ngio/common/transforms/_label.py +0 -12
  51. ngio/common/transforms/_zoom.py +0 -109
  52. ngio-0.4.0a3.dist-info/RECORD +0 -76
  53. {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/WHEEL +0 -0
  54. {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -4,6 +4,7 @@ import warnings
4
4
  from collections.abc import Sequence
5
5
 
6
6
  import numpy as np
7
+ from zarr.types import DIMENSION_SEPARATOR
7
8
 
8
9
  from ngio.images._create import create_empty_image_container
9
10
  from ngio.images._image import Image, ImagesContainer
@@ -408,6 +409,8 @@ class OmeZarrContainer:
408
409
  name: str | None = None,
409
410
  chunks: Sequence[int] | None = None,
410
411
  dtype: str | None = None,
412
+ dimension_separator: DIMENSION_SEPARATOR | None = None,
413
+ compressor=None,
411
414
  copy_labels: bool = False,
412
415
  copy_tables: bool = False,
413
416
  overwrite: bool = False,
@@ -425,6 +428,11 @@ class OmeZarrContainer:
425
428
  chunks (Sequence[int] | None): The chunk shape of the new image.
426
429
  dtype (str | None): The data type of the new image.
427
430
  name (str | None): The name of the new image.
431
+ dimension_separator (DIMENSION_SEPARATOR | None): The dimension
432
+ separator to use. If None, the dimension separator of the
433
+ reference image will be used.
434
+ compressor: The compressor to use. If None, the compressor of the
435
+ reference image will be used.
428
436
  copy_labels (bool): Whether to copy the labels from the reference image.
429
437
  copy_tables (bool): Whether to copy the tables from the reference image.
430
438
  overwrite (bool): Whether to overwrite an existing image.
@@ -443,6 +451,8 @@ class OmeZarrContainer:
443
451
  name=name,
444
452
  chunks=chunks,
445
453
  dtype=dtype,
454
+ dimension_separator=dimension_separator,
455
+ compressor=compressor,
446
456
  overwrite=overwrite,
447
457
  )
448
458
 
@@ -683,6 +693,8 @@ class OmeZarrContainer:
683
693
  axes_names: Sequence[str] | None = None,
684
694
  chunks: Sequence[int] | None = None,
685
695
  dtype: str = "uint32",
696
+ dimension_separator: DIMENSION_SEPARATOR | None = None,
697
+ compressor=None,
686
698
  overwrite: bool = False,
687
699
  ) -> "Label":
688
700
  """Create an empty OME-Zarr label from a reference image.
@@ -699,6 +711,11 @@ class OmeZarrContainer:
699
711
  For labels, the channel axis is not allowed.
700
712
  chunks (Sequence[int] | None): The chunk shape of the new image.
701
713
  dtype (str): The data type of the new label.
714
+ dimension_separator (DIMENSION_SEPARATOR | None): The dimension
715
+ separator to use. If None, the dimension separator of the
716
+ reference image will be used.
717
+ compressor: The compressor to use. If None, the compressor of the
718
+ reference image will be used.
702
719
  overwrite (bool): Whether to overwrite an existing image.
703
720
 
704
721
  Returns:
@@ -715,6 +732,8 @@ class OmeZarrContainer:
715
732
  axes_names=axes_names,
716
733
  chunks=chunks,
717
734
  dtype=dtype,
735
+ dimension_separator=dimension_separator,
736
+ compressor=compressor,
718
737
  overwrite=overwrite,
719
738
  )
720
739
 
@@ -819,6 +838,8 @@ def create_empty_ome_zarr(
819
838
  name: str | None = None,
820
839
  chunks: Sequence[int] | None = None,
821
840
  dtype: str = "uint16",
841
+ dimension_separator: DIMENSION_SEPARATOR = "/",
842
+ compressor="default",
822
843
  channel_labels: list[str] | None = None,
823
844
  channel_wavelengths: list[str] | None = None,
824
845
  channel_colors: Sequence[str] | None = None,
@@ -851,6 +872,9 @@ def create_empty_ome_zarr(
851
872
  chunks (Sequence[int] | None, optional): The chunk shape. If None the shape
852
873
  is used. Defaults to None.
853
874
  dtype (str, optional): The data type of the image. Defaults to "uint16".
875
+ dimension_separator (DIMENSION_SEPARATOR): The dimension
876
+ separator to use. Defaults to "/".
877
+ compressor: The compressor to use. Defaults to "default".
854
878
  channel_labels (list[str] | None, optional): The labels of the channels.
855
879
  Defaults to None.
856
880
  channel_wavelengths (list[str] | None, optional): The wavelengths of the
@@ -879,6 +903,8 @@ def create_empty_ome_zarr(
879
903
  name=name,
880
904
  chunks=chunks,
881
905
  dtype=dtype,
906
+ dimension_separator=dimension_separator,
907
+ compressor=compressor,
882
908
  overwrite=overwrite,
883
909
  version=version,
884
910
  )
@@ -913,6 +939,8 @@ def create_ome_zarr_from_array(
913
939
  channel_active: Sequence[bool] | None = None,
914
940
  name: str | None = None,
915
941
  chunks: Sequence[int] | None = None,
942
+ dimension_separator: DIMENSION_SEPARATOR = "/",
943
+ compressor: str = "default",
916
944
  overwrite: bool = False,
917
945
  version: NgffVersions = DefaultNgffVersion,
918
946
  ) -> OmeZarrContainer:
@@ -950,6 +978,9 @@ def create_ome_zarr_from_array(
950
978
  Defaults to None.
951
979
  channel_active (Sequence[bool] | None, optional): Whether the channels are
952
980
  active. Defaults to None.
981
+ dimension_separator (DIMENSION_SEPARATOR): The separator to use for
982
+ dimensions. Defaults to "/".
983
+ compressor: The compressor to use. Defaults to "default".
953
984
  overwrite (bool, optional): Whether to overwrite an existing image.
954
985
  Defaults to True.
955
986
  version (str, optional): The version of the OME-Zarr specification.
@@ -971,6 +1002,8 @@ def create_ome_zarr_from_array(
971
1002
  chunks=chunks,
972
1003
  dtype=str(array.dtype),
973
1004
  overwrite=overwrite,
1005
+ dimension_separator=dimension_separator,
1006
+ compressor=compressor,
974
1007
  version=version,
975
1008
  )
976
1009
 
@@ -0,0 +1,75 @@
1
+ """I/O pipes for reading and writing data from zarr to numpy and dask arrays.
2
+
3
+ There are 3 main types of I/O pipes:
4
+ - Standard I/O pipes: NumpyGetter, NumpySetter, DaskGetter, DaskSetter:
5
+ These pipes read and write data from simple integer indexing and slicing.
6
+ - ROI I/O pipes: NumpyRoiGetter, NumpyRoiSetter, DaskRoiGetter, DaskRoiSetter:
7
+ These pipes read and write data from a region of interest (ROI) defined in physical
8
+ coordinates.
9
+ - Masked I/O pipes: NumpyGetterMasked, NumpySetterMasked, DaskGetterMasked,
10
+ DaskSetterMasked: These pipes like the ROI pipes read and write data
11
+ from a region of interest (ROI). However they also load a boolean mask
12
+ from a label zarr array to mask the data being read or written.
13
+
14
+ All the io pipes are structured in the same way.
15
+
16
+ When reading data the order of operations is:
17
+ - Step 1: Slice the zarr array to load only the data needed into memory.
18
+ - Step 2: Apply axes operations to reorder, squeeze or expand the axes.
19
+ To match the user desired axes order.
20
+ - Step 3: Apply any additional transforms to the data.
21
+
22
+ When writing data the order of operations is the reverse.
23
+
24
+ The Transforms must implement the TransformProtocol.
25
+ They should be stateless and only depend on the input array and the slicing
26
+ and axes ops. This allows them to be easily reused between different I/O pipes.
27
+
28
+ """
29
+
30
+ from ngio.io_pipes._io_pipes import (
31
+ DaskGetter,
32
+ DaskSetter,
33
+ DataGetter,
34
+ DataSetter,
35
+ NumpyGetter,
36
+ NumpySetter,
37
+ )
38
+ from ngio.io_pipes._io_pipes_masked import (
39
+ DaskGetterMasked,
40
+ DaskSetterMasked,
41
+ NumpyGetterMasked,
42
+ NumpySetterMasked,
43
+ )
44
+ from ngio.io_pipes._io_pipes_roi import (
45
+ DaskRoiGetter,
46
+ DaskRoiSetter,
47
+ NumpyRoiGetter,
48
+ NumpyRoiSetter,
49
+ )
50
+ from ngio.io_pipes._match_shape import dask_match_shape, numpy_match_shape
51
+ from ngio.io_pipes._ops_slices import SlicingInputType, SlicingOps, SlicingType
52
+ from ngio.io_pipes._ops_transforms import TransformProtocol
53
+
54
+ __all__ = [
55
+ "DaskGetter",
56
+ "DaskGetterMasked",
57
+ "DaskRoiGetter",
58
+ "DaskRoiSetter",
59
+ "DaskSetter",
60
+ "DaskSetterMasked",
61
+ "DataGetter",
62
+ "DataSetter",
63
+ "NumpyGetter",
64
+ "NumpyGetterMasked",
65
+ "NumpyRoiGetter",
66
+ "NumpyRoiSetter",
67
+ "NumpySetter",
68
+ "NumpySetterMasked",
69
+ "SlicingInputType",
70
+ "SlicingOps",
71
+ "SlicingType",
72
+ "TransformProtocol",
73
+ "dask_match_shape",
74
+ "numpy_match_shape",
75
+ ]
@@ -0,0 +1,361 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import Sequence
3
+ from typing import Generic, TypeVar
4
+
5
+ import numpy as np
6
+ import zarr
7
+ from dask.array import Array as DaskArray
8
+
9
+ from ngio.common._dimensions import Dimensions
10
+ from ngio.common._roi import Roi, RoiPixels
11
+ from ngio.io_pipes._ops_axes import (
12
+ AxesOps,
13
+ build_axes_ops,
14
+ get_as_dask_axes_ops,
15
+ get_as_numpy_axes_ops,
16
+ set_as_dask_axes_ops,
17
+ set_as_numpy_axes_ops,
18
+ )
19
+ from ngio.io_pipes._ops_slices import (
20
+ SlicingInputType,
21
+ SlicingOps,
22
+ build_slicing_ops,
23
+ get_slice_as_dask,
24
+ get_slice_as_numpy,
25
+ set_slice_as_dask,
26
+ set_slice_as_numpy,
27
+ )
28
+ from ngio.io_pipes._ops_transforms import (
29
+ TransformProtocol,
30
+ get_as_dask_transform,
31
+ get_as_numpy_transform,
32
+ set_as_dask_transform,
33
+ set_as_numpy_transform,
34
+ )
35
+
36
+
37
+ def setup_io_pipe(
38
+ *,
39
+ dimensions: Dimensions,
40
+ slicing_dict: dict[str, SlicingInputType] | None = None,
41
+ axes_order: Sequence[str] | None = None,
42
+ remove_channel_selection: bool = False,
43
+ ) -> tuple[SlicingOps, AxesOps]:
44
+ """Setup the slicing tuple and axes ops for an IO pipe."""
45
+ slicing_ops = build_slicing_ops(
46
+ dimensions=dimensions,
47
+ slicing_dict=slicing_dict,
48
+ remove_channel_selection=remove_channel_selection,
49
+ )
50
+
51
+ axes_ops = build_axes_ops(
52
+ dimensions=dimensions,
53
+ input_axes=slicing_ops.slice_axes,
54
+ axes_order=axes_order,
55
+ )
56
+ return slicing_ops, axes_ops
57
+
58
+
59
+ ##############################################################
60
+ #
61
+ # "From Disk" Pipes
62
+ #
63
+ ##############################################################
64
+
65
+ T = TypeVar("T")
66
+
67
+
68
+ class DataGetter(ABC, Generic[T]):
69
+ def __init__(
70
+ self,
71
+ zarr_array: zarr.Array,
72
+ slicing_ops: SlicingOps,
73
+ axes_ops: AxesOps,
74
+ transforms: Sequence[TransformProtocol] | None = None,
75
+ roi: Roi | RoiPixels | None = None,
76
+ ) -> None:
77
+ self._zarr_array = zarr_array
78
+ self._slicing_ops = slicing_ops
79
+ self._axes_ops = axes_ops
80
+ self._transforms = transforms
81
+ self._roi = roi
82
+
83
+ def __repr__(self) -> str:
84
+ name = self.__class__.__name__
85
+ return (
86
+ f"{name}(zarr_array={self._zarr_array}, "
87
+ f"slicing_ops={self._slicing_ops}, "
88
+ f"axes_ops={self._axes_ops}, "
89
+ f"transforms={self._transforms})"
90
+ )
91
+
92
+ @property
93
+ def zarr_array(self) -> zarr.Array:
94
+ return self._zarr_array
95
+
96
+ @property
97
+ def slicing_ops(self) -> SlicingOps:
98
+ return self._slicing_ops
99
+
100
+ @property
101
+ def axes_ops(self) -> AxesOps:
102
+ return self._axes_ops
103
+
104
+ @property
105
+ def transforms(self) -> Sequence[TransformProtocol] | None:
106
+ return self._transforms
107
+
108
+ @property
109
+ def roi(self) -> Roi | RoiPixels:
110
+ if self._roi is None:
111
+ name = self.__class__.__name__
112
+ raise ValueError(f"No ROI defined for {name}.")
113
+ return self._roi
114
+
115
+ def __call__(self) -> T:
116
+ return self.get()
117
+
118
+ @abstractmethod
119
+ def get(self) -> T:
120
+ pass
121
+
122
+
123
+ class DataSetter(ABC, Generic[T]):
124
+ def __init__(
125
+ self,
126
+ zarr_array: zarr.Array,
127
+ slicing_ops: SlicingOps,
128
+ axes_ops: AxesOps,
129
+ transforms: Sequence[TransformProtocol] | None = None,
130
+ roi: Roi | RoiPixels | None = None,
131
+ ) -> None:
132
+ self._zarr_array = zarr_array
133
+ self._slicing_ops = slicing_ops
134
+ self._axes_ops = axes_ops
135
+ self._transforms = transforms
136
+ self._roi = roi
137
+
138
+ def __repr__(self) -> str:
139
+ name = self.__class__.__name__
140
+ return (
141
+ f"{name}(zarr_array={self._zarr_array}, "
142
+ f"slicing_ops={self._slicing_ops}, "
143
+ f"axes_ops={self._axes_ops}, "
144
+ f"transforms={self._transforms})"
145
+ )
146
+
147
+ @property
148
+ def zarr_array(self) -> zarr.Array:
149
+ return self._zarr_array
150
+
151
+ @property
152
+ def slicing_ops(self) -> SlicingOps:
153
+ return self._slicing_ops
154
+
155
+ @property
156
+ def axes_ops(self) -> AxesOps:
157
+ return self._axes_ops
158
+
159
+ @property
160
+ def transforms(self) -> Sequence[TransformProtocol] | None:
161
+ return self._transforms
162
+
163
+ @property
164
+ def roi(self) -> Roi | RoiPixels:
165
+ if self._roi is None:
166
+ name = self.__class__.__name__
167
+ raise ValueError(f"No ROI defined for {name}.")
168
+ return self._roi
169
+
170
+ def __call__(self, patch: T) -> None:
171
+ return self.set(patch)
172
+
173
+ @abstractmethod
174
+ def set(self, patch: T) -> None:
175
+ pass
176
+
177
+
178
+ class NumpyGetter(DataGetter[np.ndarray]):
179
+ def __init__(
180
+ self,
181
+ *,
182
+ zarr_array: zarr.Array,
183
+ dimensions: Dimensions,
184
+ axes_order: Sequence[str] | None = None,
185
+ transforms: Sequence[TransformProtocol] | None = None,
186
+ slicing_dict: dict[str, SlicingInputType] | None = None,
187
+ remove_channel_selection: bool = False,
188
+ roi: Roi | RoiPixels | None = None,
189
+ ) -> None:
190
+ """Build a pipe to get a numpy or dask array from a zarr array."""
191
+ slicing_ops, axes_ops = setup_io_pipe(
192
+ dimensions=dimensions,
193
+ slicing_dict=slicing_dict,
194
+ axes_order=axes_order,
195
+ remove_channel_selection=remove_channel_selection,
196
+ )
197
+ super().__init__(
198
+ zarr_array=zarr_array,
199
+ slicing_ops=slicing_ops,
200
+ axes_ops=axes_ops,
201
+ transforms=transforms,
202
+ roi=roi,
203
+ )
204
+
205
+ def get(self) -> np.ndarray:
206
+ """Get a numpy array from the zarr array with ops."""
207
+ array = get_slice_as_numpy(self._zarr_array, slicing_ops=self._slicing_ops)
208
+ array = get_as_numpy_axes_ops(array, axes_ops=self._axes_ops)
209
+ array = get_as_numpy_transform(
210
+ array,
211
+ slicing_ops=self._slicing_ops,
212
+ axes_ops=self._axes_ops,
213
+ transforms=self._transforms,
214
+ )
215
+ return array
216
+
217
+
218
+ class DaskGetter(DataGetter[DaskArray]):
219
+ def __init__(
220
+ self,
221
+ *,
222
+ zarr_array: zarr.Array,
223
+ dimensions: Dimensions,
224
+ axes_order: Sequence[str] | None = None,
225
+ transforms: Sequence[TransformProtocol] | None = None,
226
+ slicing_dict: dict[str, SlicingInputType] | None = None,
227
+ remove_channel_selection: bool = False,
228
+ roi: Roi | RoiPixels | None = None,
229
+ ) -> None:
230
+ """Build a pipe to get a numpy or dask array from a zarr array."""
231
+ slicing_ops, axes_ops = setup_io_pipe(
232
+ dimensions=dimensions,
233
+ slicing_dict=slicing_dict,
234
+ axes_order=axes_order,
235
+ remove_channel_selection=remove_channel_selection,
236
+ )
237
+ super().__init__(
238
+ zarr_array=zarr_array,
239
+ slicing_ops=slicing_ops,
240
+ axes_ops=axes_ops,
241
+ transforms=transforms,
242
+ roi=roi,
243
+ )
244
+
245
+ def get(self) -> DaskArray:
246
+ """Get a dask array from the zarr array with ops.
247
+
248
+ The order of operations is:
249
+ * get slice will load the data from the zarr array
250
+ * get axes ops will reorder, squeeze or expand the axes
251
+ * get transform will apply any additional transforms
252
+
253
+ """
254
+ array = get_slice_as_dask(self._zarr_array, slicing_ops=self._slicing_ops)
255
+ array = get_as_dask_axes_ops(array, axes_ops=self._axes_ops)
256
+ array = get_as_dask_transform(
257
+ array,
258
+ slicing_ops=self._slicing_ops,
259
+ axes_ops=self._axes_ops,
260
+ transforms=self._transforms,
261
+ )
262
+ return array
263
+
264
+
265
+ ##############################################################
266
+ #
267
+ # "To Disk" Pipes
268
+ #
269
+ ##############################################################
270
+
271
+
272
+ class NumpySetter(DataSetter[np.ndarray]):
273
+ def __init__(
274
+ self,
275
+ *,
276
+ zarr_array: zarr.Array,
277
+ dimensions: Dimensions,
278
+ axes_order: Sequence[str] | None = None,
279
+ transforms: Sequence[TransformProtocol] | None = None,
280
+ slicing_dict: dict[str, SlicingInputType] | None = None,
281
+ remove_channel_selection: bool = False,
282
+ roi: Roi | RoiPixels | None = None,
283
+ ) -> None:
284
+ """Build a pipe to get a numpy or dask array from a zarr array."""
285
+ slicing_ops, axes_ops = setup_io_pipe(
286
+ dimensions=dimensions,
287
+ slicing_dict=slicing_dict,
288
+ axes_order=axes_order,
289
+ remove_channel_selection=remove_channel_selection,
290
+ )
291
+ super().__init__(
292
+ zarr_array=zarr_array,
293
+ slicing_ops=slicing_ops,
294
+ axes_ops=axes_ops,
295
+ transforms=transforms,
296
+ roi=roi,
297
+ )
298
+
299
+ def set(self, patch: np.ndarray) -> None:
300
+ """Get a numpy array from the zarr array with ops."""
301
+ patch = set_as_numpy_transform(
302
+ array=patch,
303
+ slicing_ops=self._slicing_ops,
304
+ axes_ops=self._axes_ops,
305
+ transforms=self._transforms,
306
+ )
307
+ patch = set_as_numpy_axes_ops(
308
+ array=patch,
309
+ axes_ops=self._axes_ops,
310
+ )
311
+ set_slice_as_numpy(
312
+ zarr_array=self._zarr_array,
313
+ patch=patch,
314
+ slicing_ops=self._slicing_ops,
315
+ )
316
+
317
+
318
+ class DaskSetter(DataSetter[DaskArray]):
319
+ def __init__(
320
+ self,
321
+ *,
322
+ zarr_array: zarr.Array,
323
+ dimensions: Dimensions,
324
+ axes_order: Sequence[str] | None = None,
325
+ transforms: Sequence[TransformProtocol] | None = None,
326
+ slicing_dict: dict[str, SlicingInputType] | None = None,
327
+ remove_channel_selection: bool = False,
328
+ roi: Roi | RoiPixels | None = None,
329
+ ) -> None:
330
+ """Build a pipe to get a numpy or dask array from a zarr array."""
331
+ slicing_ops, axes_ops = setup_io_pipe(
332
+ dimensions=dimensions,
333
+ slicing_dict=slicing_dict,
334
+ axes_order=axes_order,
335
+ remove_channel_selection=remove_channel_selection,
336
+ )
337
+ super().__init__(
338
+ zarr_array=zarr_array,
339
+ slicing_ops=slicing_ops,
340
+ axes_ops=axes_ops,
341
+ transforms=transforms,
342
+ roi=roi,
343
+ )
344
+
345
+ def set(self, patch: DaskArray) -> None:
346
+ """Get a dask array from the zarr array with ops."""
347
+ patch = set_as_dask_transform(
348
+ array=patch,
349
+ slicing_ops=self._slicing_ops,
350
+ axes_ops=self._axes_ops,
351
+ transforms=self._transforms,
352
+ )
353
+ patch = set_as_dask_axes_ops(
354
+ array=patch,
355
+ axes_ops=self._axes_ops,
356
+ )
357
+ set_slice_as_dask(
358
+ zarr_array=self._zarr_array,
359
+ patch=patch,
360
+ slicing_ops=self._slicing_ops,
361
+ )