ngio 0.5.0b6__py3-none-any.whl → 0.5.1__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/_masking_roi.py +18 -5
- ngio/common/_pyramid.py +129 -30
- ngio/hcs/_plate.py +30 -24
- ngio/images/_abstract_image.py +182 -60
- ngio/images/_create_synt_container.py +5 -1
- ngio/images/_create_utils.py +69 -74
- ngio/images/_image.py +350 -86
- ngio/images/_label.py +39 -31
- ngio/images/_masked_image.py +2 -2
- ngio/images/_ome_zarr_container.py +263 -96
- ngio/io_pipes/_match_shape.py +10 -14
- ngio/io_pipes/_ops_slices.py +6 -4
- ngio/io_pipes/_ops_slices_utils.py +8 -7
- ngio/ome_zarr_meta/_meta_handlers.py +2 -26
- ngio/ome_zarr_meta/ngio_specs/__init__.py +2 -0
- ngio/ome_zarr_meta/ngio_specs/_axes.py +161 -58
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +78 -32
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +36 -0
- ngio/ome_zarr_meta/v04/_v04_spec.py +5 -22
- ngio/ome_zarr_meta/v05/_v05_spec.py +7 -23
- ngio/resources/__init__.py +1 -1
- ngio/resources/resource_model.py +1 -1
- ngio/tables/_tables_container.py +39 -7
- ngio/tables/v1/_roi_table.py +4 -4
- ngio/utils/_zarr_utils.py +8 -15
- {ngio-0.5.0b6.dist-info → ngio-0.5.1.dist-info}/METADATA +3 -2
- {ngio-0.5.0b6.dist-info → ngio-0.5.1.dist-info}/RECORD +29 -29
- {ngio-0.5.0b6.dist-info → ngio-0.5.1.dist-info}/WHEEL +0 -0
- {ngio-0.5.0b6.dist-info → ngio-0.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""HCS (High Content Screening) specific metadata classes for NGIO."""
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import logging
|
|
4
4
|
from typing import Annotated
|
|
5
5
|
|
|
6
6
|
from ome_zarr_models.common.plate import (
|
|
@@ -16,16 +16,17 @@ from pydantic import BaseModel, SkipValidation, field_serializer
|
|
|
16
16
|
from ngio.ome_zarr_meta.ngio_specs._ngio_image import DefaultNgffVersion, NgffVersions
|
|
17
17
|
from ngio.utils import NgioValueError
|
|
18
18
|
|
|
19
|
+
logger = logging.getLogger(f"ngio:{__name__}")
|
|
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
|
+
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
|
|
|
@@ -147,23 +148,58 @@ class NgioWellMeta(BaseModel):
|
|
|
147
148
|
raise NgioValueError(f"Image at path {path} not found in the well.")
|
|
148
149
|
|
|
149
150
|
|
|
150
|
-
def
|
|
151
|
+
def _format_int_column(column: int, num_digits: int = 2) -> str:
|
|
152
|
+
"""Format the column as a string.
|
|
153
|
+
|
|
154
|
+
We make sure to pad the column with zeros
|
|
155
|
+
to have a consistent format.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
column (int): The column to format.
|
|
159
|
+
num_digits (int): The number of digits to pad the column.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
str: The column as a string.
|
|
163
|
+
"""
|
|
164
|
+
return f"{column:0{num_digits}d}"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _stringify_column(column: str | int, num_digits: int = 2) -> str:
|
|
151
168
|
"""Convert the column to a string.
|
|
152
169
|
|
|
170
|
+
This will ensure that columns are always strings.
|
|
171
|
+
and will help with sorting and comparison.
|
|
172
|
+
|
|
153
173
|
Args:
|
|
154
174
|
column (str | int): The column to convert.
|
|
175
|
+
num_digits (int): The number of digits to pad the column.
|
|
155
176
|
|
|
156
177
|
Returns:
|
|
157
178
|
str: The column as a string.
|
|
158
179
|
"""
|
|
159
|
-
if isinstance(column,
|
|
160
|
-
return column
|
|
180
|
+
if isinstance(column, int):
|
|
181
|
+
return _format_int_column(column, num_digits=num_digits)
|
|
161
182
|
|
|
162
|
-
|
|
163
|
-
|
|
183
|
+
elif isinstance(column, str):
|
|
184
|
+
try:
|
|
185
|
+
column_int = int(column)
|
|
186
|
+
return _format_int_column(column_int, num_digits=num_digits)
|
|
187
|
+
except ValueError:
|
|
188
|
+
pass
|
|
189
|
+
return column
|
|
190
|
+
raise NgioValueError(f"Column {column} must be a string or an integer.")
|
|
164
191
|
|
|
165
192
|
|
|
166
193
|
def _find_row_index(rows: list[str], row: str) -> int | None:
|
|
194
|
+
"""Find the index of a row in the list of rows.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
rows: List of row names.
|
|
198
|
+
row: The row name to find.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
The index of the row, or None if not found.
|
|
202
|
+
"""
|
|
167
203
|
try:
|
|
168
204
|
return rows.index(row)
|
|
169
205
|
except ValueError:
|
|
@@ -171,8 +207,17 @@ def _find_row_index(rows: list[str], row: str) -> int | None:
|
|
|
171
207
|
|
|
172
208
|
|
|
173
209
|
def _find_column_index(columns: list[str], column: str | int) -> int | None:
|
|
174
|
-
|
|
175
|
-
|
|
210
|
+
"""Find the index of a column in the list of columns.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
columns: List of column names.
|
|
214
|
+
column: The column name or number to find.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
The index of the column, or None if not found.
|
|
218
|
+
"""
|
|
219
|
+
_num_columns = [_stringify_column(columns) for columns in columns]
|
|
220
|
+
column = _stringify_column(column)
|
|
176
221
|
try:
|
|
177
222
|
return _num_columns.index(column)
|
|
178
223
|
except ValueError:
|
|
@@ -182,6 +227,16 @@ def _find_column_index(columns: list[str], column: str | int) -> int | None:
|
|
|
182
227
|
def _relabel_wells(
|
|
183
228
|
wells: list[WellInPlate], rows: list[Row], columns: list[Column]
|
|
184
229
|
) -> list[WellInPlate]:
|
|
230
|
+
"""Relabel well indices after rows or columns have been added.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
wells: List of wells to relabel.
|
|
234
|
+
rows: Updated list of rows.
|
|
235
|
+
columns: Updated list of columns.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
List of wells with updated row and column indices.
|
|
239
|
+
"""
|
|
185
240
|
new_wells = []
|
|
186
241
|
_rows = [row.name for row in rows]
|
|
187
242
|
_columns = [column.name for column in columns]
|
|
@@ -286,23 +341,8 @@ class NgioPlateMeta(BaseModel):
|
|
|
286
341
|
Returns:
|
|
287
342
|
str: The path of the well.
|
|
288
343
|
"""
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
f"Row {row} not found in the plate. Available rows are {self.rows}."
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
row_idx = self.rows.index(row)
|
|
295
|
-
|
|
296
|
-
_num_columns = [int(columns) for columns in self.columns]
|
|
297
|
-
|
|
298
|
-
try:
|
|
299
|
-
_column = int(column)
|
|
300
|
-
except ValueError:
|
|
301
|
-
raise NgioValueError(
|
|
302
|
-
f"Column {column} must be an integer or convertible to an integer."
|
|
303
|
-
) from None
|
|
304
|
-
|
|
305
|
-
column_idx = _num_columns.index(_column)
|
|
344
|
+
row_idx = _find_row_index(self.rows, row)
|
|
345
|
+
column_idx = _find_column_index(self.columns, column)
|
|
306
346
|
|
|
307
347
|
for well in self.plate.wells:
|
|
308
348
|
if well.columnIndex == column_idx and well.rowIndex == row_idx:
|
|
@@ -365,7 +405,7 @@ class NgioPlateMeta(BaseModel):
|
|
|
365
405
|
|
|
366
406
|
columns_names.append(_stringify_column(column))
|
|
367
407
|
# sort as numbers
|
|
368
|
-
columns_names.sort(key=lambda x:
|
|
408
|
+
columns_names.sort(key=lambda x: _stringify_column(x))
|
|
369
409
|
column_idx = columns_names.index(_stringify_column(column))
|
|
370
410
|
relabel_wells = True
|
|
371
411
|
|
|
@@ -392,11 +432,14 @@ class NgioPlateMeta(BaseModel):
|
|
|
392
432
|
row: str,
|
|
393
433
|
column: str | int,
|
|
394
434
|
) -> "NgioPlateMeta":
|
|
395
|
-
"""Add
|
|
435
|
+
"""Add a well to the plate.
|
|
396
436
|
|
|
397
437
|
Args:
|
|
398
438
|
row (str): The row of the well.
|
|
399
439
|
column (str | int): The column of the well.
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
NgioPlateMeta: Updated plate metadata with the new well.
|
|
400
443
|
"""
|
|
401
444
|
plate, row_idx = self.add_row(row=row)
|
|
402
445
|
plate, column_idx = plate.add_column(column=column)
|
|
@@ -509,10 +552,13 @@ class NgioPlateMeta(BaseModel):
|
|
|
509
552
|
"""Derive the plate metadata.
|
|
510
553
|
|
|
511
554
|
Args:
|
|
512
|
-
name (str): The name of the derived plate.
|
|
513
|
-
ngff_version (
|
|
555
|
+
name (str | None): The name of the derived plate.
|
|
556
|
+
ngff_version (NgffVersions | None): The version of the derived plate.
|
|
514
557
|
If None, use the version of the original plate.
|
|
515
558
|
keep_acquisitions (bool): If True, keep the acquisitions in the plate.
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
NgioPlateMeta: The derived plate metadata.
|
|
516
562
|
"""
|
|
517
563
|
columns = self.plate.columns
|
|
518
564
|
rows = self.plate.rows
|
|
@@ -129,6 +129,42 @@ class AbstractNgioImageMeta:
|
|
|
129
129
|
datasets=new_datasets,
|
|
130
130
|
)
|
|
131
131
|
|
|
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
|
+
|
|
132
168
|
@property
|
|
133
169
|
def version(self) -> NgffVersions:
|
|
134
170
|
"""Version of the OME-NFF metadata used to build the object."""
|
|
@@ -9,6 +9,9 @@ For Images and Labels implements the following functionalities:
|
|
|
9
9
|
- A function to convert a ngio image metadata to a v04 image metadata.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
from ome_zarr_models.common.coordinate_transformations import (
|
|
13
|
+
ValidTransform as ValidTransformV04,
|
|
14
|
+
)
|
|
12
15
|
from ome_zarr_models.v04.axes import Axis as AxisV04
|
|
13
16
|
from ome_zarr_models.v04.coordinate_transformations import VectorScale as VectorScaleV04
|
|
14
17
|
from ome_zarr_models.v04.coordinate_transformations import (
|
|
@@ -20,7 +23,6 @@ from ome_zarr_models.v04.image_label import ImageLabelAttrs as ImageLabelAttrsV0
|
|
|
20
23
|
from ome_zarr_models.v04.labels import LabelsAttrs as LabelsAttrsV04
|
|
21
24
|
from ome_zarr_models.v04.multiscales import Dataset as DatasetV04
|
|
22
25
|
from ome_zarr_models.v04.multiscales import Multiscale as MultiscaleV04
|
|
23
|
-
from ome_zarr_models.v04.multiscales import ValidTransform as ValidTransformV04
|
|
24
26
|
from ome_zarr_models.v04.omero import Channel as ChannelV04
|
|
25
27
|
from ome_zarr_models.v04.omero import Omero as OmeroV04
|
|
26
28
|
from ome_zarr_models.v04.omero import Window as WindowV04
|
|
@@ -117,8 +119,6 @@ def _compute_scale_translation(
|
|
|
117
119
|
def _v04_to_ngio_datasets(
|
|
118
120
|
v04_multiscale: MultiscaleV04,
|
|
119
121
|
axes_setup: AxesSetup,
|
|
120
|
-
allow_non_canonical_axes: bool = False,
|
|
121
|
-
strict_canonical_order: bool = True,
|
|
122
122
|
) -> list[Dataset]:
|
|
123
123
|
"""Convert a v04 multiscale to a list of ngio datasets."""
|
|
124
124
|
datasets = []
|
|
@@ -149,8 +149,6 @@ def _v04_to_ngio_datasets(
|
|
|
149
149
|
axes_handler = AxesHandler(
|
|
150
150
|
axes=axes,
|
|
151
151
|
axes_setup=axes_setup,
|
|
152
|
-
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
153
|
-
strict_canonical_order=strict_canonical_order,
|
|
154
152
|
)
|
|
155
153
|
|
|
156
154
|
for v04_dataset in v04_multiscale.datasets:
|
|
@@ -170,9 +168,7 @@ def _v04_to_ngio_datasets(
|
|
|
170
168
|
|
|
171
169
|
def v04_to_ngio_image_meta(
|
|
172
170
|
metadata: dict,
|
|
173
|
-
axes_setup: AxesSetup
|
|
174
|
-
allow_non_canonical_axes: bool = False,
|
|
175
|
-
strict_canonical_order: bool = True,
|
|
171
|
+
axes_setup: AxesSetup,
|
|
176
172
|
) -> NgioImageMeta:
|
|
177
173
|
"""Convert a v04 image metadata to a ngio image metadata.
|
|
178
174
|
|
|
@@ -180,8 +176,6 @@ def v04_to_ngio_image_meta(
|
|
|
180
176
|
metadata (dict): The v04 image metadata.
|
|
181
177
|
axes_setup (AxesSetup, optional): The axes setup. This is
|
|
182
178
|
required to convert image with non-canonical axes names.
|
|
183
|
-
allow_non_canonical_axes (bool, optional): Allow non-canonical axes.
|
|
184
|
-
strict_canonical_order (bool, optional): Strict canonical order.
|
|
185
179
|
|
|
186
180
|
Returns:
|
|
187
181
|
NgioImageMeta: The ngio image metadata.
|
|
@@ -196,12 +190,9 @@ def v04_to_ngio_image_meta(
|
|
|
196
190
|
v04_muliscale = v04_image.multiscales[0]
|
|
197
191
|
|
|
198
192
|
channels_meta = _v04_omero_to_channels(v04_image.omero)
|
|
199
|
-
axes_setup = axes_setup if axes_setup is not None else AxesSetup()
|
|
200
193
|
datasets = _v04_to_ngio_datasets(
|
|
201
194
|
v04_muliscale,
|
|
202
195
|
axes_setup=axes_setup,
|
|
203
|
-
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
204
|
-
strict_canonical_order=strict_canonical_order,
|
|
205
196
|
)
|
|
206
197
|
|
|
207
198
|
name = v04_muliscale.name
|
|
@@ -217,9 +208,7 @@ def v04_to_ngio_image_meta(
|
|
|
217
208
|
|
|
218
209
|
def v04_to_ngio_label_meta(
|
|
219
210
|
metadata: dict,
|
|
220
|
-
axes_setup: AxesSetup
|
|
221
|
-
allow_non_canonical_axes: bool = False,
|
|
222
|
-
strict_canonical_order: bool = True,
|
|
211
|
+
axes_setup: AxesSetup,
|
|
223
212
|
) -> NgioLabelMeta:
|
|
224
213
|
"""Convert a v04 image metadata to a ngio image metadata.
|
|
225
214
|
|
|
@@ -227,8 +216,6 @@ def v04_to_ngio_label_meta(
|
|
|
227
216
|
metadata (dict): The v04 image metadata.
|
|
228
217
|
axes_setup (AxesSetup, optional): The axes setup. This is
|
|
229
218
|
required to convert image with non-canonical axes names.
|
|
230
|
-
allow_non_canonical_axes (bool, optional): Allow non-canonical axes.
|
|
231
|
-
strict_canonical_order (bool, optional): Strict canonical order.
|
|
232
219
|
|
|
233
220
|
Returns:
|
|
234
221
|
NgioImageMeta: The ngio image metadata.
|
|
@@ -241,13 +228,9 @@ def v04_to_ngio_label_meta(
|
|
|
241
228
|
)
|
|
242
229
|
|
|
243
230
|
v04_muliscale = v04_label.multiscales[0]
|
|
244
|
-
|
|
245
|
-
axes_setup = axes_setup if axes_setup is not None else AxesSetup()
|
|
246
231
|
datasets = _v04_to_ngio_datasets(
|
|
247
232
|
v04_muliscale,
|
|
248
233
|
axes_setup=axes_setup,
|
|
249
|
-
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
250
|
-
strict_canonical_order=strict_canonical_order,
|
|
251
234
|
)
|
|
252
235
|
|
|
253
236
|
source = v04_label.image_label.source
|
|
@@ -9,6 +9,9 @@ For Images and Labels implements the following functionalities:
|
|
|
9
9
|
- A function to convert a ngio image metadata to a v05 image metadata.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
from ome_zarr_models.common.coordinate_transformations import (
|
|
13
|
+
ValidTransform as ValidTransformV05,
|
|
14
|
+
)
|
|
12
15
|
from ome_zarr_models.common.omero import Channel as ChannelV05
|
|
13
16
|
from ome_zarr_models.common.omero import Omero as OmeroV05
|
|
14
17
|
from ome_zarr_models.common.omero import Window as WindowV05
|
|
@@ -24,7 +27,6 @@ from ome_zarr_models.v05.labels import Labels as Labels
|
|
|
24
27
|
from ome_zarr_models.v05.labels import LabelsAttrs as LabelsAttrsV05
|
|
25
28
|
from ome_zarr_models.v05.multiscales import Dataset as DatasetV05
|
|
26
29
|
from ome_zarr_models.v05.multiscales import Multiscale as MultiscaleV05
|
|
27
|
-
from ome_zarr_models.v05.multiscales import ValidTransform as ValidTransformV05
|
|
28
30
|
from pydantic import BaseModel
|
|
29
31
|
|
|
30
32
|
from ngio.ome_zarr_meta.ngio_specs import (
|
|
@@ -131,8 +133,6 @@ def _compute_scale_translation(
|
|
|
131
133
|
def _v05_to_ngio_datasets(
|
|
132
134
|
v05_multiscale: MultiscaleV05,
|
|
133
135
|
axes_setup: AxesSetup,
|
|
134
|
-
allow_non_canonical_axes: bool = False,
|
|
135
|
-
strict_canonical_order: bool = True,
|
|
136
136
|
) -> list[Dataset]:
|
|
137
137
|
"""Convert a v05 multiscale to a list of ngio datasets."""
|
|
138
138
|
datasets = []
|
|
@@ -163,8 +163,6 @@ def _v05_to_ngio_datasets(
|
|
|
163
163
|
axes_handler = AxesHandler(
|
|
164
164
|
axes=axes,
|
|
165
165
|
axes_setup=axes_setup,
|
|
166
|
-
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
167
|
-
strict_canonical_order=strict_canonical_order,
|
|
168
166
|
)
|
|
169
167
|
|
|
170
168
|
for v05_dataset in v05_multiscale.datasets:
|
|
@@ -184,18 +182,14 @@ def _v05_to_ngio_datasets(
|
|
|
184
182
|
|
|
185
183
|
def v05_to_ngio_image_meta(
|
|
186
184
|
metadata: dict,
|
|
187
|
-
axes_setup: AxesSetup
|
|
188
|
-
allow_non_canonical_axes: bool = False,
|
|
189
|
-
strict_canonical_order: bool = True,
|
|
185
|
+
axes_setup: AxesSetup,
|
|
190
186
|
) -> NgioImageMeta:
|
|
191
187
|
"""Convert a v05 image metadata to a ngio image metadata.
|
|
192
188
|
|
|
193
189
|
Args:
|
|
194
190
|
metadata (dict): The v05 image metadata.
|
|
195
|
-
axes_setup (AxesSetup
|
|
191
|
+
axes_setup (AxesSetup): The axes setup. This is
|
|
196
192
|
required to convert image with non-canonical axes names.
|
|
197
|
-
allow_non_canonical_axes (bool, optional): Allow non-canonical axes.
|
|
198
|
-
strict_canonical_order (bool, optional): Strict canonical order.
|
|
199
193
|
|
|
200
194
|
Returns:
|
|
201
195
|
NgioImageMeta: The ngio image metadata.
|
|
@@ -210,12 +204,9 @@ def v05_to_ngio_image_meta(
|
|
|
210
204
|
v05_multiscale = v05_image.multiscales[0]
|
|
211
205
|
|
|
212
206
|
channels_meta = _v05_omero_to_channels(v05_image.omero)
|
|
213
|
-
axes_setup = axes_setup if axes_setup is not None else AxesSetup()
|
|
214
207
|
datasets = _v05_to_ngio_datasets(
|
|
215
208
|
v05_multiscale,
|
|
216
209
|
axes_setup=axes_setup,
|
|
217
|
-
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
218
|
-
strict_canonical_order=strict_canonical_order,
|
|
219
210
|
)
|
|
220
211
|
|
|
221
212
|
name = v05_multiscale.name
|
|
@@ -231,18 +222,14 @@ def v05_to_ngio_image_meta(
|
|
|
231
222
|
|
|
232
223
|
def v05_to_ngio_label_meta(
|
|
233
224
|
metadata: dict,
|
|
234
|
-
axes_setup: AxesSetup
|
|
235
|
-
allow_non_canonical_axes: bool = False,
|
|
236
|
-
strict_canonical_order: bool = True,
|
|
225
|
+
axes_setup: AxesSetup,
|
|
237
226
|
) -> NgioLabelMeta:
|
|
238
227
|
"""Convert a v05 image metadata to a ngio image metadata.
|
|
239
228
|
|
|
240
229
|
Args:
|
|
241
230
|
metadata (dict): The v05 image metadata.
|
|
242
|
-
axes_setup (AxesSetup
|
|
231
|
+
axes_setup (AxesSetup): The axes setup. This is
|
|
243
232
|
required to convert image with non-canonical axes names.
|
|
244
|
-
allow_non_canonical_axes (bool, optional): Allow non-canonical axes.
|
|
245
|
-
strict_canonical_order (bool, optional): Strict canonical order.
|
|
246
233
|
|
|
247
234
|
Returns:
|
|
248
235
|
NgioLabelMeta: The ngio label metadata.
|
|
@@ -257,12 +244,9 @@ def v05_to_ngio_label_meta(
|
|
|
257
244
|
|
|
258
245
|
v05_multiscale = v05_label.multiscales[0]
|
|
259
246
|
|
|
260
|
-
axes_setup = axes_setup if axes_setup is not None else AxesSetup()
|
|
261
247
|
datasets = _v05_to_ngio_datasets(
|
|
262
248
|
v05_multiscale,
|
|
263
249
|
axes_setup=axes_setup,
|
|
264
|
-
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
265
|
-
strict_canonical_order=strict_canonical_order,
|
|
266
250
|
)
|
|
267
251
|
|
|
268
252
|
if v05_label.image_label is not None:
|
ngio/resources/__init__.py
CHANGED
ngio/resources/resource_model.py
CHANGED
ngio/tables/_tables_container.py
CHANGED
|
@@ -229,10 +229,10 @@ class ImplementedTables:
|
|
|
229
229
|
|
|
230
230
|
|
|
231
231
|
class TablesContainer:
|
|
232
|
-
"""A class to handle the /
|
|
232
|
+
"""A class to handle the /tables group in an OME-NGFF file."""
|
|
233
233
|
|
|
234
234
|
def __init__(self, group_handler: ZarrGroupHandler) -> None:
|
|
235
|
-
"""Initialize the
|
|
235
|
+
"""Initialize the TablesContainer."""
|
|
236
236
|
self._group_handler = group_handler
|
|
237
237
|
|
|
238
238
|
# Validate the group
|
|
@@ -252,7 +252,7 @@ class TablesContainer:
|
|
|
252
252
|
)
|
|
253
253
|
|
|
254
254
|
def _get_tables_list(self) -> list[str]:
|
|
255
|
-
"""
|
|
255
|
+
"""Return the list of table names from the group attributes."""
|
|
256
256
|
attrs = self._group_handler.load_attrs()
|
|
257
257
|
return attrs.get("tables", [])
|
|
258
258
|
|
|
@@ -262,7 +262,14 @@ class TablesContainer:
|
|
|
262
262
|
return handler
|
|
263
263
|
|
|
264
264
|
def list(self, filter_types: TypedTable | str | None = None) -> list[str]:
|
|
265
|
-
"""List all
|
|
265
|
+
"""List all tables in the group.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
filter_types: If provided, only return tables of this type.
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
A list of table names.
|
|
272
|
+
"""
|
|
266
273
|
tables = self._get_tables_list()
|
|
267
274
|
if filter_types is None:
|
|
268
275
|
return tables
|
|
@@ -281,7 +288,16 @@ class TablesContainer:
|
|
|
281
288
|
backend: TableBackend | None = None,
|
|
282
289
|
strict: bool = True,
|
|
283
290
|
) -> Table:
|
|
284
|
-
"""Get a
|
|
291
|
+
"""Get a table from the group.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
name: The name of the table.
|
|
295
|
+
backend: The backend to use for reading the table.
|
|
296
|
+
strict: If True, raise an error if the table type is not implemented.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
The table object.
|
|
300
|
+
"""
|
|
285
301
|
if name not in self.list():
|
|
286
302
|
raise NgioValueError(f"Table '{name}' not found in the group.")
|
|
287
303
|
|
|
@@ -301,7 +317,16 @@ class TablesContainer:
|
|
|
301
317
|
table_cls: type[TableType],
|
|
302
318
|
backend: TableBackend | None = None,
|
|
303
319
|
) -> TableType:
|
|
304
|
-
"""Get a table from the group as a specific type.
|
|
320
|
+
"""Get a table from the group as a specific type.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
name: The name of the table.
|
|
324
|
+
table_cls: The table class to use for loading the table.
|
|
325
|
+
backend: The backend to use for reading the table.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
The table object of the specified type.
|
|
329
|
+
"""
|
|
305
330
|
if name not in self.list():
|
|
306
331
|
raise NgioValueError(f"Table '{name}' not found in the group.")
|
|
307
332
|
|
|
@@ -339,7 +364,14 @@ class TablesContainer:
|
|
|
339
364
|
backend: TableBackend = DefaultTableBackend,
|
|
340
365
|
overwrite: bool = False,
|
|
341
366
|
) -> None:
|
|
342
|
-
"""Add a table to the group.
|
|
367
|
+
"""Add a table to the group.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
name: The name of the table.
|
|
371
|
+
table: The table object to add.
|
|
372
|
+
backend: The backend to use for writing the table.
|
|
373
|
+
overwrite: Whether to overwrite an existing table with the same name.
|
|
374
|
+
"""
|
|
343
375
|
existing_tables = self._get_tables_list()
|
|
344
376
|
if name in existing_tables and not overwrite:
|
|
345
377
|
raise NgioValueError(
|
ngio/tables/v1/_roi_table.py
CHANGED
|
@@ -4,7 +4,7 @@ This class follows the roi_table specification at:
|
|
|
4
4
|
https://fractal-analytics-platform.github.io/fractal-tasks-core/tables/
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import logging
|
|
8
8
|
from collections.abc import Iterable
|
|
9
9
|
from typing import Literal
|
|
10
10
|
from uuid import uuid4
|
|
@@ -29,6 +29,8 @@ from ngio.utils import (
|
|
|
29
29
|
ZarrGroupHandler,
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
+
logger = logging.getLogger(f"ngio:{__name__}")
|
|
33
|
+
|
|
32
34
|
REQUIRED_COLUMNS = [
|
|
33
35
|
"x_micrometer",
|
|
34
36
|
"y_micrometer",
|
|
@@ -77,9 +79,7 @@ OPTIONAL_COLUMNS = ORIGIN_COLUMNS + TRANSLATION_COLUMNS + PLATE_COLUMNS + INDEX_
|
|
|
77
79
|
def _check_optional_columns(col_name: str) -> None:
|
|
78
80
|
"""Check if the column name is in the optional columns."""
|
|
79
81
|
if col_name not in OPTIONAL_COLUMNS + TIME_COLUMNS:
|
|
80
|
-
|
|
81
|
-
f"Column {col_name} is not in the optional columns.", stacklevel=2
|
|
82
|
-
)
|
|
82
|
+
logger.warning(f"Column {col_name} is not in the optional columns.")
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
def _dataframe_to_rois(
|
ngio/utils/_zarr_utils.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Common utilities for working with Zarr groups in consistent ways."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
import
|
|
4
|
+
import logging
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Literal, TypeAlias
|
|
7
7
|
|
|
@@ -22,6 +22,8 @@ from ngio.utils._errors import (
|
|
|
22
22
|
NgioValueError,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
+
logger = logging.getLogger(f"ngio:{__name__}")
|
|
26
|
+
|
|
25
27
|
AccessModeLiteral = Literal["r", "r+", "w", "w-", "a"]
|
|
26
28
|
# StoreLike is more restrictive than it could be
|
|
27
29
|
# but to make sure we can handle the store correctly
|
|
@@ -36,12 +38,10 @@ StoreOrGroup: TypeAlias = NgioSupportedStore | zarr.Group
|
|
|
36
38
|
def _check_store(store) -> NgioSupportedStore:
|
|
37
39
|
"""Check the store and return a valid store."""
|
|
38
40
|
if not isinstance(store, NgioSupportedStore):
|
|
39
|
-
|
|
41
|
+
logger.warning(
|
|
40
42
|
f"Store type {type(store)} is not explicitly supported. "
|
|
41
43
|
f"Supported types are: {NgioSupportedStore}. "
|
|
42
|
-
"Proceeding, but this may lead to unexpected behavior."
|
|
43
|
-
UserWarning,
|
|
44
|
-
stacklevel=2,
|
|
44
|
+
"Proceeding, but this may lead to unexpected behavior."
|
|
45
45
|
)
|
|
46
46
|
return store
|
|
47
47
|
|
|
@@ -114,7 +114,6 @@ class ZarrGroupHandler:
|
|
|
114
114
|
|
|
115
115
|
Args:
|
|
116
116
|
store (StoreOrGroup): The Zarr store or group containing the image data.
|
|
117
|
-
meta_mode (str): The mode of the metadata handler.
|
|
118
117
|
zarr_format (int | None): The Zarr format version to use.
|
|
119
118
|
cache (bool): Whether to cache the metadata.
|
|
120
119
|
mode (str | None): The mode of the store.
|
|
@@ -154,11 +153,7 @@ class ZarrGroupHandler:
|
|
|
154
153
|
return (self.store.path / self.group.path).as_posix()
|
|
155
154
|
elif isinstance(self.store, MemoryStore):
|
|
156
155
|
return None
|
|
157
|
-
|
|
158
|
-
f"Cannot determine full URL for store type {type(self.store)}. ",
|
|
159
|
-
UserWarning,
|
|
160
|
-
stacklevel=2,
|
|
161
|
-
)
|
|
156
|
+
logger.warning(f"Cannot determine full URL for store type {type(self.store)}.")
|
|
162
157
|
return None
|
|
163
158
|
|
|
164
159
|
@property
|
|
@@ -524,11 +519,9 @@ def copy_group(
|
|
|
524
519
|
_fsspec_copy(src_group.store, src_group.path, dest_group.store, dest_group.path)
|
|
525
520
|
return
|
|
526
521
|
if not suppress_warnings:
|
|
527
|
-
|
|
522
|
+
logger.warning(
|
|
528
523
|
"Fsspec copy not possible, falling back to Zarr Python API for the copy. "
|
|
529
524
|
"This will preserve some tabular data non-zarr native (parquet, and csv), "
|
|
530
|
-
"and it will be slower for large datasets."
|
|
531
|
-
UserWarning,
|
|
532
|
-
stacklevel=2,
|
|
525
|
+
"and it will be slower for large datasets."
|
|
533
526
|
)
|
|
534
527
|
_zarr_python_copy(src_group, dest_group)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ngio
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Next Generation file format IO
|
|
5
5
|
Project-URL: homepage, https://github.com/BioVisionCenter/ngio
|
|
6
6
|
Project-URL: repository, https://github.com/BioVisionCenter/ngio
|
|
@@ -23,7 +23,7 @@ Requires-Dist: dask[distributed]<2025.11.0
|
|
|
23
23
|
Requires-Dist: filelock
|
|
24
24
|
Requires-Dist: numpy
|
|
25
25
|
Requires-Dist: ome-zarr-models
|
|
26
|
-
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: pandas<3.0.0,>=1.2.0
|
|
27
27
|
Requires-Dist: pillow
|
|
28
28
|
Requires-Dist: polars
|
|
29
29
|
Requires-Dist: pooch
|
|
@@ -58,6 +58,7 @@ Requires-Dist: mkdocs-jupyter; extra == 'docs'
|
|
|
58
58
|
Requires-Dist: mkdocs-material; extra == 'docs'
|
|
59
59
|
Requires-Dist: mkdocstrings[python]; extra == 'docs'
|
|
60
60
|
Requires-Dist: rich; extra == 'docs'
|
|
61
|
+
Requires-Dist: ruff; extra == 'docs'
|
|
61
62
|
Requires-Dist: scikit-image; extra == 'docs'
|
|
62
63
|
Requires-Dist: tabulate; extra == 'docs'
|
|
63
64
|
Provides-Extra: test
|