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.
- ngio/__init__.py +1 -2
- ngio/common/__init__.py +2 -51
- ngio/common/_dimensions.py +253 -74
- ngio/common/_pyramid.py +42 -23
- ngio/common/_roi.py +49 -413
- ngio/common/_zoom.py +32 -7
- ngio/experimental/iterators/__init__.py +0 -2
- ngio/experimental/iterators/_abstract_iterator.py +246 -26
- ngio/experimental/iterators/_feature.py +90 -52
- ngio/experimental/iterators/_image_processing.py +24 -63
- ngio/experimental/iterators/_mappers.py +48 -0
- ngio/experimental/iterators/_rois_utils.py +4 -4
- ngio/experimental/iterators/_segmentation.py +38 -85
- ngio/images/_abstract_image.py +192 -95
- ngio/images/_create.py +16 -0
- ngio/images/_create_synt_container.py +10 -0
- ngio/images/_image.py +35 -9
- ngio/images/_label.py +26 -3
- ngio/images/_masked_image.py +45 -61
- ngio/images/_ome_zarr_container.py +33 -0
- ngio/io_pipes/__init__.py +75 -0
- ngio/io_pipes/_io_pipes.py +361 -0
- ngio/io_pipes/_io_pipes_masked.py +488 -0
- ngio/io_pipes/_io_pipes_roi.py +152 -0
- ngio/io_pipes/_io_pipes_types.py +56 -0
- ngio/io_pipes/_match_shape.py +376 -0
- ngio/io_pipes/_ops_axes.py +344 -0
- ngio/io_pipes/_ops_slices.py +446 -0
- ngio/io_pipes/_ops_slices_utils.py +196 -0
- ngio/io_pipes/_ops_transforms.py +104 -0
- ngio/io_pipes/_zoom_transform.py +175 -0
- ngio/ome_zarr_meta/__init__.py +4 -2
- ngio/ome_zarr_meta/ngio_specs/__init__.py +4 -4
- ngio/ome_zarr_meta/ngio_specs/_axes.py +129 -141
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +47 -121
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +30 -22
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +17 -1
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +33 -30
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
- ngio/resources/__init__.py +1 -0
- ngio/resources/resource_model.py +1 -0
- ngio/{common/transforms → transforms}/__init__.py +1 -1
- ngio/transforms/_zoom.py +19 -0
- ngio/utils/_datasets.py +5 -0
- ngio/utils/_zarr_utils.py +5 -1
- {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/METADATA +1 -1
- ngio-0.4.0b1.dist-info/RECORD +85 -0
- ngio/common/_array_io_pipes.py +0 -554
- ngio/common/_array_io_utils.py +0 -508
- ngio/common/transforms/_label.py +0 -12
- ngio/common/transforms/_zoom.py +0 -109
- ngio-0.4.0a3.dist-info/RECORD +0 -76
- {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/WHEEL +0 -0
- {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
|
+
)
|