ngio 0.5.0__py3-none-any.whl → 0.5.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ngio/__init__.py +2 -5
- ngio/common/__init__.py +6 -11
- ngio/common/_masking_roi.py +54 -34
- ngio/common/_pyramid.py +87 -321
- ngio/common/_roi.py +330 -258
- ngio/experimental/iterators/_feature.py +3 -3
- ngio/experimental/iterators/_rois_utils.py +11 -10
- ngio/hcs/_plate.py +136 -192
- ngio/images/_abstract_image.py +35 -539
- ngio/images/_create.py +283 -0
- ngio/images/_create_synt_container.py +43 -40
- ngio/images/_image.py +251 -517
- ngio/images/_label.py +172 -249
- ngio/images/_masked_image.py +2 -2
- ngio/images/_ome_zarr_container.py +241 -644
- ngio/io_pipes/_io_pipes.py +9 -9
- ngio/io_pipes/_io_pipes_masked.py +7 -7
- ngio/io_pipes/_io_pipes_roi.py +6 -6
- ngio/io_pipes/_io_pipes_types.py +3 -3
- ngio/io_pipes/_match_shape.py +8 -6
- ngio/io_pipes/_ops_slices_utils.py +5 -8
- ngio/ome_zarr_meta/__init__.py +18 -29
- ngio/ome_zarr_meta/_meta_handlers.py +708 -392
- ngio/ome_zarr_meta/ngio_specs/__init__.py +0 -4
- ngio/ome_zarr_meta/ngio_specs/_axes.py +51 -152
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +22 -13
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +91 -129
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +68 -57
- ngio/ome_zarr_meta/v04/__init__.py +1 -5
- ngio/ome_zarr_meta/v04/{_v04_spec.py → _v04_spec_utils.py} +85 -54
- ngio/ome_zarr_meta/v05/__init__.py +1 -5
- ngio/ome_zarr_meta/v05/{_v05_spec.py → _v05_spec_utils.py} +87 -64
- ngio/resources/__init__.py +1 -1
- ngio/resources/resource_model.py +1 -1
- ngio/tables/_tables_container.py +27 -85
- ngio/tables/backends/_anndata.py +8 -58
- ngio/tables/backends/_anndata_utils.py +6 -1
- ngio/tables/backends/_csv.py +19 -3
- ngio/tables/backends/_json.py +13 -10
- ngio/tables/backends/_non_zarr_backends.py +196 -0
- ngio/tables/backends/_parquet.py +31 -3
- ngio/tables/v1/_roi_table.py +27 -44
- ngio/utils/__init__.py +12 -8
- ngio/utils/_datasets.py +0 -6
- ngio/utils/_logger.py +50 -0
- ngio/utils/_zarr_utils.py +250 -292
- {ngio-0.5.0.dist-info → ngio-0.5.0a1.dist-info}/METADATA +6 -13
- ngio-0.5.0a1.dist-info/RECORD +88 -0
- {ngio-0.5.0.dist-info → ngio-0.5.0a1.dist-info}/WHEEL +1 -1
- ngio/images/_create_utils.py +0 -406
- ngio/tables/backends/_py_arrow_backends.py +0 -222
- ngio/utils/_cache.py +0 -48
- ngio-0.5.0.dist-info/RECORD +0 -88
- {ngio-0.5.0.dist-info → ngio-0.5.0a1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,31 +1,32 @@
|
|
|
1
1
|
"""HCS (High Content Screening) specific metadata classes for NGIO."""
|
|
2
2
|
|
|
3
|
-
import warnings
|
|
4
3
|
from typing import Annotated
|
|
5
4
|
|
|
6
|
-
from ome_zarr_models.
|
|
5
|
+
from ome_zarr_models.v04.hcs import HCSAttrs
|
|
6
|
+
from ome_zarr_models.v04.plate import (
|
|
7
7
|
Acquisition,
|
|
8
8
|
Column,
|
|
9
|
-
|
|
9
|
+
Plate,
|
|
10
10
|
Row,
|
|
11
11
|
WellInPlate,
|
|
12
12
|
)
|
|
13
|
-
from ome_zarr_models.
|
|
13
|
+
from ome_zarr_models.v04.well import WellAttrs as WellAttrs04
|
|
14
|
+
from ome_zarr_models.v04.well_types import WellImage as WellImage04
|
|
15
|
+
from ome_zarr_models.v04.well_types import WellMeta as WellMeta04
|
|
14
16
|
from pydantic import BaseModel, SkipValidation, field_serializer
|
|
15
17
|
|
|
16
18
|
from ngio.ome_zarr_meta.ngio_specs._ngio_image import DefaultNgffVersion, NgffVersions
|
|
17
|
-
from ngio.utils import NgioValueError
|
|
19
|
+
from ngio.utils import NgioValueError, ngio_logger
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
def path_in_well_validation(path: str) -> str:
|
|
21
23
|
"""Validate the path in the well."""
|
|
22
24
|
# Check if the value contains only alphanumeric characters
|
|
23
25
|
if not path.isalnum():
|
|
24
|
-
|
|
26
|
+
ngio_logger.warning(
|
|
25
27
|
f"Path '{path}' contains non-alphanumeric characters. "
|
|
26
28
|
"This may cause issues with some tools. "
|
|
27
|
-
"Consider using only alphanumeric characters in the path."
|
|
28
|
-
stacklevel=2,
|
|
29
|
+
"Consider using only alphanumeric characters in the path."
|
|
29
30
|
)
|
|
30
31
|
return path
|
|
31
32
|
|
|
@@ -40,7 +41,7 @@ class ImageInWellPath(BaseModel):
|
|
|
40
41
|
acquisition_name: str | None = None
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
class CustomWellImage(
|
|
44
|
+
class CustomWellImage(WellImage04):
|
|
44
45
|
path: Annotated[str, SkipValidation]
|
|
45
46
|
|
|
46
47
|
@field_serializer("path")
|
|
@@ -49,29 +50,32 @@ class CustomWellImage(WellImageCommon):
|
|
|
49
50
|
return path_in_well_validation(value)
|
|
50
51
|
|
|
51
52
|
|
|
52
|
-
class
|
|
53
|
-
|
|
53
|
+
class CustomWellMeta(WellMeta04):
|
|
54
|
+
images: list[CustomWellImage] # type: ignore (override of WellMeta04.images)
|
|
54
55
|
|
|
55
56
|
|
|
56
|
-
class
|
|
57
|
-
|
|
57
|
+
class CustomWellAttrs(WellAttrs04):
|
|
58
|
+
well: CustomWellMeta # type: ignore (override of WellAttrs04.well)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
|
|
61
|
+
class NgioWellMeta(CustomWellAttrs):
|
|
62
|
+
"""HCS well metadata."""
|
|
61
63
|
|
|
62
64
|
@classmethod
|
|
63
65
|
def default_init(
|
|
64
66
|
cls,
|
|
65
|
-
|
|
67
|
+
version: NgffVersions | None = None,
|
|
66
68
|
) -> "NgioWellMeta":
|
|
67
|
-
|
|
69
|
+
if version is None:
|
|
70
|
+
version = DefaultNgffVersion
|
|
71
|
+
well = cls(well=CustomWellMeta(images=[], version=version))
|
|
68
72
|
return well
|
|
69
73
|
|
|
70
74
|
@property
|
|
71
75
|
def acquisition_ids(self) -> list[int]:
|
|
72
76
|
"""Return the acquisition ids in the well."""
|
|
73
77
|
acquisitions = []
|
|
74
|
-
for images in self.images:
|
|
78
|
+
for images in self.well.images:
|
|
75
79
|
if (
|
|
76
80
|
images.acquisition is not None
|
|
77
81
|
and images.acquisition not in acquisitions
|
|
@@ -81,7 +85,7 @@ class NgioWellMeta(BaseModel):
|
|
|
81
85
|
|
|
82
86
|
def get_image_acquisition_id(self, image_path: str) -> int | None:
|
|
83
87
|
"""Return the acquisition id for the given image path."""
|
|
84
|
-
for images in self.images:
|
|
88
|
+
for images in self.well.images:
|
|
85
89
|
if images.path == image_path:
|
|
86
90
|
return images.acquisition
|
|
87
91
|
raise NgioValueError(f"Image at path {image_path} not found in the well.")
|
|
@@ -96,9 +100,11 @@ class NgioWellMeta(BaseModel):
|
|
|
96
100
|
acquisition (int | None): The acquisition id to filter the images.
|
|
97
101
|
"""
|
|
98
102
|
if acquisition is None:
|
|
99
|
-
return [images.path for images in self.images]
|
|
103
|
+
return [images.path for images in self.well.images]
|
|
100
104
|
return [
|
|
101
|
-
images.path
|
|
105
|
+
images.path
|
|
106
|
+
for images in self.well.images
|
|
107
|
+
if images.acquisition == acquisition
|
|
102
108
|
]
|
|
103
109
|
|
|
104
110
|
def add_image(
|
|
@@ -112,7 +118,7 @@ class NgioWellMeta(BaseModel):
|
|
|
112
118
|
strict (bool): If True, check if the image already exists in the well.
|
|
113
119
|
If False, do not check if the image already exists in the well.
|
|
114
120
|
"""
|
|
115
|
-
list_of_images = self.images
|
|
121
|
+
list_of_images = self.well.images
|
|
116
122
|
for image in list_of_images:
|
|
117
123
|
if image.path == path:
|
|
118
124
|
raise NgioValueError(
|
|
@@ -131,7 +137,9 @@ class NgioWellMeta(BaseModel):
|
|
|
131
137
|
|
|
132
138
|
new_image = CustomWellImage(path=path, acquisition=acquisition)
|
|
133
139
|
list_of_images.append(new_image)
|
|
134
|
-
return NgioWellMeta(
|
|
140
|
+
return NgioWellMeta(
|
|
141
|
+
well=CustomWellMeta(images=list_of_images, version=self.well.version)
|
|
142
|
+
)
|
|
135
143
|
|
|
136
144
|
def remove_image(self, path: str) -> "NgioWellMeta":
|
|
137
145
|
"""Remove an image from the well.
|
|
@@ -139,66 +147,35 @@ class NgioWellMeta(BaseModel):
|
|
|
139
147
|
Args:
|
|
140
148
|
path (str): The path of the image.
|
|
141
149
|
"""
|
|
142
|
-
list_of_images = self.images
|
|
150
|
+
list_of_images = self.well.images
|
|
143
151
|
for image in list_of_images:
|
|
144
152
|
if image.path == path:
|
|
145
153
|
list_of_images.remove(image)
|
|
146
|
-
return NgioWellMeta(
|
|
154
|
+
return NgioWellMeta(
|
|
155
|
+
well=CustomWellMeta(
|
|
156
|
+
images=list_of_images, version=self.well.version
|
|
157
|
+
)
|
|
158
|
+
)
|
|
147
159
|
raise NgioValueError(f"Image at path {path} not found in the well.")
|
|
148
160
|
|
|
149
161
|
|
|
150
|
-
def
|
|
151
|
-
"""Format the column as a string.
|
|
152
|
-
|
|
153
|
-
We make sure to pad the column with zeros
|
|
154
|
-
to have a consistent format.
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
column (int): The column to format.
|
|
158
|
-
num_digits (int): The number of digits to pad the column.
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
str: The column as a string.
|
|
162
|
-
"""
|
|
163
|
-
return f"{column:0{num_digits}d}"
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def _stringify_column(column: str | int, num_digits: int = 2) -> str:
|
|
162
|
+
def _stringify_column(column: str | int) -> str:
|
|
167
163
|
"""Convert the column to a string.
|
|
168
164
|
|
|
169
|
-
This will ensure that columns are always strings.
|
|
170
|
-
and will help with sorting and comparison.
|
|
171
|
-
|
|
172
165
|
Args:
|
|
173
166
|
column (str | int): The column to convert.
|
|
174
|
-
num_digits (int): The number of digits to pad the column.
|
|
175
167
|
|
|
176
168
|
Returns:
|
|
177
169
|
str: The column as a string.
|
|
178
170
|
"""
|
|
179
|
-
if isinstance(column,
|
|
180
|
-
return _format_int_column(column, num_digits=num_digits)
|
|
181
|
-
|
|
182
|
-
elif isinstance(column, str):
|
|
183
|
-
try:
|
|
184
|
-
column_int = int(column)
|
|
185
|
-
return _format_int_column(column_int, num_digits=num_digits)
|
|
186
|
-
except ValueError:
|
|
187
|
-
pass
|
|
171
|
+
if isinstance(column, str):
|
|
188
172
|
return column
|
|
189
|
-
raise NgioValueError(f"Column {column} must be a string or an integer.")
|
|
190
|
-
|
|
191
173
|
|
|
192
|
-
|
|
193
|
-
|
|
174
|
+
# Maybe we should pad the column with zeros
|
|
175
|
+
return str(column)
|
|
194
176
|
|
|
195
|
-
Args:
|
|
196
|
-
rows: List of row names.
|
|
197
|
-
row: The row name to find.
|
|
198
177
|
|
|
199
|
-
|
|
200
|
-
The index of the row, or None if not found.
|
|
201
|
-
"""
|
|
178
|
+
def _find_row_index(rows: list[str], row: str) -> int | None:
|
|
202
179
|
try:
|
|
203
180
|
return rows.index(row)
|
|
204
181
|
except ValueError:
|
|
@@ -206,17 +183,8 @@ def _find_row_index(rows: list[str], row: str) -> int | None:
|
|
|
206
183
|
|
|
207
184
|
|
|
208
185
|
def _find_column_index(columns: list[str], column: str | int) -> int | None:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
Args:
|
|
212
|
-
columns: List of column names.
|
|
213
|
-
column: The column name or number to find.
|
|
214
|
-
|
|
215
|
-
Returns:
|
|
216
|
-
The index of the column, or None if not found.
|
|
217
|
-
"""
|
|
218
|
-
_num_columns = [_stringify_column(columns) for columns in columns]
|
|
219
|
-
column = _stringify_column(column)
|
|
186
|
+
_num_columns = [int(columns) for columns in columns]
|
|
187
|
+
column = int(column)
|
|
220
188
|
try:
|
|
221
189
|
return _num_columns.index(column)
|
|
222
190
|
except ValueError:
|
|
@@ -226,16 +194,6 @@ def _find_column_index(columns: list[str], column: str | int) -> int | None:
|
|
|
226
194
|
def _relabel_wells(
|
|
227
195
|
wells: list[WellInPlate], rows: list[Row], columns: list[Column]
|
|
228
196
|
) -> list[WellInPlate]:
|
|
229
|
-
"""Relabel well indices after rows or columns have been added.
|
|
230
|
-
|
|
231
|
-
Args:
|
|
232
|
-
wells: List of wells to relabel.
|
|
233
|
-
rows: Updated list of rows.
|
|
234
|
-
columns: Updated list of columns.
|
|
235
|
-
|
|
236
|
-
Returns:
|
|
237
|
-
List of wells with updated row and column indices.
|
|
238
|
-
"""
|
|
239
197
|
new_wells = []
|
|
240
198
|
_rows = [row.name for row in rows]
|
|
241
199
|
_columns = [column.name for column in columns]
|
|
@@ -260,30 +218,26 @@ def _relabel_wells(
|
|
|
260
218
|
return new_wells
|
|
261
219
|
|
|
262
220
|
|
|
263
|
-
class NgioPlateMeta(
|
|
221
|
+
class NgioPlateMeta(HCSAttrs):
|
|
264
222
|
"""HCS plate metadata."""
|
|
265
223
|
|
|
266
|
-
plate: PlateWithVersion
|
|
267
|
-
version: NgffVersions
|
|
268
|
-
|
|
269
224
|
@classmethod
|
|
270
225
|
def default_init(
|
|
271
226
|
cls,
|
|
272
227
|
images: list[ImageInWellPath] | None = None,
|
|
273
228
|
name: str | None = None,
|
|
274
|
-
|
|
229
|
+
version: NgffVersions | None = None,
|
|
275
230
|
) -> "NgioPlateMeta":
|
|
276
231
|
plate = cls(
|
|
277
|
-
plate=
|
|
232
|
+
plate=Plate(
|
|
278
233
|
rows=[],
|
|
279
234
|
columns=[],
|
|
280
235
|
acquisitions=None,
|
|
281
236
|
wells=[],
|
|
282
237
|
field_count=None,
|
|
238
|
+
version=version,
|
|
283
239
|
name=name,
|
|
284
|
-
|
|
285
|
-
),
|
|
286
|
-
version=ngff_version,
|
|
240
|
+
)
|
|
287
241
|
)
|
|
288
242
|
|
|
289
243
|
if images is None:
|
|
@@ -340,8 +294,23 @@ class NgioPlateMeta(BaseModel):
|
|
|
340
294
|
Returns:
|
|
341
295
|
str: The path of the well.
|
|
342
296
|
"""
|
|
343
|
-
|
|
344
|
-
|
|
297
|
+
if row not in self.rows:
|
|
298
|
+
raise NgioValueError(
|
|
299
|
+
f"Row {row} not found in the plate. Available rows are {self.rows}."
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
row_idx = self.rows.index(row)
|
|
303
|
+
|
|
304
|
+
_num_columns = [int(columns) for columns in self.columns]
|
|
305
|
+
|
|
306
|
+
try:
|
|
307
|
+
_column = int(column)
|
|
308
|
+
except ValueError:
|
|
309
|
+
raise NgioValueError(
|
|
310
|
+
f"Column {column} must be an integer or convertible to an integer."
|
|
311
|
+
) from None
|
|
312
|
+
|
|
313
|
+
column_idx = _num_columns.index(_column)
|
|
345
314
|
|
|
346
315
|
for well in self.plate.wells:
|
|
347
316
|
if well.columnIndex == column_idx and well.rowIndex == row_idx:
|
|
@@ -377,16 +346,16 @@ class NgioPlateMeta(BaseModel):
|
|
|
377
346
|
else:
|
|
378
347
|
wells = self.plate.wells
|
|
379
348
|
|
|
380
|
-
new_plate =
|
|
349
|
+
new_plate = Plate(
|
|
381
350
|
rows=rows,
|
|
382
351
|
columns=self.plate.columns,
|
|
383
352
|
acquisitions=self.plate.acquisitions,
|
|
384
353
|
wells=wells,
|
|
385
354
|
field_count=self.plate.field_count,
|
|
386
355
|
name=self.plate.name,
|
|
387
|
-
version=self.version,
|
|
356
|
+
version=self.plate.version,
|
|
388
357
|
)
|
|
389
|
-
return NgioPlateMeta(plate=new_plate
|
|
358
|
+
return NgioPlateMeta(plate=new_plate), row_idx
|
|
390
359
|
|
|
391
360
|
def add_column(self, column: str | int) -> "tuple[NgioPlateMeta, int]":
|
|
392
361
|
"""Add a column to the plate.
|
|
@@ -404,7 +373,7 @@ class NgioPlateMeta(BaseModel):
|
|
|
404
373
|
|
|
405
374
|
columns_names.append(_stringify_column(column))
|
|
406
375
|
# sort as numbers
|
|
407
|
-
columns_names.sort(key=lambda x:
|
|
376
|
+
columns_names.sort(key=lambda x: int(x))
|
|
408
377
|
column_idx = columns_names.index(_stringify_column(column))
|
|
409
378
|
relabel_wells = True
|
|
410
379
|
|
|
@@ -415,30 +384,27 @@ class NgioPlateMeta(BaseModel):
|
|
|
415
384
|
else:
|
|
416
385
|
wells = self.plate.wells
|
|
417
386
|
|
|
418
|
-
new_plate =
|
|
387
|
+
new_plate = Plate(
|
|
419
388
|
rows=self.plate.rows,
|
|
420
389
|
columns=columns,
|
|
421
390
|
acquisitions=self.plate.acquisitions,
|
|
422
391
|
wells=wells,
|
|
423
392
|
field_count=self.plate.field_count,
|
|
424
393
|
name=self.plate.name,
|
|
425
|
-
version=self.version,
|
|
394
|
+
version=self.plate.version,
|
|
426
395
|
)
|
|
427
|
-
return NgioPlateMeta(plate=new_plate
|
|
396
|
+
return NgioPlateMeta(plate=new_plate), column_idx
|
|
428
397
|
|
|
429
398
|
def add_well(
|
|
430
399
|
self,
|
|
431
400
|
row: str,
|
|
432
401
|
column: str | int,
|
|
433
402
|
) -> "NgioPlateMeta":
|
|
434
|
-
"""Add
|
|
403
|
+
"""Add an image to the well.
|
|
435
404
|
|
|
436
405
|
Args:
|
|
437
406
|
row (str): The row of the well.
|
|
438
407
|
column (str | int): The column of the well.
|
|
439
|
-
|
|
440
|
-
Returns:
|
|
441
|
-
NgioPlateMeta: Updated plate metadata with the new well.
|
|
442
408
|
"""
|
|
443
409
|
plate, row_idx = self.add_row(row=row)
|
|
444
410
|
plate, column_idx = plate.add_column(column=column)
|
|
@@ -456,16 +422,16 @@ class NgioPlateMeta(BaseModel):
|
|
|
456
422
|
)
|
|
457
423
|
)
|
|
458
424
|
|
|
459
|
-
new_plate =
|
|
425
|
+
new_plate = Plate(
|
|
460
426
|
rows=plate.plate.rows,
|
|
461
427
|
columns=plate.plate.columns,
|
|
462
428
|
acquisitions=plate.plate.acquisitions,
|
|
463
429
|
wells=wells,
|
|
464
430
|
field_count=plate.plate.field_count,
|
|
465
431
|
name=plate.plate.name,
|
|
466
|
-
version=plate.version,
|
|
432
|
+
version=plate.plate.version,
|
|
467
433
|
)
|
|
468
|
-
return NgioPlateMeta(plate=new_plate
|
|
434
|
+
return NgioPlateMeta(plate=new_plate)
|
|
469
435
|
|
|
470
436
|
def add_acquisition(
|
|
471
437
|
self,
|
|
@@ -495,16 +461,16 @@ class NgioPlateMeta(BaseModel):
|
|
|
495
461
|
Acquisition(id=acquisition_id, name=acquisition_name, **acquisition_kwargs)
|
|
496
462
|
)
|
|
497
463
|
|
|
498
|
-
new_plate =
|
|
464
|
+
new_plate = Plate(
|
|
499
465
|
rows=self.plate.rows,
|
|
500
466
|
columns=self.plate.columns,
|
|
501
467
|
acquisitions=acquisitions,
|
|
502
468
|
wells=self.plate.wells,
|
|
503
469
|
field_count=self.plate.field_count,
|
|
504
470
|
name=self.plate.name,
|
|
505
|
-
version=self.version,
|
|
471
|
+
version=self.plate.version,
|
|
506
472
|
)
|
|
507
|
-
return NgioPlateMeta(plate=new_plate
|
|
473
|
+
return NgioPlateMeta(plate=new_plate)
|
|
508
474
|
|
|
509
475
|
def remove_well(self, row: str, column: str | int) -> "NgioPlateMeta":
|
|
510
476
|
"""Remove a well from the plate.
|
|
@@ -531,33 +497,30 @@ class NgioPlateMeta(BaseModel):
|
|
|
531
497
|
f"Well at row {row} and column {column} not found in the plate."
|
|
532
498
|
)
|
|
533
499
|
|
|
534
|
-
new_plate =
|
|
500
|
+
new_plate = Plate(
|
|
535
501
|
rows=self.plate.rows,
|
|
536
502
|
columns=self.plate.columns,
|
|
537
503
|
acquisitions=self.plate.acquisitions,
|
|
538
504
|
wells=wells,
|
|
539
505
|
field_count=self.plate.field_count,
|
|
540
506
|
name=self.plate.name,
|
|
541
|
-
version=self.version,
|
|
507
|
+
version=self.plate.version,
|
|
542
508
|
)
|
|
543
|
-
return NgioPlateMeta(plate=new_plate
|
|
509
|
+
return NgioPlateMeta(plate=new_plate)
|
|
544
510
|
|
|
545
511
|
def derive(
|
|
546
512
|
self,
|
|
547
513
|
name: str | None = None,
|
|
548
|
-
|
|
514
|
+
version: NgffVersions | None = None,
|
|
549
515
|
keep_acquisitions: bool = False,
|
|
550
516
|
) -> "NgioPlateMeta":
|
|
551
517
|
"""Derive the plate metadata.
|
|
552
518
|
|
|
553
519
|
Args:
|
|
554
|
-
name (str
|
|
555
|
-
|
|
520
|
+
name (str): The name of the derived plate.
|
|
521
|
+
version (NgffVersion | None): The version of the derived plate.
|
|
556
522
|
If None, use the version of the original plate.
|
|
557
523
|
keep_acquisitions (bool): If True, keep the acquisitions in the plate.
|
|
558
|
-
|
|
559
|
-
Returns:
|
|
560
|
-
NgioPlateMeta: The derived plate metadata.
|
|
561
524
|
"""
|
|
562
525
|
columns = self.plate.columns
|
|
563
526
|
rows = self.plate.rows
|
|
@@ -567,18 +530,17 @@ class NgioPlateMeta(BaseModel):
|
|
|
567
530
|
else:
|
|
568
531
|
acquisitions = None
|
|
569
532
|
|
|
570
|
-
if
|
|
571
|
-
|
|
533
|
+
if version is None:
|
|
534
|
+
version = self.plate.version # type: ignore (version is NgffVersions or None)
|
|
572
535
|
|
|
573
536
|
return NgioPlateMeta(
|
|
574
|
-
plate=
|
|
537
|
+
plate=Plate(
|
|
575
538
|
rows=rows,
|
|
576
539
|
columns=columns,
|
|
577
540
|
acquisitions=acquisitions,
|
|
578
541
|
wells=[],
|
|
579
542
|
field_count=self.plate.field_count,
|
|
543
|
+
version=version,
|
|
580
544
|
name=name,
|
|
581
|
-
|
|
582
|
-
),
|
|
583
|
-
version=ngff_version,
|
|
545
|
+
)
|
|
584
546
|
)
|
|
@@ -13,11 +13,11 @@ import numpy as np
|
|
|
13
13
|
from pydantic import BaseModel
|
|
14
14
|
|
|
15
15
|
from ngio.ome_zarr_meta.ngio_specs._axes import (
|
|
16
|
-
AxesHandler,
|
|
17
16
|
DefaultSpaceUnit,
|
|
18
17
|
DefaultTimeUnit,
|
|
19
18
|
SpaceUnits,
|
|
20
19
|
TimeUnits,
|
|
20
|
+
build_canonical_axes_handler,
|
|
21
21
|
)
|
|
22
22
|
from ngio.ome_zarr_meta.ngio_specs._channels import ChannelsMeta
|
|
23
23
|
from ngio.ome_zarr_meta.ngio_specs._dataset import Dataset
|
|
@@ -41,13 +41,6 @@ class ImageLabelSource(BaseModel):
|
|
|
41
41
|
return cls(version=version, source={"image": "../../"})
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
class NgioLabelsGroupMeta(BaseModel):
|
|
45
|
-
"""Metadata model for the /labels group in OME-NGFF."""
|
|
46
|
-
|
|
47
|
-
version: NgffVersions
|
|
48
|
-
labels: list[str]
|
|
49
|
-
|
|
50
|
-
|
|
51
44
|
class AbstractNgioImageMeta:
|
|
52
45
|
"""Base class for ImageMeta and LabelMeta."""
|
|
53
46
|
|
|
@@ -73,23 +66,42 @@ class AbstractNgioImageMeta:
|
|
|
73
66
|
@classmethod
|
|
74
67
|
def default_init(
|
|
75
68
|
cls,
|
|
76
|
-
levels: Sequence[str],
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
levels: int | Sequence[str],
|
|
70
|
+
axes_names: Sequence[str],
|
|
71
|
+
pixel_size: PixelSize,
|
|
72
|
+
scaling_factors: Sequence[float] | None = None,
|
|
80
73
|
name: str | None = None,
|
|
81
74
|
version: NgffVersions = DefaultNgffVersion,
|
|
82
75
|
):
|
|
83
76
|
"""Initialize the ImageMeta object."""
|
|
77
|
+
axes_handler = build_canonical_axes_handler(
|
|
78
|
+
axes_names,
|
|
79
|
+
space_units=pixel_size.space_unit,
|
|
80
|
+
time_units=pixel_size.time_unit,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
px_size_dict = pixel_size.as_dict()
|
|
84
|
+
scale = [px_size_dict.get(name, 1.0) for name in axes_handler.axes_names]
|
|
85
|
+
|
|
86
|
+
if scaling_factors is None:
|
|
87
|
+
_default = {"x": 2.0, "y": 2.0}
|
|
88
|
+
scaling_factors = [
|
|
89
|
+
_default.get(name, 1.0) for name in axes_handler.axes_names
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
if isinstance(levels, int):
|
|
93
|
+
levels = [str(i) for i in range(levels)]
|
|
94
|
+
|
|
84
95
|
datasets = []
|
|
85
|
-
for level
|
|
96
|
+
for level in levels:
|
|
86
97
|
dataset = Dataset(
|
|
87
98
|
path=level,
|
|
88
99
|
axes_handler=axes_handler,
|
|
89
100
|
scale=scale,
|
|
90
|
-
translation=
|
|
101
|
+
translation=None,
|
|
91
102
|
)
|
|
92
103
|
datasets.append(dataset)
|
|
104
|
+
scale = [s * f for s, f in zip(scale, scaling_factors, strict=True)]
|
|
93
105
|
|
|
94
106
|
return cls(
|
|
95
107
|
version=version,
|
|
@@ -129,42 +141,6 @@ class AbstractNgioImageMeta:
|
|
|
129
141
|
datasets=new_datasets,
|
|
130
142
|
)
|
|
131
143
|
|
|
132
|
-
def rename_axes(self, axes_names: Sequence[str]):
|
|
133
|
-
"""Rename axes in the metadata.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
axes_names(Sequence[str]): The new axes names in the order of the current
|
|
137
|
-
axes.
|
|
138
|
-
"""
|
|
139
|
-
new_axes_handler = self.axes_handler.rename_axes(axes_names=axes_names)
|
|
140
|
-
new_datasets = []
|
|
141
|
-
for dataset in self.datasets:
|
|
142
|
-
new_dataset = Dataset(
|
|
143
|
-
path=dataset.path,
|
|
144
|
-
axes_handler=new_axes_handler,
|
|
145
|
-
scale=dataset.scale,
|
|
146
|
-
translation=dataset.translation,
|
|
147
|
-
)
|
|
148
|
-
new_datasets.append(new_dataset)
|
|
149
|
-
|
|
150
|
-
return type(self)(
|
|
151
|
-
version=self.version,
|
|
152
|
-
name=self.name,
|
|
153
|
-
datasets=new_datasets,
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
def rename_image(self, name: str):
|
|
157
|
-
"""Rename the image in the metadata.
|
|
158
|
-
|
|
159
|
-
Args:
|
|
160
|
-
name(str): The new name of the image.
|
|
161
|
-
"""
|
|
162
|
-
return type(self)(
|
|
163
|
-
version=self.version,
|
|
164
|
-
name=name,
|
|
165
|
-
datasets=self.datasets,
|
|
166
|
-
)
|
|
167
|
-
|
|
168
144
|
@property
|
|
169
145
|
def version(self) -> NgffVersions:
|
|
170
146
|
"""Version of the OME-NFF metadata used to build the object."""
|
|
@@ -361,15 +337,50 @@ class AbstractNgioImageMeta:
|
|
|
361
337
|
)
|
|
362
338
|
return dataset, lr_dataset
|
|
363
339
|
|
|
364
|
-
def scaling_factor(self, path: str | None = None) ->
|
|
365
|
-
"""Get the scaling factors
|
|
340
|
+
def scaling_factor(self, path: str | None = None) -> list[float]:
|
|
341
|
+
"""Get the scaling factors from a dataset to its lower resolution."""
|
|
342
|
+
if self.levels == 1:
|
|
343
|
+
return [1.0] * len(self.axes_handler.axes_names)
|
|
344
|
+
dataset, lr_dataset = self._get_closest_datasets(path=path)
|
|
345
|
+
|
|
346
|
+
scaling_factors = []
|
|
347
|
+
for ax_name in self.axes_handler.axes_names:
|
|
348
|
+
s_d = dataset.get_scale(ax_name)
|
|
349
|
+
s_lr_d = lr_dataset.get_scale(ax_name)
|
|
350
|
+
scaling_factors.append(s_lr_d / s_d)
|
|
351
|
+
return scaling_factors
|
|
352
|
+
|
|
353
|
+
def yx_scaling(self, path: str | None = None) -> tuple[float, float]:
|
|
354
|
+
"""Get the scaling factor from a dataset to its lower resolution."""
|
|
366
355
|
if self.levels == 1:
|
|
367
|
-
return
|
|
356
|
+
return 1.0, 1.0
|
|
368
357
|
dataset, lr_dataset = self._get_closest_datasets(path=path)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
358
|
+
|
|
359
|
+
if lr_dataset is None:
|
|
360
|
+
raise NgioValueError(
|
|
361
|
+
"No lower resolution dataset found. "
|
|
362
|
+
"This is the lowest resolution dataset."
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
s_d = dataset.get_scale("y")
|
|
366
|
+
s_lr_d = lr_dataset.get_scale("y")
|
|
367
|
+
scale_y = s_lr_d / s_d
|
|
368
|
+
|
|
369
|
+
s_d = dataset.get_scale("x")
|
|
370
|
+
s_lr_d = lr_dataset.get_scale("x")
|
|
371
|
+
scale_x = s_lr_d / s_d
|
|
372
|
+
|
|
373
|
+
return scale_y, scale_x
|
|
374
|
+
|
|
375
|
+
def z_scaling(self, path: str | None = None) -> float:
|
|
376
|
+
"""Get the scaling factor from a dataset to its lower resolution."""
|
|
377
|
+
if self.levels == 1:
|
|
378
|
+
return 1.0
|
|
379
|
+
dataset, lr_dataset = self._get_closest_datasets(path=path)
|
|
380
|
+
|
|
381
|
+
s_d = dataset.get_scale("z", default=1.0)
|
|
382
|
+
s_lr_d = lr_dataset.get_scale("z", default=1.0)
|
|
383
|
+
return s_lr_d / s_d
|
|
373
384
|
|
|
374
385
|
|
|
375
386
|
class NgioLabelMeta(AbstractNgioImageMeta):
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
"""Utility to read/write OME-Zarr metadata v0.4."""
|
|
2
2
|
|
|
3
|
-
from ngio.ome_zarr_meta.v04.
|
|
3
|
+
from ngio.ome_zarr_meta.v04._v04_spec_utils import (
|
|
4
4
|
ngio_to_v04_image_meta,
|
|
5
5
|
ngio_to_v04_label_meta,
|
|
6
|
-
ngio_to_v04_labels_group_meta,
|
|
7
6
|
ngio_to_v04_plate_meta,
|
|
8
7
|
ngio_to_v04_well_meta,
|
|
9
8
|
v04_to_ngio_image_meta,
|
|
10
9
|
v04_to_ngio_label_meta,
|
|
11
|
-
v04_to_ngio_labels_group_meta,
|
|
12
10
|
v04_to_ngio_plate_meta,
|
|
13
11
|
v04_to_ngio_well_meta,
|
|
14
12
|
)
|
|
@@ -16,12 +14,10 @@ from ngio.ome_zarr_meta.v04._v04_spec import (
|
|
|
16
14
|
__all__ = [
|
|
17
15
|
"ngio_to_v04_image_meta",
|
|
18
16
|
"ngio_to_v04_label_meta",
|
|
19
|
-
"ngio_to_v04_labels_group_meta",
|
|
20
17
|
"ngio_to_v04_plate_meta",
|
|
21
18
|
"ngio_to_v04_well_meta",
|
|
22
19
|
"v04_to_ngio_image_meta",
|
|
23
20
|
"v04_to_ngio_label_meta",
|
|
24
|
-
"v04_to_ngio_labels_group_meta",
|
|
25
21
|
"v04_to_ngio_plate_meta",
|
|
26
22
|
"v04_to_ngio_well_meta",
|
|
27
23
|
]
|