ngio 0.2.1__py3-none-any.whl → 0.2.3__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 +20 -2
- ngio/common/_pyramid.py +5 -1
- ngio/common/_roi.py +2 -2
- ngio/hcs/__init__.py +16 -2
- ngio/hcs/plate.py +496 -18
- ngio/images/abstract_image.py +11 -0
- ngio/images/create.py +25 -36
- ngio/images/image.py +80 -6
- ngio/images/label.py +38 -9
- ngio/images/ome_zarr_container.py +70 -33
- ngio/ome_zarr_meta/__init__.py +5 -3
- ngio/ome_zarr_meta/ngio_specs/__init__.py +10 -2
- ngio/ome_zarr_meta/ngio_specs/_axes.py +90 -65
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +46 -8
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +242 -70
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +49 -11
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +28 -11
- ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +2 -2
- ngio/tables/_validators.py +1 -83
- ngio/tables/backends/__init__.py +27 -1
- ngio/tables/backends/_abstract_backend.py +207 -22
- ngio/tables/backends/_anndata_utils.py +3 -109
- ngio/tables/backends/_anndata_v1.py +43 -46
- ngio/tables/backends/_csv_v1.py +162 -0
- ngio/tables/backends/_json_v1.py +54 -18
- ngio/tables/backends/_table_backends.py +98 -18
- ngio/tables/backends/_utils.py +458 -0
- ngio/tables/tables_container.py +3 -1
- ngio/tables/v1/_feature_table.py +20 -11
- ngio/tables/v1/_generic_table.py +20 -15
- ngio/tables/v1/_roi_table.py +7 -9
- ngio/utils/_zarr_utils.py +46 -32
- {ngio-0.2.1.dist-info → ngio-0.2.3.dist-info}/METADATA +3 -1
- ngio-0.2.3.dist-info/RECORD +57 -0
- ngio-0.2.1.dist-info/RECORD +0 -54
- {ngio-0.2.1.dist-info → ngio-0.2.3.dist-info}/WHEEL +0 -0
- {ngio-0.2.1.dist-info → ngio-0.2.3.dist-info}/licenses/LICENSE +0 -0
ngio/hcs/plate.py
CHANGED
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
"""A module for handling the Plate Collection in an OME-Zarr file."""
|
|
2
2
|
|
|
3
|
+
from typing import Literal, overload
|
|
4
|
+
|
|
3
5
|
from ngio.images import OmeZarrContainer
|
|
4
6
|
from ngio.ome_zarr_meta import (
|
|
5
7
|
ImageInWellPath,
|
|
6
|
-
|
|
8
|
+
NgffVersions,
|
|
7
9
|
NgioPlateMeta,
|
|
8
10
|
NgioWellMeta,
|
|
9
11
|
find_plate_meta_handler,
|
|
10
12
|
find_well_meta_handler,
|
|
11
13
|
get_plate_meta_handler,
|
|
12
14
|
get_well_meta_handler,
|
|
15
|
+
path_in_well_validation,
|
|
16
|
+
)
|
|
17
|
+
from ngio.tables import (
|
|
18
|
+
FeatureTable,
|
|
19
|
+
GenericRoiTable,
|
|
20
|
+
MaskingRoiTable,
|
|
21
|
+
RoiTable,
|
|
22
|
+
Table,
|
|
23
|
+
TablesContainer,
|
|
24
|
+
TypedTable,
|
|
13
25
|
)
|
|
14
26
|
from ngio.utils import (
|
|
15
27
|
AccessModeLiteral,
|
|
28
|
+
NgioValidationError,
|
|
29
|
+
NgioValueError,
|
|
16
30
|
StoreOrGroup,
|
|
17
31
|
ZarrGroupHandler,
|
|
18
32
|
)
|
|
19
33
|
|
|
20
34
|
|
|
35
|
+
def _default_table_container(handler: ZarrGroupHandler) -> TablesContainer | None:
|
|
36
|
+
"""Return a default table container."""
|
|
37
|
+
success, table_handler = handler.safe_derive_handler("tables")
|
|
38
|
+
if success and isinstance(table_handler, ZarrGroupHandler):
|
|
39
|
+
return TablesContainer(table_handler)
|
|
40
|
+
|
|
41
|
+
|
|
21
42
|
# Mock lock class that does nothing
|
|
22
43
|
class MockLock:
|
|
23
44
|
"""A mock lock class that does nothing."""
|
|
@@ -43,6 +64,10 @@ class OmeZarrWell:
|
|
|
43
64
|
self._group_handler = group_handler
|
|
44
65
|
self._meta_handler = find_well_meta_handler(group_handler)
|
|
45
66
|
|
|
67
|
+
def __repr__(self) -> str:
|
|
68
|
+
"""Return a string representation of the well."""
|
|
69
|
+
return f"Well(#images: {len(self.paths())})"
|
|
70
|
+
|
|
46
71
|
@property
|
|
47
72
|
def meta_handler(self):
|
|
48
73
|
"""Return the metadata handler."""
|
|
@@ -53,6 +78,11 @@ class OmeZarrWell:
|
|
|
53
78
|
"""Return the metadata."""
|
|
54
79
|
return self._meta_handler.meta
|
|
55
80
|
|
|
81
|
+
@property
|
|
82
|
+
def acquisition_ids(self) -> list[int]:
|
|
83
|
+
"""Return the acquisitions ids in the well."""
|
|
84
|
+
return self.meta.acquisition_ids
|
|
85
|
+
|
|
56
86
|
def paths(self, acquisition: int | None = None) -> list[str]:
|
|
57
87
|
"""Return the images paths in the well.
|
|
58
88
|
|
|
@@ -64,18 +94,115 @@ class OmeZarrWell:
|
|
|
64
94
|
"""
|
|
65
95
|
return self.meta.paths(acquisition)
|
|
66
96
|
|
|
97
|
+
def get_image_store(self, image_path: str) -> StoreOrGroup:
|
|
98
|
+
"""Get the image store from the well.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
image_path (str): The path of the image.
|
|
102
|
+
"""
|
|
103
|
+
return self._group_handler.get_group(image_path, create_mode=True)
|
|
104
|
+
|
|
105
|
+
def get_image_acquisition_id(self, image_path: str) -> int | None:
|
|
106
|
+
"""Get the acquisition id of an image in the well.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
image_path (str): The path of the image.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
int | None: The acquisition id of the image.
|
|
113
|
+
"""
|
|
114
|
+
return self.meta.get_image_acquisition_id(image_path=image_path)
|
|
115
|
+
|
|
116
|
+
def get_image(self, image_path: str) -> OmeZarrContainer:
|
|
117
|
+
"""Get an image from the well.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
image_path (str): The path of the image.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
OmeZarrContainer: The image.
|
|
124
|
+
"""
|
|
125
|
+
handler = self._group_handler.derive_handler(image_path)
|
|
126
|
+
return OmeZarrContainer(handler)
|
|
127
|
+
|
|
128
|
+
def _add_image(
|
|
129
|
+
self,
|
|
130
|
+
image_path: str,
|
|
131
|
+
acquisition_id: int | None = None,
|
|
132
|
+
strict: bool = True,
|
|
133
|
+
atomic: bool = False,
|
|
134
|
+
) -> StoreOrGroup:
|
|
135
|
+
"""Add an image to an ome-zarr well."""
|
|
136
|
+
image_path = path_in_well_validation(path=image_path)
|
|
137
|
+
|
|
138
|
+
if atomic:
|
|
139
|
+
well_lock = self._group_handler.lock
|
|
140
|
+
else:
|
|
141
|
+
well_lock = MockLock()
|
|
142
|
+
|
|
143
|
+
with well_lock:
|
|
144
|
+
meta = self.meta.add_image(
|
|
145
|
+
path=image_path, acquisition=acquisition_id, strict=strict
|
|
146
|
+
)
|
|
147
|
+
self.meta_handler.write_meta(meta)
|
|
148
|
+
self.meta_handler._group_handler.clean_cache()
|
|
149
|
+
|
|
150
|
+
return self._group_handler.get_group(image_path, create_mode=True)
|
|
151
|
+
|
|
152
|
+
def atomic_add_image(
|
|
153
|
+
self,
|
|
154
|
+
image_path: str,
|
|
155
|
+
acquisition_id: int | None = None,
|
|
156
|
+
strict: bool = True,
|
|
157
|
+
) -> StoreOrGroup:
|
|
158
|
+
"""Parallel safe version of add_image."""
|
|
159
|
+
return self._add_image(
|
|
160
|
+
image_path=image_path,
|
|
161
|
+
acquisition_id=acquisition_id,
|
|
162
|
+
atomic=True,
|
|
163
|
+
strict=strict,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def add_image(
|
|
167
|
+
self,
|
|
168
|
+
image_path: str,
|
|
169
|
+
acquisition_id: int | None = None,
|
|
170
|
+
strict: bool = True,
|
|
171
|
+
) -> StoreOrGroup:
|
|
172
|
+
"""Add an image to an ome-zarr well.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
image_path (str): The path of the image.
|
|
176
|
+
acquisition_id (int | None): The acquisition id to filter the images.
|
|
177
|
+
strict (bool): Whether to check if the acquisition id is already exists
|
|
178
|
+
in the well. Defaults to True. If False this might lead to
|
|
179
|
+
acquision in a well that does not exist at the plate level.
|
|
180
|
+
"""
|
|
181
|
+
return self._add_image(
|
|
182
|
+
image_path=image_path,
|
|
183
|
+
acquisition_id=acquisition_id,
|
|
184
|
+
atomic=False,
|
|
185
|
+
strict=strict,
|
|
186
|
+
)
|
|
187
|
+
|
|
67
188
|
|
|
68
189
|
class OmeZarrPlate:
|
|
69
190
|
"""A class to handle the Plate Collection in an OME-Zarr file."""
|
|
70
191
|
|
|
71
|
-
def __init__(
|
|
192
|
+
def __init__(
|
|
193
|
+
self,
|
|
194
|
+
group_handler: ZarrGroupHandler,
|
|
195
|
+
table_container: TablesContainer | None = None,
|
|
196
|
+
) -> None:
|
|
72
197
|
"""Initialize the LabelGroupHandler.
|
|
73
198
|
|
|
74
199
|
Args:
|
|
75
200
|
group_handler: The Zarr group handler that contains the Plate.
|
|
201
|
+
table_container: The tables container that contains plate level tables.
|
|
76
202
|
"""
|
|
77
203
|
self._group_handler = group_handler
|
|
78
204
|
self._meta_handler = find_plate_meta_handler(group_handler)
|
|
205
|
+
self._tables_container = table_container
|
|
79
206
|
|
|
80
207
|
def __repr__(self) -> str:
|
|
81
208
|
"""Return a string representation of the plate."""
|
|
@@ -107,9 +234,9 @@ class OmeZarrPlate:
|
|
|
107
234
|
return self.meta.acquisitions_names
|
|
108
235
|
|
|
109
236
|
@property
|
|
110
|
-
def
|
|
237
|
+
def acquisition_ids(self) -> list[int]:
|
|
111
238
|
"""Return the acquisitions ids in the plate."""
|
|
112
|
-
return self.meta.
|
|
239
|
+
return self.meta.acquisition_ids
|
|
113
240
|
|
|
114
241
|
def _well_path(self, row: str, column: int | str) -> str:
|
|
115
242
|
"""Return the well path in the plate."""
|
|
@@ -160,6 +287,22 @@ class OmeZarrPlate:
|
|
|
160
287
|
images.append(self._image_path(row=row, column=column, path=path))
|
|
161
288
|
return images
|
|
162
289
|
|
|
290
|
+
def get_image_acquisition_id(
|
|
291
|
+
self, row: str, column: int | str, image_path: str
|
|
292
|
+
) -> int | None:
|
|
293
|
+
"""Get the acquisition id of an image in a well.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
row (str): The row of the well.
|
|
297
|
+
column (int | str): The column of the well.
|
|
298
|
+
image_path (str): The path of the image.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
int | None: The acquisition id of the image.
|
|
302
|
+
"""
|
|
303
|
+
well = self.get_well(row=row, column=column)
|
|
304
|
+
return well.get_image_acquisition_id(image_path=image_path)
|
|
305
|
+
|
|
163
306
|
def get_well(self, row: str, column: int | str) -> OmeZarrWell:
|
|
164
307
|
"""Get a well from the plate.
|
|
165
308
|
|
|
@@ -217,6 +360,19 @@ class OmeZarrPlate:
|
|
|
217
360
|
group_handler = self._group_handler.derive_handler(image_path)
|
|
218
361
|
return OmeZarrContainer(group_handler)
|
|
219
362
|
|
|
363
|
+
def get_image_store(
|
|
364
|
+
self, row: str, column: int | str, image_path: str
|
|
365
|
+
) -> StoreOrGroup:
|
|
366
|
+
"""Get the image store from the plate.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
row (str): The row of the well.
|
|
370
|
+
column (int | str): The column of the well.
|
|
371
|
+
image_path (str): The path of the image.
|
|
372
|
+
"""
|
|
373
|
+
well = self.get_well(row=row, column=column)
|
|
374
|
+
return well.get_image_store(image_path=image_path)
|
|
375
|
+
|
|
220
376
|
def get_well_images(
|
|
221
377
|
self, row: str, column: str | int, acquisition: int | None = None
|
|
222
378
|
) -> dict[str, OmeZarrContainer]:
|
|
@@ -239,12 +395,15 @@ class OmeZarrPlate:
|
|
|
239
395
|
self,
|
|
240
396
|
row: str,
|
|
241
397
|
column: int | str,
|
|
242
|
-
image_path: str,
|
|
398
|
+
image_path: str | None = None,
|
|
243
399
|
acquisition_id: int | None = None,
|
|
244
400
|
acquisition_name: str | None = None,
|
|
245
401
|
atomic: bool = False,
|
|
246
|
-
) -> StoreOrGroup:
|
|
402
|
+
) -> StoreOrGroup | None:
|
|
247
403
|
"""Add an image to an ome-zarr plate."""
|
|
404
|
+
if image_path is not None:
|
|
405
|
+
image_path = path_in_well_validation(path=image_path)
|
|
406
|
+
|
|
248
407
|
if atomic:
|
|
249
408
|
plate_lock = self._group_handler.lock
|
|
250
409
|
else:
|
|
@@ -252,7 +411,11 @@ class OmeZarrPlate:
|
|
|
252
411
|
|
|
253
412
|
with plate_lock:
|
|
254
413
|
meta = self.meta
|
|
255
|
-
meta = meta.add_well(row, column
|
|
414
|
+
meta = meta.add_well(row=row, column=column)
|
|
415
|
+
if acquisition_id is not None:
|
|
416
|
+
meta = meta.add_acquisition(
|
|
417
|
+
acquisition_id=acquisition_id, acquisition_name=acquisition_name
|
|
418
|
+
)
|
|
256
419
|
self.meta_handler.write_meta(meta)
|
|
257
420
|
self.meta_handler._group_handler.clean_cache()
|
|
258
421
|
|
|
@@ -279,11 +442,16 @@ class OmeZarrPlate:
|
|
|
279
442
|
|
|
280
443
|
group_handler = self._group_handler.derive_handler(well_path)
|
|
281
444
|
|
|
282
|
-
|
|
445
|
+
if image_path is not None:
|
|
446
|
+
well_meta = well_meta.add_image(
|
|
447
|
+
path=image_path, acquisition=acquisition_id, strict=False
|
|
448
|
+
)
|
|
283
449
|
meta_handler.write_meta(well_meta)
|
|
284
450
|
meta_handler._group_handler.clean_cache()
|
|
285
451
|
|
|
286
|
-
|
|
452
|
+
if image_path is not None:
|
|
453
|
+
return group_handler.get_group(image_path, create_mode=True)
|
|
454
|
+
return None
|
|
287
455
|
|
|
288
456
|
def atomic_add_image(
|
|
289
457
|
self,
|
|
@@ -294,7 +462,12 @@ class OmeZarrPlate:
|
|
|
294
462
|
acquisition_name: str | None = None,
|
|
295
463
|
) -> StoreOrGroup:
|
|
296
464
|
"""Parallel safe version of add_image."""
|
|
297
|
-
|
|
465
|
+
if image_path is None:
|
|
466
|
+
raise ValueError(
|
|
467
|
+
"Image path cannot be None for atomic add_image. "
|
|
468
|
+
"If your intent is to add a well, use add_well instead."
|
|
469
|
+
)
|
|
470
|
+
group = self._add_image(
|
|
298
471
|
row=row,
|
|
299
472
|
column=column,
|
|
300
473
|
image_path=image_path,
|
|
@@ -302,6 +475,12 @@ class OmeZarrPlate:
|
|
|
302
475
|
acquisition_name=acquisition_name,
|
|
303
476
|
atomic=True,
|
|
304
477
|
)
|
|
478
|
+
if group is None:
|
|
479
|
+
raise ValueError(
|
|
480
|
+
f"Some error occurred while adding image {image_path} "
|
|
481
|
+
f"to well {row}{column}."
|
|
482
|
+
)
|
|
483
|
+
return group
|
|
305
484
|
|
|
306
485
|
def add_image(
|
|
307
486
|
self,
|
|
@@ -312,7 +491,12 @@ class OmeZarrPlate:
|
|
|
312
491
|
acquisition_name: str | None = None,
|
|
313
492
|
) -> StoreOrGroup:
|
|
314
493
|
"""Add an image to an ome-zarr plate."""
|
|
315
|
-
|
|
494
|
+
if image_path is None:
|
|
495
|
+
raise ValueError(
|
|
496
|
+
"Image path cannot be None for atomic add_image. "
|
|
497
|
+
"If your intent is to add a well, use add_well instead."
|
|
498
|
+
)
|
|
499
|
+
group = self._add_image(
|
|
316
500
|
row=row,
|
|
317
501
|
column=column,
|
|
318
502
|
image_path=image_path,
|
|
@@ -320,6 +504,68 @@ class OmeZarrPlate:
|
|
|
320
504
|
acquisition_name=acquisition_name,
|
|
321
505
|
atomic=False,
|
|
322
506
|
)
|
|
507
|
+
if group is None:
|
|
508
|
+
raise ValueError(
|
|
509
|
+
f"Some error occurred while adding image {image_path} "
|
|
510
|
+
f"to well {row}{column}."
|
|
511
|
+
)
|
|
512
|
+
return group
|
|
513
|
+
|
|
514
|
+
def add_well(
|
|
515
|
+
self,
|
|
516
|
+
row: str,
|
|
517
|
+
column: int | str,
|
|
518
|
+
) -> OmeZarrWell:
|
|
519
|
+
"""Add a well to an ome-zarr plate."""
|
|
520
|
+
_ = self._add_image(
|
|
521
|
+
row=row,
|
|
522
|
+
column=column,
|
|
523
|
+
image_path=None,
|
|
524
|
+
acquisition_id=None,
|
|
525
|
+
acquisition_name=None,
|
|
526
|
+
atomic=False,
|
|
527
|
+
)
|
|
528
|
+
return self.get_well(row=row, column=column)
|
|
529
|
+
|
|
530
|
+
def add_column(
|
|
531
|
+
self,
|
|
532
|
+
column: int | str,
|
|
533
|
+
) -> "OmeZarrPlate":
|
|
534
|
+
"""Add a column to an ome-zarr plate."""
|
|
535
|
+
meta, _ = self.meta.add_column(column)
|
|
536
|
+
self.meta_handler.write_meta(meta)
|
|
537
|
+
self.meta_handler._group_handler.clean_cache()
|
|
538
|
+
return self
|
|
539
|
+
|
|
540
|
+
def add_row(
|
|
541
|
+
self,
|
|
542
|
+
row: str,
|
|
543
|
+
) -> "OmeZarrPlate":
|
|
544
|
+
"""Add a row to an ome-zarr plate."""
|
|
545
|
+
meta, _ = self.meta.add_row(row)
|
|
546
|
+
self.meta_handler.write_meta(meta)
|
|
547
|
+
self.meta_handler._group_handler.clean_cache()
|
|
548
|
+
return self
|
|
549
|
+
|
|
550
|
+
def add_acquisition(
|
|
551
|
+
self,
|
|
552
|
+
acquisition_id: int,
|
|
553
|
+
acquisition_name: str,
|
|
554
|
+
) -> "OmeZarrPlate":
|
|
555
|
+
"""Add an acquisition to an ome-zarr plate.
|
|
556
|
+
|
|
557
|
+
Be aware that this is not a parallel safe operation.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
acquisition_id (int): The acquisition id.
|
|
561
|
+
acquisition_name (str): The acquisition name.
|
|
562
|
+
"""
|
|
563
|
+
meta = self.meta.add_acquisition(
|
|
564
|
+
acquisition_id=acquisition_id, acquisition_name=acquisition_name
|
|
565
|
+
)
|
|
566
|
+
self.meta_handler.write_meta(meta)
|
|
567
|
+
self.meta_handler._group_handler.clean_cache()
|
|
568
|
+
return self
|
|
323
569
|
|
|
324
570
|
def _remove_well(
|
|
325
571
|
self,
|
|
@@ -390,6 +636,127 @@ class OmeZarrPlate:
|
|
|
390
636
|
atomic=False,
|
|
391
637
|
)
|
|
392
638
|
|
|
639
|
+
def derive_plate(
|
|
640
|
+
self,
|
|
641
|
+
store: StoreOrGroup,
|
|
642
|
+
plate_name: str | None = None,
|
|
643
|
+
version: NgffVersions = "0.4",
|
|
644
|
+
keep_acquisitions: bool = False,
|
|
645
|
+
cache: bool = False,
|
|
646
|
+
overwrite: bool = False,
|
|
647
|
+
parallel_safe: bool = True,
|
|
648
|
+
) -> "OmeZarrPlate":
|
|
649
|
+
"""Derive a new OME-Zarr plate from an existing one.
|
|
650
|
+
|
|
651
|
+
Args:
|
|
652
|
+
store (StoreOrGroup): The Zarr store or group that stores the plate.
|
|
653
|
+
plate_name (str | None): The name of the new plate.
|
|
654
|
+
version (NgffVersion): The version of the new plate.
|
|
655
|
+
keep_acquisitions (bool): Whether to keep the acquisitions in the new plate.
|
|
656
|
+
cache (bool): Whether to use a cache for the zarr group metadata.
|
|
657
|
+
overwrite (bool): Whether to overwrite the existing plate.
|
|
658
|
+
parallel_safe (bool): Whether the group handler is parallel safe.
|
|
659
|
+
"""
|
|
660
|
+
return derive_ome_zarr_plate(
|
|
661
|
+
ome_zarr_plate=self,
|
|
662
|
+
store=store,
|
|
663
|
+
plate_name=plate_name,
|
|
664
|
+
version=version,
|
|
665
|
+
keep_acquisitions=keep_acquisitions,
|
|
666
|
+
cache=cache,
|
|
667
|
+
overwrite=overwrite,
|
|
668
|
+
parallel_safe=parallel_safe,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
@property
|
|
672
|
+
def tables_container(self) -> TablesContainer:
|
|
673
|
+
"""Return the tables container."""
|
|
674
|
+
if self._tables_container is None:
|
|
675
|
+
self._tables_container = _default_table_container(self._group_handler)
|
|
676
|
+
if self._tables_container is None:
|
|
677
|
+
raise NgioValidationError("No tables found in the image.")
|
|
678
|
+
return self._tables_container
|
|
679
|
+
|
|
680
|
+
@property
|
|
681
|
+
def list_tables(self) -> list[str]:
|
|
682
|
+
"""List all tables in the image."""
|
|
683
|
+
return self.tables_container.list()
|
|
684
|
+
|
|
685
|
+
def list_roi_tables(self) -> list[str]:
|
|
686
|
+
"""List all ROI tables in the image."""
|
|
687
|
+
return self.tables_container.list_roi_tables()
|
|
688
|
+
|
|
689
|
+
@overload
|
|
690
|
+
def get_table(self, name: str, check_type: None) -> Table: ...
|
|
691
|
+
|
|
692
|
+
@overload
|
|
693
|
+
def get_table(self, name: str, check_type: Literal["roi_table"]) -> RoiTable: ...
|
|
694
|
+
|
|
695
|
+
@overload
|
|
696
|
+
def get_table(
|
|
697
|
+
self, name: str, check_type: Literal["masking_roi_table"]
|
|
698
|
+
) -> MaskingRoiTable: ...
|
|
699
|
+
|
|
700
|
+
@overload
|
|
701
|
+
def get_table(
|
|
702
|
+
self, name: str, check_type: Literal["feature_table"]
|
|
703
|
+
) -> FeatureTable: ...
|
|
704
|
+
|
|
705
|
+
@overload
|
|
706
|
+
def get_table(
|
|
707
|
+
self, name: str, check_type: Literal["generic_roi_table"]
|
|
708
|
+
) -> GenericRoiTable: ...
|
|
709
|
+
|
|
710
|
+
def get_table(self, name: str, check_type: TypedTable | None = None) -> Table:
|
|
711
|
+
"""Get a table from the image."""
|
|
712
|
+
table = self.tables_container.get(name)
|
|
713
|
+
match check_type:
|
|
714
|
+
case "roi_table":
|
|
715
|
+
if not isinstance(table, RoiTable):
|
|
716
|
+
raise NgioValueError(
|
|
717
|
+
f"Table '{name}' is not a ROI table. Found type: {table.type()}"
|
|
718
|
+
)
|
|
719
|
+
return table
|
|
720
|
+
case "masking_roi_table":
|
|
721
|
+
if not isinstance(table, MaskingRoiTable):
|
|
722
|
+
raise NgioValueError(
|
|
723
|
+
f"Table '{name}' is not a masking ROI table. "
|
|
724
|
+
f"Found type: {table.type()}"
|
|
725
|
+
)
|
|
726
|
+
return table
|
|
727
|
+
|
|
728
|
+
case "generic_roi_table":
|
|
729
|
+
if not isinstance(table, GenericRoiTable):
|
|
730
|
+
raise NgioValueError(
|
|
731
|
+
f"Table '{name}' is not a generic ROI table. "
|
|
732
|
+
f"Found type: {table.type()}"
|
|
733
|
+
)
|
|
734
|
+
return table
|
|
735
|
+
|
|
736
|
+
case "feature_table":
|
|
737
|
+
if not isinstance(table, FeatureTable):
|
|
738
|
+
raise NgioValueError(
|
|
739
|
+
f"Table '{name}' is not a feature table. "
|
|
740
|
+
f"Found type: {table.type()}"
|
|
741
|
+
)
|
|
742
|
+
return table
|
|
743
|
+
case None:
|
|
744
|
+
return table
|
|
745
|
+
case _:
|
|
746
|
+
raise NgioValueError(f"Unknown check_type: {check_type}")
|
|
747
|
+
|
|
748
|
+
def add_table(
|
|
749
|
+
self,
|
|
750
|
+
name: str,
|
|
751
|
+
table: Table,
|
|
752
|
+
backend: str | None = None,
|
|
753
|
+
overwrite: bool = False,
|
|
754
|
+
) -> None:
|
|
755
|
+
"""Add a table to the image."""
|
|
756
|
+
self.tables_container.add(
|
|
757
|
+
name=name, table=table, backend=backend, overwrite=overwrite
|
|
758
|
+
)
|
|
759
|
+
|
|
393
760
|
|
|
394
761
|
def open_ome_zarr_plate(
|
|
395
762
|
store: StoreOrGroup,
|
|
@@ -412,26 +779,42 @@ def open_ome_zarr_plate(
|
|
|
412
779
|
return OmeZarrPlate(group_handler)
|
|
413
780
|
|
|
414
781
|
|
|
782
|
+
def _create_empty_plate_from_meta(
|
|
783
|
+
store: StoreOrGroup,
|
|
784
|
+
meta: NgioPlateMeta,
|
|
785
|
+
version: NgffVersions = "0.4",
|
|
786
|
+
overwrite: bool = False,
|
|
787
|
+
) -> ZarrGroupHandler:
|
|
788
|
+
"""Create an empty OME-Zarr plate from metadata."""
|
|
789
|
+
mode = "w" if overwrite else "w-"
|
|
790
|
+
group_handler = ZarrGroupHandler(
|
|
791
|
+
store=store, cache=True, mode=mode, parallel_safe=False
|
|
792
|
+
)
|
|
793
|
+
meta_handler = get_plate_meta_handler(group_handler, version=version)
|
|
794
|
+
meta_handler.write_meta(meta)
|
|
795
|
+
return group_handler
|
|
796
|
+
|
|
797
|
+
|
|
415
798
|
def create_empty_plate(
|
|
416
799
|
store: StoreOrGroup,
|
|
417
800
|
name: str,
|
|
418
801
|
images: list[ImageInWellPath] | None = None,
|
|
419
|
-
version:
|
|
802
|
+
version: NgffVersions = "0.4",
|
|
420
803
|
cache: bool = False,
|
|
421
804
|
overwrite: bool = False,
|
|
422
805
|
parallel_safe: bool = True,
|
|
423
806
|
) -> OmeZarrPlate:
|
|
424
807
|
"""Initialize and create an empty OME-Zarr plate."""
|
|
425
|
-
mode = "w" if overwrite else "w-"
|
|
426
|
-
group_handler = ZarrGroupHandler(
|
|
427
|
-
store=store, cache=True, mode=mode, parallel_safe=False
|
|
428
|
-
)
|
|
429
|
-
meta_handler = get_plate_meta_handler(group_handler, version=version)
|
|
430
808
|
plate_meta = NgioPlateMeta.default_init(
|
|
431
809
|
name=name,
|
|
432
810
|
version=version,
|
|
433
811
|
)
|
|
434
|
-
|
|
812
|
+
group_handler = _create_empty_plate_from_meta(
|
|
813
|
+
store=store,
|
|
814
|
+
meta=plate_meta,
|
|
815
|
+
version=version,
|
|
816
|
+
overwrite=overwrite,
|
|
817
|
+
)
|
|
435
818
|
|
|
436
819
|
if images is not None:
|
|
437
820
|
plate = OmeZarrPlate(group_handler)
|
|
@@ -449,3 +832,98 @@ def create_empty_plate(
|
|
|
449
832
|
mode="r+",
|
|
450
833
|
parallel_safe=parallel_safe,
|
|
451
834
|
)
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
def derive_ome_zarr_plate(
|
|
838
|
+
ome_zarr_plate: OmeZarrPlate,
|
|
839
|
+
store: StoreOrGroup,
|
|
840
|
+
plate_name: str | None = None,
|
|
841
|
+
version: NgffVersions = "0.4",
|
|
842
|
+
keep_acquisitions: bool = False,
|
|
843
|
+
cache: bool = False,
|
|
844
|
+
overwrite: bool = False,
|
|
845
|
+
parallel_safe: bool = True,
|
|
846
|
+
) -> OmeZarrPlate:
|
|
847
|
+
"""Derive a new OME-Zarr plate from an existing one.
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
ome_zarr_plate (OmeZarrPlate): The existing OME-Zarr plate.
|
|
851
|
+
store (StoreOrGroup): The Zarr store or group that stores the plate.
|
|
852
|
+
plate_name (str | None): The name of the new plate.
|
|
853
|
+
version (NgffVersion): The version of the new plate.
|
|
854
|
+
keep_acquisitions (bool): Whether to keep the acquisitions in the new plate.
|
|
855
|
+
cache (bool): Whether to use a cache for the zarr group metadata.
|
|
856
|
+
overwrite (bool): Whether to overwrite the existing plate.
|
|
857
|
+
parallel_safe (bool): Whether the group handler is parallel safe.
|
|
858
|
+
"""
|
|
859
|
+
if plate_name is None:
|
|
860
|
+
plate_name = ome_zarr_plate.meta.plate.name
|
|
861
|
+
|
|
862
|
+
new_meta = ome_zarr_plate.meta.derive(
|
|
863
|
+
name=plate_name,
|
|
864
|
+
version=version,
|
|
865
|
+
keep_acquisitions=keep_acquisitions,
|
|
866
|
+
)
|
|
867
|
+
_ = _create_empty_plate_from_meta(
|
|
868
|
+
store=store,
|
|
869
|
+
meta=new_meta,
|
|
870
|
+
overwrite=overwrite,
|
|
871
|
+
version=version,
|
|
872
|
+
)
|
|
873
|
+
return open_ome_zarr_plate(
|
|
874
|
+
store=store,
|
|
875
|
+
cache=cache,
|
|
876
|
+
mode="r+",
|
|
877
|
+
parallel_safe=parallel_safe,
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def open_ome_zarr_well(
|
|
882
|
+
store: StoreOrGroup,
|
|
883
|
+
cache: bool = False,
|
|
884
|
+
mode: AccessModeLiteral = "r+",
|
|
885
|
+
parallel_safe: bool = True,
|
|
886
|
+
) -> OmeZarrWell:
|
|
887
|
+
"""Open an OME-Zarr well.
|
|
888
|
+
|
|
889
|
+
Args:
|
|
890
|
+
store (StoreOrGroup): The Zarr store or group that stores the plate.
|
|
891
|
+
cache (bool): Whether to use a cache for the zarr group metadata.
|
|
892
|
+
mode (AccessModeLiteral): The access mode for the image. Defaults to "r+".
|
|
893
|
+
parallel_safe (bool): Whether the group handler is parallel safe.
|
|
894
|
+
"""
|
|
895
|
+
group_handler = ZarrGroupHandler(
|
|
896
|
+
store=store, cache=cache, mode=mode, parallel_safe=parallel_safe
|
|
897
|
+
)
|
|
898
|
+
return OmeZarrWell(group_handler)
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
def create_empty_well(
|
|
902
|
+
store: StoreOrGroup,
|
|
903
|
+
version: NgffVersions = "0.4",
|
|
904
|
+
cache: bool = False,
|
|
905
|
+
overwrite: bool = False,
|
|
906
|
+
parallel_safe: bool = True,
|
|
907
|
+
) -> OmeZarrWell:
|
|
908
|
+
"""Create an empty OME-Zarr well.
|
|
909
|
+
|
|
910
|
+
Args:
|
|
911
|
+
store (StoreOrGroup): The Zarr store or group that stores the well.
|
|
912
|
+
version (NgffVersion): The version of the new well.
|
|
913
|
+
cache (bool): Whether to use a cache for the zarr group metadata.
|
|
914
|
+
overwrite (bool): Whether to overwrite the existing well.
|
|
915
|
+
parallel_safe (bool): Whether the group handler is parallel safe.
|
|
916
|
+
"""
|
|
917
|
+
group_handler = ZarrGroupHandler(
|
|
918
|
+
store=store, cache=True, mode="w" if overwrite else "w-", parallel_safe=False
|
|
919
|
+
)
|
|
920
|
+
meta_handler = get_well_meta_handler(group_handler, version=version)
|
|
921
|
+
meta = NgioWellMeta.default_init()
|
|
922
|
+
meta_handler.write_meta(meta)
|
|
923
|
+
|
|
924
|
+
return open_ome_zarr_well(
|
|
925
|
+
store=store,
|
|
926
|
+
cache=cache,
|
|
927
|
+
mode="r+",
|
|
928
|
+
parallel_safe=parallel_safe,
|
|
929
|
+
)
|
ngio/images/abstract_image.py
CHANGED
|
@@ -135,6 +135,16 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
135
135
|
"""Return True if the image is multichannel."""
|
|
136
136
|
return self.dimensions.is_multi_channels
|
|
137
137
|
|
|
138
|
+
@property
|
|
139
|
+
def space_unit(self) -> str | None:
|
|
140
|
+
"""Return the space unit of the image."""
|
|
141
|
+
return self.meta_handler.meta.space_unit
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def time_unit(self) -> str | None:
|
|
145
|
+
"""Return the time unit of the image."""
|
|
146
|
+
return self.meta_handler.meta.time_unit
|
|
147
|
+
|
|
138
148
|
@property
|
|
139
149
|
def pixel_size(self) -> PixelSize:
|
|
140
150
|
"""Return the pixel size of the image."""
|
|
@@ -152,6 +162,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
152
162
|
|
|
153
163
|
def has_axis(self, axis: str) -> bool:
|
|
154
164
|
"""Return True if the image has the given axis."""
|
|
165
|
+
self.axes_mapper.get_index("x")
|
|
155
166
|
return self.dimensions.has_axis(axis)
|
|
156
167
|
|
|
157
168
|
def get_array(
|