ngio 0.3.0a1__py3-none-any.whl → 0.3.2__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/common/_array_pipe.py +50 -27
- ngio/common/_roi.py +2 -0
- ngio/common/_table_ops.py +1 -1
- ngio/hcs/__init__.py +1 -1
- ngio/hcs/{plate.py → _plate.py} +25 -9
- ngio/images/__init__.py +3 -3
- ngio/images/{image.py → _image.py} +26 -21
- ngio/images/{label.py → _label.py} +6 -4
- ngio/images/{masked_image.py → _masked_image.py} +2 -2
- ngio/images/{ome_zarr_container.py → _ome_zarr_container.py} +58 -22
- ngio/ome_zarr_meta/ngio_specs/_axes.py +4 -7
- ngio/ome_zarr_meta/ngio_specs/_channels.py +41 -29
- ngio/tables/__init__.py +8 -6
- ngio/tables/{abstract_table.py → _abstract_table.py} +2 -1
- ngio/tables/{tables_container.py → _tables_container.py} +33 -19
- ngio/tables/backends/__init__.py +2 -0
- ngio/tables/backends/_abstract_backend.py +1 -1
- ngio/tables/backends/_table_backends.py +35 -12
- ngio/tables/v1/_condition_table.py +1 -1
- ngio/tables/v1/_feature_table.py +2 -2
- ngio/tables/v1/_generic_table.py +1 -1
- ngio/tables/v1/_roi_table.py +13 -3
- ngio/utils/_fractal_fsspec_store.py +1 -1
- {ngio-0.3.0a1.dist-info → ngio-0.3.2.dist-info}/METADATA +68 -35
- {ngio-0.3.0a1.dist-info → ngio-0.3.2.dist-info}/RECORD +29 -29
- /ngio/images/{abstract_image.py → _abstract_image.py} +0 -0
- /ngio/images/{create.py → _create.py} +0 -0
- {ngio-0.3.0a1.dist-info → ngio-0.3.2.dist-info}/WHEEL +0 -0
- {ngio-0.3.0a1.dist-info → ngio-0.3.2.dist-info}/licenses/LICENSE +0 -0
ngio/common/_array_pipe.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from collections.abc import Collection, Iterable
|
|
2
2
|
from typing import Literal
|
|
3
3
|
|
|
4
|
-
import dask
|
|
5
|
-
import dask.delayed
|
|
4
|
+
import dask.array as da
|
|
6
5
|
import numpy as np
|
|
7
6
|
import zarr
|
|
7
|
+
from dask.array import Array as DaskArray
|
|
8
|
+
from dask.delayed import Delayed, delayed
|
|
8
9
|
|
|
9
10
|
from ngio.common._axes_transforms import transform_dask_array, transform_numpy_array
|
|
10
11
|
from ngio.common._common_types import ArrayLike
|
|
@@ -55,26 +56,26 @@ def _numpy_get_pipe(
|
|
|
55
56
|
slices: SliceTransform,
|
|
56
57
|
transformations: tuple[AxesTransformation, ...],
|
|
57
58
|
) -> np.ndarray:
|
|
58
|
-
|
|
59
|
-
return transform_numpy_array(
|
|
59
|
+
_array = numpy_get_slice(array, slices)
|
|
60
|
+
return transform_numpy_array(_array, transformations)
|
|
60
61
|
|
|
61
62
|
|
|
62
63
|
def _delayed_numpy_get_pipe(
|
|
63
64
|
array: zarr.Array,
|
|
64
65
|
slices: SliceTransform,
|
|
65
66
|
transformations: tuple[AxesTransformation, ...],
|
|
66
|
-
) ->
|
|
67
|
-
|
|
68
|
-
return
|
|
67
|
+
) -> Delayed:
|
|
68
|
+
_array = delayed(numpy_get_slice)(array, slices)
|
|
69
|
+
return delayed(transform_numpy_array)(_array, transformations)
|
|
69
70
|
|
|
70
71
|
|
|
71
72
|
def _dask_get_pipe(
|
|
72
73
|
array: zarr.Array,
|
|
73
74
|
slices: SliceTransform,
|
|
74
75
|
transformations: tuple[AxesTransformation, ...],
|
|
75
|
-
) ->
|
|
76
|
-
|
|
77
|
-
return transform_dask_array(
|
|
76
|
+
) -> DaskArray:
|
|
77
|
+
_array = dask_get_slice(array, slices)
|
|
78
|
+
return transform_dask_array(_array, transformations)
|
|
78
79
|
|
|
79
80
|
|
|
80
81
|
def _numpy_set_pipe(
|
|
@@ -89,22 +90,22 @@ def _numpy_set_pipe(
|
|
|
89
90
|
|
|
90
91
|
def _dask_set_pipe(
|
|
91
92
|
array: zarr.Array,
|
|
92
|
-
patch:
|
|
93
|
+
patch: DaskArray,
|
|
93
94
|
slices: SliceTransform,
|
|
94
95
|
transformations: tuple[AxesTransformation, ...],
|
|
95
96
|
) -> None:
|
|
96
|
-
|
|
97
|
-
dask_set_slice(array,
|
|
97
|
+
_patch = transform_dask_array(patch, transformations)
|
|
98
|
+
dask_set_slice(array, _patch, slices)
|
|
98
99
|
|
|
99
100
|
|
|
100
101
|
def _delayed_numpy_set_pipe(
|
|
101
102
|
array: zarr.Array,
|
|
102
|
-
patch: np.ndarray,
|
|
103
|
+
patch: np.ndarray | Delayed,
|
|
103
104
|
slices: SliceTransform,
|
|
104
105
|
transformations: tuple[AxesTransformation, ...],
|
|
105
|
-
) ->
|
|
106
|
-
|
|
107
|
-
return
|
|
106
|
+
) -> Delayed:
|
|
107
|
+
_patch = delayed(transform_numpy_array)(patch, transformations)
|
|
108
|
+
return delayed(numpy_set_slice)(array, _patch, slices)
|
|
108
109
|
|
|
109
110
|
|
|
110
111
|
def get_pipe(
|
|
@@ -144,7 +145,7 @@ def set_pipe(
|
|
|
144
145
|
slices, transformations = _compute_to_disk_transforms(
|
|
145
146
|
dimensions=dimensions, axes_order=axes_order, **slice_kwargs
|
|
146
147
|
)
|
|
147
|
-
if isinstance(patch,
|
|
148
|
+
if isinstance(patch, DaskArray):
|
|
148
149
|
_dask_set_pipe(
|
|
149
150
|
array=array, patch=patch, slices=slices, transformations=transformations
|
|
150
151
|
)
|
|
@@ -152,7 +153,7 @@ def set_pipe(
|
|
|
152
153
|
_numpy_set_pipe(
|
|
153
154
|
array=array, patch=patch, slices=slices, transformations=transformations
|
|
154
155
|
)
|
|
155
|
-
elif isinstance(patch,
|
|
156
|
+
elif isinstance(patch, Delayed):
|
|
156
157
|
_delayed_numpy_set_pipe(
|
|
157
158
|
array=array, patch=patch, slices=slices, transformations=transformations
|
|
158
159
|
)
|
|
@@ -193,12 +194,15 @@ def _mask_pipe_common(
|
|
|
193
194
|
**slice_kwargs,
|
|
194
195
|
)
|
|
195
196
|
|
|
196
|
-
if isinstance(array_patch, np.ndarray):
|
|
197
|
+
if isinstance(array_patch, np.ndarray) and isinstance(label_patch, np.ndarray):
|
|
197
198
|
label_patch = np.broadcast_to(label_patch, array_patch.shape)
|
|
198
|
-
elif isinstance(array_patch,
|
|
199
|
-
label_patch =
|
|
199
|
+
elif isinstance(array_patch, DaskArray) and isinstance(label_patch, DaskArray):
|
|
200
|
+
label_patch = da.broadcast_to(label_patch, array_patch.shape)
|
|
200
201
|
else:
|
|
201
|
-
raise NgioValueError(
|
|
202
|
+
raise NgioValueError(
|
|
203
|
+
"Incompatible types for array and label: "
|
|
204
|
+
f"{type(array_patch)} and {type(label_patch)}"
|
|
205
|
+
)
|
|
202
206
|
|
|
203
207
|
mask = label_patch == label
|
|
204
208
|
return array_patch, mask
|
|
@@ -225,7 +229,14 @@ def get_masked_pipe(
|
|
|
225
229
|
mode=mode,
|
|
226
230
|
**slice_kwargs,
|
|
227
231
|
)
|
|
228
|
-
array_patch
|
|
232
|
+
if isinstance(array_patch, np.ndarray):
|
|
233
|
+
array_patch[~mask] = 0
|
|
234
|
+
elif isinstance(array_patch, DaskArray):
|
|
235
|
+
array_patch = da.where(mask, array_patch, 0)
|
|
236
|
+
else:
|
|
237
|
+
raise NgioValueError(
|
|
238
|
+
"Mode not yet supported for masked array. Expected a numpy or dask array."
|
|
239
|
+
)
|
|
229
240
|
return array_patch
|
|
230
241
|
|
|
231
242
|
|
|
@@ -240,7 +251,7 @@ def set_masked_pipe(
|
|
|
240
251
|
axes_order: Collection[str] | None = None,
|
|
241
252
|
**slice_kwargs: slice | int | Iterable[int],
|
|
242
253
|
):
|
|
243
|
-
if isinstance(patch,
|
|
254
|
+
if isinstance(patch, DaskArray):
|
|
244
255
|
mode = "dask"
|
|
245
256
|
elif isinstance(patch, np.ndarray):
|
|
246
257
|
mode = "numpy"
|
|
@@ -259,7 +270,19 @@ def set_masked_pipe(
|
|
|
259
270
|
mode=mode,
|
|
260
271
|
**slice_kwargs,
|
|
261
272
|
)
|
|
262
|
-
|
|
273
|
+
if isinstance(patch, np.ndarray):
|
|
274
|
+
assert isinstance(array_patch, np.ndarray)
|
|
275
|
+
_patch = np.where(mask, patch, array_patch)
|
|
276
|
+
elif isinstance(patch, DaskArray):
|
|
277
|
+
_patch = da.where(mask, patch, array_patch)
|
|
278
|
+
else:
|
|
279
|
+
raise NgioValueError(
|
|
280
|
+
"Mode not yet supported for masked array. Expected a numpy or dask array."
|
|
281
|
+
)
|
|
263
282
|
set_pipe(
|
|
264
|
-
array,
|
|
283
|
+
array,
|
|
284
|
+
_patch,
|
|
285
|
+
dimensions=dimensions_array,
|
|
286
|
+
axes_order=axes_order,
|
|
287
|
+
**slice_kwargs,
|
|
265
288
|
)
|
ngio/common/_roi.py
CHANGED
|
@@ -57,6 +57,7 @@ class Roi(BaseModel):
|
|
|
57
57
|
x_length=_to_raster(self.x_length, pixel_size.x, dim_x),
|
|
58
58
|
y_length=_to_raster(self.y_length, pixel_size.y, dim_y),
|
|
59
59
|
z_length=_to_raster(self.z_length, pixel_size.z, dim_z),
|
|
60
|
+
**self.model_extra,
|
|
60
61
|
)
|
|
61
62
|
|
|
62
63
|
def zoom(self, zoom_factor: float = 1) -> "Roi":
|
|
@@ -94,6 +95,7 @@ class RoiPixels(BaseModel):
|
|
|
94
95
|
y_length=_to_world(self.y_length, pixel_size.y),
|
|
95
96
|
z_length=_to_world(self.z_length, pixel_size.z),
|
|
96
97
|
unit=pixel_size.space_unit,
|
|
98
|
+
**self.model_extra,
|
|
97
99
|
)
|
|
98
100
|
|
|
99
101
|
def to_slices(self) -> dict[str, slice]:
|
ngio/common/_table_ops.py
CHANGED
ngio/hcs/__init__.py
CHANGED
ngio/hcs/{plate.py → _plate.py}
RENAMED
|
@@ -27,6 +27,7 @@ from ngio.ome_zarr_meta import (
|
|
|
27
27
|
)
|
|
28
28
|
from ngio.tables import (
|
|
29
29
|
ConditionTable,
|
|
30
|
+
DefaultTableBackend,
|
|
30
31
|
FeatureTable,
|
|
31
32
|
GenericRoiTable,
|
|
32
33
|
MaskingRoiTable,
|
|
@@ -39,7 +40,6 @@ from ngio.tables import (
|
|
|
39
40
|
)
|
|
40
41
|
from ngio.utils import (
|
|
41
42
|
AccessModeLiteral,
|
|
42
|
-
NgioValidationError,
|
|
43
43
|
NgioValueError,
|
|
44
44
|
StoreOrGroup,
|
|
45
45
|
ZarrGroupHandler,
|
|
@@ -805,22 +805,38 @@ class OmeZarrPlate:
|
|
|
805
805
|
parallel_safe=parallel_safe,
|
|
806
806
|
)
|
|
807
807
|
|
|
808
|
-
|
|
809
|
-
def tables_container(self) -> TablesContainer:
|
|
808
|
+
def _get_tables_container(self) -> TablesContainer | None:
|
|
810
809
|
"""Return the tables container."""
|
|
811
810
|
if self._tables_container is None:
|
|
812
|
-
|
|
813
|
-
if
|
|
814
|
-
|
|
811
|
+
_tables_container = _default_table_container(self._group_handler)
|
|
812
|
+
if _tables_container is None:
|
|
813
|
+
return None
|
|
814
|
+
self._tables_container = _tables_container
|
|
815
815
|
return self._tables_container
|
|
816
816
|
|
|
817
|
-
|
|
817
|
+
@property
|
|
818
|
+
def tables_container(self) -> TablesContainer:
|
|
819
|
+
"""Return the tables container."""
|
|
820
|
+
_table_container = self._get_tables_container()
|
|
821
|
+
if _table_container is None:
|
|
822
|
+
raise NgioValueError(
|
|
823
|
+
"No tables container found. Please add a tables container to the plate."
|
|
824
|
+
)
|
|
825
|
+
return _table_container
|
|
826
|
+
|
|
827
|
+
def list_tables(self, filter_types: TypedTable | str | None = None) -> list[str]:
|
|
818
828
|
"""List all tables in the image."""
|
|
819
829
|
return self.tables_container.list(filter_types=filter_types)
|
|
820
830
|
|
|
821
831
|
def list_roi_tables(self) -> list[str]:
|
|
822
832
|
"""List all ROI tables in the image."""
|
|
823
|
-
|
|
833
|
+
masking_roi = self.tables_container.list(
|
|
834
|
+
filter_types="masking_roi_table",
|
|
835
|
+
)
|
|
836
|
+
roi = self.tables_container.list(
|
|
837
|
+
filter_types="roi_table",
|
|
838
|
+
)
|
|
839
|
+
return masking_roi + roi
|
|
824
840
|
|
|
825
841
|
def get_roi_table(self, name: str) -> RoiTable:
|
|
826
842
|
"""Get a ROI table from the image.
|
|
@@ -929,7 +945,7 @@ class OmeZarrPlate:
|
|
|
929
945
|
self,
|
|
930
946
|
name: str,
|
|
931
947
|
table: Table,
|
|
932
|
-
backend: TableBackend =
|
|
948
|
+
backend: TableBackend = DefaultTableBackend,
|
|
933
949
|
overwrite: bool = False,
|
|
934
950
|
) -> None:
|
|
935
951
|
"""Add a table to the image."""
|
ngio/images/__init__.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""OME-Zarr object models."""
|
|
2
2
|
|
|
3
|
-
from ngio.images.
|
|
4
|
-
from ngio.images.
|
|
5
|
-
from ngio.images.
|
|
3
|
+
from ngio.images._image import Image, ImagesContainer
|
|
4
|
+
from ngio.images._label import Label, LabelsContainer
|
|
5
|
+
from ngio.images._ome_zarr_container import (
|
|
6
6
|
OmeZarrContainer,
|
|
7
7
|
create_empty_ome_zarr,
|
|
8
8
|
create_ome_zarr_from_array,
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
from collections.abc import Collection
|
|
4
4
|
from typing import Literal
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import dask.array as da
|
|
7
7
|
|
|
8
8
|
from ngio.common import Dimensions
|
|
9
|
-
from ngio.images.
|
|
10
|
-
from ngio.images.
|
|
9
|
+
from ngio.images._abstract_image import AbstractImage, consolidate_image
|
|
10
|
+
from ngio.images._create import create_empty_image_container
|
|
11
11
|
from ngio.ome_zarr_meta import (
|
|
12
12
|
ImageMetaHandler,
|
|
13
13
|
NgioImageMeta,
|
|
@@ -152,31 +152,33 @@ class ImagesContainer:
|
|
|
152
152
|
|
|
153
153
|
def set_channel_meta(
|
|
154
154
|
self,
|
|
155
|
-
labels: Collection[str] | int | None = None,
|
|
156
|
-
wavelength_id: Collection[str] | None = None,
|
|
157
|
-
start: Collection[float] | None = None,
|
|
158
|
-
end: Collection[float] | None = None,
|
|
155
|
+
labels: Collection[str | None] | int | None = None,
|
|
156
|
+
wavelength_id: Collection[str | None] | None = None,
|
|
157
|
+
start: Collection[float | None] | None = None,
|
|
158
|
+
end: Collection[float | None] | None = None,
|
|
159
159
|
percentiles: tuple[float, float] | None = None,
|
|
160
|
-
colors: Collection[str] | None = None,
|
|
161
|
-
active: Collection[bool] | None = None,
|
|
160
|
+
colors: Collection[str | None] | None = None,
|
|
161
|
+
active: Collection[bool | None] | None = None,
|
|
162
162
|
**omero_kwargs: dict,
|
|
163
163
|
) -> None:
|
|
164
164
|
"""Create a ChannelsMeta object with the default unit.
|
|
165
165
|
|
|
166
166
|
Args:
|
|
167
|
-
labels(Collection[str] | int): The list of channels names
|
|
168
|
-
If an integer is provided, the channels will
|
|
169
|
-
|
|
167
|
+
labels(Collection[str | None] | int): The list of channels names
|
|
168
|
+
in the image. If an integer is provided, the channels will
|
|
169
|
+
be named "channel_i".
|
|
170
|
+
wavelength_id(Collection[str | None]): The wavelength ID of the channel.
|
|
170
171
|
If None, the wavelength ID will be the same as the channel name.
|
|
171
|
-
start(Collection[float
|
|
172
|
+
start(Collection[float | None]): The start value for each channel.
|
|
172
173
|
If None, the start value will be computed from the image.
|
|
173
|
-
end(Collection[float
|
|
174
|
+
end(Collection[float | None]): The end value for each channel.
|
|
174
175
|
If None, the end value will be computed from the image.
|
|
175
|
-
percentiles(tuple[float, float] | None): The start and end
|
|
176
|
-
for each channel. If None, the percentiles will
|
|
177
|
-
|
|
176
|
+
percentiles(tuple[float, float] | None): The start and end
|
|
177
|
+
percentiles for each channel. If None, the percentiles will
|
|
178
|
+
not be computed.
|
|
179
|
+
colors(Collection[str | None]): The list of colors for the
|
|
178
180
|
channels. If None, the colors will be random.
|
|
179
|
-
active (Collection[bool
|
|
181
|
+
active (Collection[bool | None]): Whether the channel should
|
|
180
182
|
be shown by default.
|
|
181
183
|
omero_kwargs(dict): Extra fields to store in the omero attributes.
|
|
182
184
|
"""
|
|
@@ -376,9 +378,12 @@ def compute_image_percentile(
|
|
|
376
378
|
starts, ends = [], []
|
|
377
379
|
for c in range(image.num_channels):
|
|
378
380
|
if image.num_channels == 1:
|
|
379
|
-
data = image.get_array(mode="dask")
|
|
381
|
+
data = image.get_array(mode="dask")
|
|
380
382
|
else:
|
|
381
|
-
data = image.get_array(c=c, mode="dask")
|
|
383
|
+
data = image.get_array(c=c, mode="dask")
|
|
384
|
+
|
|
385
|
+
assert isinstance(data, da.Array), "Data must be a Dask array."
|
|
386
|
+
data = da.ravel(data)
|
|
382
387
|
# remove all the zeros
|
|
383
388
|
mask = data > 1e-16
|
|
384
389
|
data = data[mask]
|
|
@@ -391,7 +396,7 @@ def compute_image_percentile(
|
|
|
391
396
|
# compute the percentiles
|
|
392
397
|
_s_perc, _e_perc = da.percentile(
|
|
393
398
|
data, [start_percentile, end_percentile], method="nearest"
|
|
394
|
-
).compute()
|
|
399
|
+
).compute() # type: ignore
|
|
395
400
|
|
|
396
401
|
starts.append(float(_s_perc))
|
|
397
402
|
ends.append(float(_e_perc))
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
from collections.abc import Collection
|
|
4
4
|
from typing import Literal
|
|
5
5
|
|
|
6
|
+
import dask.array as da
|
|
7
|
+
|
|
6
8
|
from ngio.common import compute_masking_roi
|
|
7
|
-
from ngio.images.
|
|
8
|
-
from ngio.images.
|
|
9
|
-
from ngio.images.
|
|
9
|
+
from ngio.images._abstract_image import AbstractImage, consolidate_image
|
|
10
|
+
from ngio.images._create import create_empty_label_container
|
|
11
|
+
from ngio.images._image import Image
|
|
10
12
|
from ngio.ome_zarr_meta import (
|
|
11
13
|
LabelMetaHandler,
|
|
12
14
|
NgioLabelMeta,
|
|
@@ -309,6 +311,6 @@ def build_masking_roi_table(label: Label) -> MaskingRoiTable:
|
|
|
309
311
|
raise NgioValueError("Time series labels are not supported.")
|
|
310
312
|
|
|
311
313
|
array = label.get_array(axes_order=["z", "y", "x"], mode="dask")
|
|
312
|
-
|
|
314
|
+
assert isinstance(array, da.Array), "Array must be a Dask array."
|
|
313
315
|
rois = compute_masking_roi(array, label.pixel_size)
|
|
314
316
|
return MaskingRoiTable(rois, reference_label=label.meta.name)
|
|
@@ -4,8 +4,8 @@ from collections.abc import Collection, Iterable
|
|
|
4
4
|
from typing import Literal
|
|
5
5
|
|
|
6
6
|
from ngio.common import ArrayLike, get_masked_pipe, roi_to_slice_kwargs, set_masked_pipe
|
|
7
|
-
from ngio.images.
|
|
8
|
-
from ngio.images.
|
|
7
|
+
from ngio.images._image import Image
|
|
8
|
+
from ngio.images._label import Label
|
|
9
9
|
from ngio.ome_zarr_meta import ImageMetaHandler, LabelMetaHandler
|
|
10
10
|
from ngio.tables import MaskingRoiTable
|
|
11
11
|
from ngio.utils import (
|
|
@@ -5,10 +5,10 @@ from collections.abc import Collection
|
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
|
-
from ngio.images.
|
|
9
|
-
from ngio.images.
|
|
10
|
-
from ngio.images.
|
|
11
|
-
from ngio.images.
|
|
8
|
+
from ngio.images._create import create_empty_image_container
|
|
9
|
+
from ngio.images._image import Image, ImagesContainer
|
|
10
|
+
from ngio.images._label import Label, LabelsContainer
|
|
11
|
+
from ngio.images._masked_image import MaskedImage, MaskedLabel
|
|
12
12
|
from ngio.ome_zarr_meta import (
|
|
13
13
|
NgioImageMeta,
|
|
14
14
|
PixelSize,
|
|
@@ -23,6 +23,7 @@ from ngio.ome_zarr_meta.ngio_specs import (
|
|
|
23
23
|
)
|
|
24
24
|
from ngio.tables import (
|
|
25
25
|
ConditionTable,
|
|
26
|
+
DefaultTableBackend,
|
|
26
27
|
FeatureTable,
|
|
27
28
|
GenericRoiTable,
|
|
28
29
|
MaskingRoiTable,
|
|
@@ -68,7 +69,7 @@ class OmeZarrContainer:
|
|
|
68
69
|
group_handler: ZarrGroupHandler,
|
|
69
70
|
table_container: TablesContainer | None = None,
|
|
70
71
|
label_container: LabelsContainer | None = None,
|
|
71
|
-
|
|
72
|
+
validate_paths: bool = False,
|
|
72
73
|
) -> None:
|
|
73
74
|
"""Initialize the OmeZarrContainer."""
|
|
74
75
|
self._group_handler = group_handler
|
|
@@ -77,6 +78,10 @@ class OmeZarrContainer:
|
|
|
77
78
|
self._labels_container = label_container
|
|
78
79
|
self._tables_container = table_container
|
|
79
80
|
|
|
81
|
+
if validate_paths:
|
|
82
|
+
for level_path in self._images_container.levels_paths:
|
|
83
|
+
self.get_image(path=level_path)
|
|
84
|
+
|
|
80
85
|
def __repr__(self) -> str:
|
|
81
86
|
"""Return a string representation of the image."""
|
|
82
87
|
num_labels = len(self.list_labels())
|
|
@@ -99,24 +104,40 @@ class OmeZarrContainer:
|
|
|
99
104
|
"""Return the image container."""
|
|
100
105
|
return self._images_container
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
def labels_container(self) -> LabelsContainer:
|
|
107
|
+
def _get_labels_container(self) -> LabelsContainer | None:
|
|
104
108
|
"""Return the labels container."""
|
|
105
109
|
if self._labels_container is None:
|
|
106
|
-
|
|
107
|
-
if
|
|
108
|
-
|
|
110
|
+
_labels_container = _default_label_container(self._group_handler)
|
|
111
|
+
if _labels_container is None:
|
|
112
|
+
return None
|
|
113
|
+
self._labels_container = _labels_container
|
|
109
114
|
return self._labels_container
|
|
110
115
|
|
|
111
116
|
@property
|
|
112
|
-
def
|
|
117
|
+
def labels_container(self) -> LabelsContainer:
|
|
118
|
+
"""Return the labels container."""
|
|
119
|
+
_labels_container = self._get_labels_container()
|
|
120
|
+
if _labels_container is None:
|
|
121
|
+
raise NgioValidationError("No labels found in the image.")
|
|
122
|
+
return _labels_container
|
|
123
|
+
|
|
124
|
+
def _get_tables_container(self) -> TablesContainer | None:
|
|
113
125
|
"""Return the tables container."""
|
|
114
126
|
if self._tables_container is None:
|
|
115
|
-
|
|
116
|
-
if
|
|
117
|
-
|
|
127
|
+
_tables_container = _default_table_container(self._group_handler)
|
|
128
|
+
if _tables_container is None:
|
|
129
|
+
return None
|
|
130
|
+
self._tables_container = _tables_container
|
|
118
131
|
return self._tables_container
|
|
119
132
|
|
|
133
|
+
@property
|
|
134
|
+
def tables_container(self) -> TablesContainer:
|
|
135
|
+
"""Return the tables container."""
|
|
136
|
+
_tables_container = self._get_tables_container()
|
|
137
|
+
if _tables_container is None:
|
|
138
|
+
raise NgioValidationError("No tables found in the image.")
|
|
139
|
+
return _tables_container
|
|
140
|
+
|
|
120
141
|
@property
|
|
121
142
|
def image_meta(self) -> NgioImageMeta:
|
|
122
143
|
"""Return the image metadata."""
|
|
@@ -332,7 +353,7 @@ class OmeZarrContainer:
|
|
|
332
353
|
|
|
333
354
|
new_ome_zarr = OmeZarrContainer(
|
|
334
355
|
group_handler=handler,
|
|
335
|
-
|
|
356
|
+
validate_paths=False,
|
|
336
357
|
)
|
|
337
358
|
|
|
338
359
|
if copy_labels:
|
|
@@ -346,13 +367,25 @@ class OmeZarrContainer:
|
|
|
346
367
|
)
|
|
347
368
|
return new_ome_zarr
|
|
348
369
|
|
|
349
|
-
def list_tables(self, filter_types: str | None = None) -> list[str]:
|
|
370
|
+
def list_tables(self, filter_types: TypedTable | str | None = None) -> list[str]:
|
|
350
371
|
"""List all tables in the image."""
|
|
351
|
-
|
|
372
|
+
table_container = self._get_tables_container()
|
|
373
|
+
if table_container is None:
|
|
374
|
+
return []
|
|
375
|
+
|
|
376
|
+
return table_container.list(
|
|
377
|
+
filter_types=filter_types,
|
|
378
|
+
)
|
|
352
379
|
|
|
353
380
|
def list_roi_tables(self) -> list[str]:
|
|
354
381
|
"""List all ROI tables in the image."""
|
|
355
|
-
|
|
382
|
+
masking_roi = self.tables_container.list(
|
|
383
|
+
filter_types="masking_roi_table",
|
|
384
|
+
)
|
|
385
|
+
roi = self.tables_container.list(
|
|
386
|
+
filter_types="roi_table",
|
|
387
|
+
)
|
|
388
|
+
return masking_roi + roi
|
|
356
389
|
|
|
357
390
|
def get_roi_table(self, name: str) -> RoiTable:
|
|
358
391
|
"""Get a ROI table from the image.
|
|
@@ -469,7 +502,7 @@ class OmeZarrContainer:
|
|
|
469
502
|
self,
|
|
470
503
|
name: str,
|
|
471
504
|
table: Table,
|
|
472
|
-
backend: TableBackend =
|
|
505
|
+
backend: TableBackend = DefaultTableBackend,
|
|
473
506
|
overwrite: bool = False,
|
|
474
507
|
) -> None:
|
|
475
508
|
"""Add a table to the image."""
|
|
@@ -479,7 +512,10 @@ class OmeZarrContainer:
|
|
|
479
512
|
|
|
480
513
|
def list_labels(self) -> list[str]:
|
|
481
514
|
"""List all labels in the image."""
|
|
482
|
-
|
|
515
|
+
label_container = self._get_labels_container()
|
|
516
|
+
if label_container is None:
|
|
517
|
+
return []
|
|
518
|
+
return label_container.list()
|
|
483
519
|
|
|
484
520
|
def get_label(
|
|
485
521
|
self,
|
|
@@ -597,7 +633,7 @@ def open_ome_zarr_container(
|
|
|
597
633
|
handler = ZarrGroupHandler(store=store, cache=cache, mode=mode)
|
|
598
634
|
return OmeZarrContainer(
|
|
599
635
|
group_handler=handler,
|
|
600
|
-
|
|
636
|
+
validate_paths=validate_arrays,
|
|
601
637
|
)
|
|
602
638
|
|
|
603
639
|
|
|
@@ -796,7 +832,7 @@ def create_ome_zarr_from_array(
|
|
|
796
832
|
axes_names=axes_names,
|
|
797
833
|
name=name,
|
|
798
834
|
chunks=chunks,
|
|
799
|
-
dtype=array.dtype,
|
|
835
|
+
dtype=str(array.dtype),
|
|
800
836
|
overwrite=overwrite,
|
|
801
837
|
version=version,
|
|
802
838
|
)
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Collection
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from logging import Logger
|
|
6
5
|
from typing import Literal, TypeVar
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
from pydantic import BaseModel, ConfigDict, Field
|
|
10
9
|
|
|
11
|
-
from ngio.utils import NgioValidationError, NgioValueError
|
|
12
|
-
|
|
13
|
-
logger = Logger(__name__)
|
|
10
|
+
from ngio.utils import NgioValidationError, NgioValueError, ngio_logger
|
|
14
11
|
|
|
15
12
|
T = TypeVar("T")
|
|
16
13
|
|
|
@@ -102,20 +99,20 @@ class Axis(BaseModel):
|
|
|
102
99
|
def implicit_type_cast(self, cast_type: AxisType) -> "Axis":
|
|
103
100
|
unit = self.unit
|
|
104
101
|
if self.axis_type != cast_type:
|
|
105
|
-
|
|
102
|
+
ngio_logger.warning(
|
|
106
103
|
f"Axis {self.on_disk_name} has type {self.axis_type}. "
|
|
107
104
|
f"Casting to {cast_type}."
|
|
108
105
|
)
|
|
109
106
|
|
|
110
107
|
if cast_type == AxisType.time and unit is None:
|
|
111
|
-
|
|
108
|
+
ngio_logger.warning(
|
|
112
109
|
f"Time axis {self.on_disk_name} has unit {self.unit}. "
|
|
113
110
|
f"Casting to {DefaultSpaceUnit}."
|
|
114
111
|
)
|
|
115
112
|
unit = DefaultTimeUnit
|
|
116
113
|
|
|
117
114
|
if cast_type == AxisType.space and unit is None:
|
|
118
|
-
|
|
115
|
+
ngio_logger.warning(
|
|
119
116
|
f"Space axis {self.on_disk_name} has unit {unit}. "
|
|
120
117
|
f"Casting to {DefaultSpaceUnit}."
|
|
121
118
|
)
|