ngio 0.3.5__py3-none-any.whl → 0.4.0a2__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 +6 -0
- ngio/common/__init__.py +50 -48
- ngio/common/_array_io_pipes.py +554 -0
- ngio/common/_array_io_utils.py +508 -0
- ngio/common/_dimensions.py +63 -27
- ngio/common/_masking_roi.py +38 -10
- ngio/common/_pyramid.py +9 -7
- ngio/common/_roi.py +583 -72
- ngio/common/_synt_images_utils.py +101 -0
- ngio/common/_zoom.py +17 -12
- ngio/common/transforms/__init__.py +5 -0
- ngio/common/transforms/_label.py +12 -0
- ngio/common/transforms/_zoom.py +109 -0
- ngio/experimental/__init__.py +5 -0
- ngio/experimental/iterators/__init__.py +17 -0
- ngio/experimental/iterators/_abstract_iterator.py +170 -0
- ngio/experimental/iterators/_feature.py +151 -0
- ngio/experimental/iterators/_image_processing.py +169 -0
- ngio/experimental/iterators/_rois_utils.py +127 -0
- ngio/experimental/iterators/_segmentation.py +282 -0
- ngio/hcs/_plate.py +41 -36
- ngio/images/__init__.py +22 -1
- ngio/images/_abstract_image.py +247 -117
- ngio/images/_create.py +15 -15
- ngio/images/_create_synt_container.py +128 -0
- ngio/images/_image.py +425 -62
- ngio/images/_label.py +33 -30
- ngio/images/_masked_image.py +396 -122
- ngio/images/_ome_zarr_container.py +203 -66
- ngio/{common → images}/_table_ops.py +41 -41
- ngio/ome_zarr_meta/ngio_specs/__init__.py +2 -8
- ngio/ome_zarr_meta/ngio_specs/_axes.py +151 -128
- ngio/ome_zarr_meta/ngio_specs/_channels.py +55 -18
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +7 -7
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +3 -3
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +11 -68
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +1 -1
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png +0 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg +0 -0
- ngio/resources/__init__.py +54 -0
- ngio/resources/resource_model.py +35 -0
- ngio/tables/backends/_abstract_backend.py +5 -6
- ngio/tables/backends/_anndata.py +1 -1
- ngio/tables/backends/_anndata_utils.py +3 -3
- ngio/tables/backends/_non_zarr_backends.py +1 -1
- ngio/tables/backends/_table_backends.py +0 -1
- ngio/tables/backends/_utils.py +3 -3
- ngio/tables/v1/_roi_table.py +156 -69
- ngio/utils/__init__.py +2 -3
- ngio/utils/_logger.py +19 -0
- ngio/utils/_zarr_utils.py +1 -5
- {ngio-0.3.5.dist-info → ngio-0.4.0a2.dist-info}/METADATA +3 -1
- ngio-0.4.0a2.dist-info/RECORD +76 -0
- ngio/common/_array_pipe.py +0 -288
- ngio/common/_axes_transforms.py +0 -64
- ngio/common/_common_types.py +0 -5
- ngio/common/_slicer.py +0 -96
- ngio-0.3.5.dist-info/RECORD +0 -61
- {ngio-0.3.5.dist-info → ngio-0.4.0a2.dist-info}/WHEEL +0 -0
- {ngio-0.3.5.dist-info → ngio-0.4.0a2.dist-info}/licenses/LICENSE +0 -0
ngio/tables/v1/_roi_table.py
CHANGED
|
@@ -4,9 +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 _type to avoid name conflict with table.type
|
|
8
7
|
from collections.abc import Iterable
|
|
9
|
-
from functools import cache
|
|
10
8
|
from typing import Literal
|
|
11
9
|
|
|
12
10
|
import pandas as pd
|
|
@@ -27,7 +25,7 @@ from ngio.utils import (
|
|
|
27
25
|
NgioTableValidationError,
|
|
28
26
|
NgioValueError,
|
|
29
27
|
ZarrGroupHandler,
|
|
30
|
-
|
|
28
|
+
ngio_warn,
|
|
31
29
|
)
|
|
32
30
|
|
|
33
31
|
REQUIRED_COLUMNS = [
|
|
@@ -44,6 +42,11 @@ REQUIRED_COLUMNS = [
|
|
|
44
42
|
# only a warning is raised if non optional columns are present
|
|
45
43
|
#####################
|
|
46
44
|
|
|
45
|
+
TIME_COLUMNS = [
|
|
46
|
+
"t_second",
|
|
47
|
+
"len_t_second",
|
|
48
|
+
]
|
|
49
|
+
|
|
47
50
|
ORIGIN_COLUMNS = [
|
|
48
51
|
"x_micrometer_original",
|
|
49
52
|
"y_micrometer_original",
|
|
@@ -70,24 +73,17 @@ INDEX_COLUMNS = [
|
|
|
70
73
|
OPTIONAL_COLUMNS = ORIGIN_COLUMNS + TRANSLATION_COLUMNS + PLATE_COLUMNS + INDEX_COLUMNS
|
|
71
74
|
|
|
72
75
|
|
|
73
|
-
@cache
|
|
74
76
|
def _check_optional_columns(col_name: str) -> None:
|
|
75
77
|
"""Check if the column name is in the optional columns."""
|
|
76
|
-
if col_name not in OPTIONAL_COLUMNS:
|
|
77
|
-
|
|
78
|
-
f"Column {col_name} is not in the optional columns. "
|
|
79
|
-
f"Standard optional columns are: {OPTIONAL_COLUMNS}."
|
|
80
|
-
)
|
|
78
|
+
if col_name not in OPTIONAL_COLUMNS + TIME_COLUMNS:
|
|
79
|
+
ngio_warn(f"Column {col_name} is not in the optional columns.")
|
|
81
80
|
|
|
82
81
|
|
|
83
82
|
def _dataframe_to_rois(
|
|
84
83
|
dataframe: pd.DataFrame,
|
|
85
|
-
required_columns: list[str]
|
|
84
|
+
required_columns: list[str] = REQUIRED_COLUMNS,
|
|
86
85
|
) -> dict[str, Roi]:
|
|
87
86
|
"""Convert a DataFrame to a WorldCooROI object."""
|
|
88
|
-
if required_columns is None:
|
|
89
|
-
required_columns = REQUIRED_COLUMNS
|
|
90
|
-
|
|
91
87
|
# Validate the columns of the DataFrame
|
|
92
88
|
_required_columns = set(dataframe.columns).intersection(set(required_columns))
|
|
93
89
|
if len(_required_columns) != len(required_columns):
|
|
@@ -95,11 +91,15 @@ def _dataframe_to_rois(
|
|
|
95
91
|
f"Could not find required columns: {_required_columns} in the table."
|
|
96
92
|
)
|
|
97
93
|
|
|
98
|
-
extra_columns = set(dataframe.columns).difference(
|
|
94
|
+
extra_columns = set(dataframe.columns).difference(
|
|
95
|
+
set(required_columns + TIME_COLUMNS)
|
|
96
|
+
)
|
|
99
97
|
|
|
100
98
|
for col in extra_columns:
|
|
101
99
|
_check_optional_columns(col)
|
|
102
100
|
|
|
101
|
+
label_is_index = True if dataframe.index.name == "label" else False
|
|
102
|
+
|
|
103
103
|
extras = {}
|
|
104
104
|
|
|
105
105
|
rois = {}
|
|
@@ -108,85 +108,166 @@ def _dataframe_to_rois(
|
|
|
108
108
|
if len(extra_columns) > 0:
|
|
109
109
|
extras = {col: getattr(row, col, None) for col in extra_columns}
|
|
110
110
|
|
|
111
|
+
z_micrometer = getattr(row, "z_micrometer", None)
|
|
112
|
+
z_length_micrometer = getattr(row, "len_z_micrometer", None)
|
|
113
|
+
|
|
114
|
+
t_second = getattr(row, "t_second", None)
|
|
115
|
+
t_length_second = getattr(row, "len_t_second", None)
|
|
116
|
+
|
|
117
|
+
if label_is_index:
|
|
118
|
+
label = int(row.Index) # type: ignore (type can not be known here, but should be castable to int)
|
|
119
|
+
else:
|
|
120
|
+
label = getattr(row, "label", None)
|
|
121
|
+
|
|
111
122
|
roi = Roi(
|
|
112
123
|
name=str(row.Index),
|
|
113
|
-
x=row.x_micrometer, # type: ignore
|
|
114
|
-
y=row.y_micrometer, # type: ignore
|
|
115
|
-
z=
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
x=row.x_micrometer, # type: ignore (type can not be known here)
|
|
125
|
+
y=row.y_micrometer, # type: ignore (type can not be known here)
|
|
126
|
+
z=z_micrometer,
|
|
127
|
+
t=t_second,
|
|
128
|
+
x_length=row.len_x_micrometer, # type: ignore (type can not be known here)
|
|
129
|
+
y_length=row.len_y_micrometer, # type: ignore (type can not be known here)
|
|
130
|
+
z_length=z_length_micrometer,
|
|
131
|
+
t_length=t_length_second,
|
|
132
|
+
unit="micrometer",
|
|
133
|
+
label=label,
|
|
120
134
|
**extras,
|
|
121
135
|
)
|
|
122
136
|
rois[roi.name] = roi
|
|
123
137
|
return rois
|
|
124
138
|
|
|
125
139
|
|
|
126
|
-
def _table_to_rois(
|
|
127
|
-
table: TabularData,
|
|
128
|
-
index_key: str | None = None,
|
|
129
|
-
index_type: Literal["int", "str"] | None = None,
|
|
130
|
-
required_columns: list[str] | None = None,
|
|
131
|
-
) -> tuple[pd.DataFrame, dict[str, Roi]]:
|
|
132
|
-
"""Convert a table to a dictionary of ROIs.
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
table: The table to convert.
|
|
136
|
-
index_key: The column name to use as the index of the DataFrame.
|
|
137
|
-
index_type: The type of the index column in the DataFrame.
|
|
138
|
-
required_columns: The required columns in the DataFrame.
|
|
139
|
-
|
|
140
|
-
Returns:
|
|
141
|
-
A dictionary of ROIs.
|
|
142
|
-
"""
|
|
143
|
-
dataframe = convert_to_pandas(
|
|
144
|
-
table,
|
|
145
|
-
index_key=index_key,
|
|
146
|
-
index_type=index_type,
|
|
147
|
-
)
|
|
148
|
-
return dataframe, _dataframe_to_rois(dataframe, required_columns=required_columns)
|
|
149
|
-
|
|
150
|
-
|
|
151
140
|
def _rois_to_dataframe(rois: dict[str, Roi], index_key: str | None) -> pd.DataFrame:
|
|
152
141
|
"""Convert a list of WorldCooROI objects to a DataFrame."""
|
|
153
142
|
data = []
|
|
154
143
|
for roi in rois.values():
|
|
144
|
+
# This normalization is necessary for backward compatibility
|
|
145
|
+
z_micrometer = roi.z if roi.z is not None else 0.0
|
|
146
|
+
len_z_micrometer = roi.z_length if roi.z_length is not None else 1.0
|
|
147
|
+
|
|
155
148
|
row = {
|
|
156
149
|
index_key: roi.name,
|
|
157
150
|
"x_micrometer": roi.x,
|
|
158
151
|
"y_micrometer": roi.y,
|
|
159
|
-
"z_micrometer":
|
|
152
|
+
"z_micrometer": z_micrometer,
|
|
160
153
|
"len_x_micrometer": roi.x_length,
|
|
161
154
|
"len_y_micrometer": roi.y_length,
|
|
162
|
-
"len_z_micrometer":
|
|
155
|
+
"len_z_micrometer": len_z_micrometer,
|
|
163
156
|
}
|
|
164
157
|
|
|
158
|
+
if roi.t is not None:
|
|
159
|
+
row["t_second"] = roi.t
|
|
160
|
+
|
|
161
|
+
if roi.t_length is not None:
|
|
162
|
+
row["len_t_second"] = roi.t_length
|
|
163
|
+
|
|
164
|
+
if roi.label is not None and index_key != "label":
|
|
165
|
+
row["label"] = roi.label
|
|
166
|
+
|
|
165
167
|
extra = roi.model_extra or {}
|
|
166
168
|
for col in extra:
|
|
167
169
|
_check_optional_columns(col)
|
|
168
170
|
row[col] = extra[col]
|
|
169
171
|
data.append(row)
|
|
172
|
+
|
|
170
173
|
dataframe = pd.DataFrame(data)
|
|
171
174
|
dataframe = normalize_pandas_df(dataframe, index_key=index_key)
|
|
172
175
|
return dataframe
|
|
173
176
|
|
|
174
177
|
|
|
178
|
+
class RoiDictWrapper:
|
|
179
|
+
"""A wrapper for a dictionary of ROIs to provide a consistent interface."""
|
|
180
|
+
|
|
181
|
+
def __init__(self, rois: Iterable[Roi]) -> None:
|
|
182
|
+
self._rois_by_name = {roi.name: roi for roi in rois}
|
|
183
|
+
self._rois_by_label = {roi.label: roi for roi in rois if roi.label is not None}
|
|
184
|
+
|
|
185
|
+
def get_by_name(self, name: str, default: Roi | None = None) -> Roi | None:
|
|
186
|
+
"""Get an ROI by its name."""
|
|
187
|
+
return self._rois_by_name.get(name, default)
|
|
188
|
+
|
|
189
|
+
def get_by_label(self, label: int, default: Roi | None = None) -> Roi | None:
|
|
190
|
+
"""Get an ROI by its label."""
|
|
191
|
+
return self._rois_by_label.get(label, default)
|
|
192
|
+
|
|
193
|
+
def _add_roi(self, roi: Roi, overwrite: bool = False) -> None:
|
|
194
|
+
"""Add an ROI to the wrapper."""
|
|
195
|
+
if roi.name in self._rois_by_name and not overwrite:
|
|
196
|
+
raise NgioValueError(f"ROI with name {roi.name} already exists.")
|
|
197
|
+
|
|
198
|
+
self._rois_by_name[roi.name] = roi
|
|
199
|
+
if roi.label is not None:
|
|
200
|
+
self._rois_by_label[roi.label] = roi
|
|
201
|
+
|
|
202
|
+
def add_rois(self, rois: Roi | Iterable[Roi], overwrite: bool = False) -> None:
|
|
203
|
+
"""Add ROIs to the wrapper."""
|
|
204
|
+
if isinstance(rois, Roi):
|
|
205
|
+
rois = [rois]
|
|
206
|
+
|
|
207
|
+
for roi in rois:
|
|
208
|
+
self._add_roi(roi, overwrite=overwrite)
|
|
209
|
+
|
|
210
|
+
def to_list(self) -> list[Roi]:
|
|
211
|
+
"""Return the list of ROIs."""
|
|
212
|
+
return list(self._rois_by_name.values())
|
|
213
|
+
|
|
214
|
+
def to_dataframe(self, index_key: str | None = None) -> pd.DataFrame:
|
|
215
|
+
"""Convert the ROIs to a DataFrame."""
|
|
216
|
+
return _rois_to_dataframe(self._rois_by_name, index_key=index_key)
|
|
217
|
+
|
|
218
|
+
@classmethod
|
|
219
|
+
def from_dataframe(
|
|
220
|
+
cls, dataframe: pd.DataFrame, required_columns: list[str] = REQUIRED_COLUMNS
|
|
221
|
+
) -> "RoiDictWrapper":
|
|
222
|
+
"""Create a RoiDictWrapper from a DataFrame."""
|
|
223
|
+
rois = _dataframe_to_rois(dataframe, required_columns=required_columns)
|
|
224
|
+
return cls(rois.values())
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _table_to_rois(
|
|
228
|
+
table: TabularData,
|
|
229
|
+
index_key: str | None = None,
|
|
230
|
+
index_type: Literal["int", "str"] | None = None,
|
|
231
|
+
required_columns: list[str] = REQUIRED_COLUMNS,
|
|
232
|
+
) -> tuple[pd.DataFrame, RoiDictWrapper]:
|
|
233
|
+
"""Convert a table to a dictionary of ROIs.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
table: The table to convert.
|
|
237
|
+
index_key: The column name to use as the index of the DataFrame.
|
|
238
|
+
index_type: The type of the index column in the DataFrame.
|
|
239
|
+
required_columns: The required columns in the DataFrame.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
A tuple containing the DataFrame and a RoiDictWrapper with the ROIs.
|
|
243
|
+
"""
|
|
244
|
+
dataframe = convert_to_pandas(
|
|
245
|
+
table,
|
|
246
|
+
index_key=index_key,
|
|
247
|
+
index_type=index_type,
|
|
248
|
+
)
|
|
249
|
+
roi_dict_wrapper = RoiDictWrapper.from_dataframe(
|
|
250
|
+
dataframe, required_columns=required_columns
|
|
251
|
+
)
|
|
252
|
+
return dataframe, roi_dict_wrapper
|
|
253
|
+
|
|
254
|
+
|
|
175
255
|
class GenericRoiTableV1(AbstractBaseTable):
|
|
176
256
|
def __init__(
|
|
177
257
|
self,
|
|
178
258
|
*,
|
|
179
259
|
rois: Iterable[Roi] | None = None,
|
|
180
260
|
meta: BackendMeta,
|
|
261
|
+
required_columns: list[str] = REQUIRED_COLUMNS,
|
|
181
262
|
) -> None:
|
|
182
263
|
table = None
|
|
183
264
|
|
|
184
|
-
self._rois:
|
|
265
|
+
self._rois: RoiDictWrapper | None = None
|
|
185
266
|
if rois is not None:
|
|
186
|
-
self._rois =
|
|
187
|
-
self.
|
|
188
|
-
table = _rois_to_dataframe(self._rois, index_key=meta.index_key)
|
|
267
|
+
self._rois = RoiDictWrapper(rois)
|
|
268
|
+
table = self._rois.to_dataframe(index_key=meta.index_key)
|
|
189
269
|
|
|
270
|
+
self._required_columns = required_columns
|
|
190
271
|
super().__init__(table_data=table, meta=meta)
|
|
191
272
|
|
|
192
273
|
def __repr__(self) -> str:
|
|
@@ -213,7 +294,7 @@ class GenericRoiTableV1(AbstractBaseTable):
|
|
|
213
294
|
return super().table_data
|
|
214
295
|
|
|
215
296
|
if len(self.rois()) > 0:
|
|
216
|
-
self._table_data =
|
|
297
|
+
self._table_data = self._rois.to_dataframe(index_key=self.meta.index_key)
|
|
217
298
|
return super().table_data
|
|
218
299
|
|
|
219
300
|
def set_table_data(
|
|
@@ -260,14 +341,16 @@ class GenericRoiTableV1(AbstractBaseTable):
|
|
|
260
341
|
If the ROIs are not loaded, load them from the table.
|
|
261
342
|
"""
|
|
262
343
|
if self._rois is None:
|
|
263
|
-
self._rois =
|
|
344
|
+
self._rois = RoiDictWrapper.from_dataframe(
|
|
345
|
+
self.dataframe, required_columns=self._required_columns
|
|
346
|
+
)
|
|
264
347
|
|
|
265
348
|
def rois(self) -> list[Roi]:
|
|
266
349
|
"""List all ROIs in the table."""
|
|
267
350
|
self._check_rois()
|
|
268
351
|
if self._rois is None:
|
|
269
352
|
return []
|
|
270
|
-
return
|
|
353
|
+
return self._rois.to_list()
|
|
271
354
|
|
|
272
355
|
def add(self, roi: Roi | Iterable[Roi], overwrite: bool = False) -> None:
|
|
273
356
|
"""Append ROIs to the current table.
|
|
@@ -281,22 +364,20 @@ class GenericRoiTableV1(AbstractBaseTable):
|
|
|
281
364
|
|
|
282
365
|
self._check_rois()
|
|
283
366
|
if self._rois is None:
|
|
284
|
-
self._rois =
|
|
367
|
+
self._rois = RoiDictWrapper([])
|
|
285
368
|
|
|
286
|
-
|
|
287
|
-
if not overwrite and _roi.name in self._rois:
|
|
288
|
-
raise NgioValueError(f"ROI {_roi.name} already exists in the table.")
|
|
289
|
-
self._rois[_roi.name] = _roi
|
|
369
|
+
self._rois.add_rois(roi, overwrite=overwrite)
|
|
290
370
|
|
|
291
371
|
def get(self, roi_name: str) -> Roi:
|
|
292
372
|
"""Get an ROI from the table."""
|
|
293
373
|
self._check_rois()
|
|
294
374
|
if self._rois is None:
|
|
295
|
-
self._rois =
|
|
375
|
+
self._rois = RoiDictWrapper([])
|
|
296
376
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
377
|
+
roi = self._rois.get_by_name(roi_name)
|
|
378
|
+
if roi is None:
|
|
379
|
+
raise NgioValueError(f"ROI with name {roi_name} not found in the table.")
|
|
380
|
+
return roi
|
|
300
381
|
|
|
301
382
|
@classmethod
|
|
302
383
|
def from_table_data(
|
|
@@ -309,7 +390,7 @@ class GenericRoiTableV1(AbstractBaseTable):
|
|
|
309
390
|
index_type=meta.index_type,
|
|
310
391
|
required_columns=REQUIRED_COLUMNS,
|
|
311
392
|
)
|
|
312
|
-
return cls(rois=rois.
|
|
393
|
+
return cls(rois=rois.to_list(), meta=meta)
|
|
313
394
|
|
|
314
395
|
|
|
315
396
|
class RoiTableV1Meta(BackendMeta):
|
|
@@ -457,7 +538,13 @@ class MaskingRoiTableV1(GenericRoiTableV1):
|
|
|
457
538
|
path = path.split("/")[-1]
|
|
458
539
|
return path
|
|
459
540
|
|
|
460
|
-
def
|
|
461
|
-
"""Get an ROI
|
|
462
|
-
|
|
463
|
-
|
|
541
|
+
def get_label(self, label: int) -> Roi:
|
|
542
|
+
"""Get an ROI by label."""
|
|
543
|
+
self._check_rois()
|
|
544
|
+
if self._rois is None:
|
|
545
|
+
self._rois = RoiDictWrapper([])
|
|
546
|
+
roi = self._rois.get_by_label(label)
|
|
547
|
+
|
|
548
|
+
if roi is None:
|
|
549
|
+
raise NgioValueError(f"ROI with label {label} not found.")
|
|
550
|
+
return roi
|
ngio/utils/__init__.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
-
from ngio.common._common_types import ArrayLike
|
|
6
5
|
from ngio.utils._datasets import (
|
|
7
6
|
download_ome_zarr_dataset,
|
|
8
7
|
list_ome_zarr_datasets,
|
|
@@ -16,7 +15,7 @@ from ngio.utils._errors import (
|
|
|
16
15
|
NgioValueError,
|
|
17
16
|
)
|
|
18
17
|
from ngio.utils._fractal_fsspec_store import fractal_fsspec_store
|
|
19
|
-
from ngio.utils._logger import ngio_logger, set_logger_level
|
|
18
|
+
from ngio.utils._logger import ngio_logger, ngio_warn, set_logger_level
|
|
20
19
|
from ngio.utils._zarr_utils import (
|
|
21
20
|
AccessModeLiteral,
|
|
22
21
|
StoreOrGroup,
|
|
@@ -29,7 +28,6 @@ set_logger_level(os.getenv("NGIO_LOGGER_LEVEL", "WARNING"))
|
|
|
29
28
|
__all__ = [
|
|
30
29
|
# Zarr
|
|
31
30
|
"AccessModeLiteral",
|
|
32
|
-
"ArrayLike",
|
|
33
31
|
# Errors
|
|
34
32
|
"NgioFileExistsError",
|
|
35
33
|
"NgioFileNotFoundError",
|
|
@@ -44,6 +42,7 @@ __all__ = [
|
|
|
44
42
|
"list_ome_zarr_datasets",
|
|
45
43
|
# Logger
|
|
46
44
|
"ngio_logger",
|
|
45
|
+
"ngio_warn",
|
|
47
46
|
"open_group_wrapper",
|
|
48
47
|
"print_datasets_infos",
|
|
49
48
|
"set_logger_level",
|
ngio/utils/_logger.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import time
|
|
3
|
+
from functools import cache
|
|
2
4
|
|
|
3
5
|
from ngio.utils._errors import NgioValueError
|
|
4
6
|
|
|
@@ -29,3 +31,20 @@ def set_logger_level(level: str) -> None:
|
|
|
29
31
|
raise NgioValueError(f"Invalid log level: {level}")
|
|
30
32
|
|
|
31
33
|
ngio_logger.setLevel(level)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@cache
|
|
37
|
+
def _warn(message: str, ttl_hash: int) -> None:
|
|
38
|
+
"""Log a warning message with a time-to-live (TTL) hash."""
|
|
39
|
+
ngio_logger.warning(message, stacklevel=3)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def ngio_warn(message: str, cooldown: int = 2) -> None:
|
|
43
|
+
"""Log a warning message.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
message: The warning message to log.
|
|
47
|
+
cooldown: The cooldown period in seconds to avoid repeated logging.
|
|
48
|
+
"""
|
|
49
|
+
ttl_hash = time.time() // cooldown
|
|
50
|
+
_warn(message, ttl_hash)
|
ngio/utils/_zarr_utils.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Common utilities for working with Zarr groups in consistent ways."""
|
|
2
2
|
|
|
3
|
-
# %%
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
from typing import Literal
|
|
6
5
|
|
|
@@ -164,7 +163,7 @@ class ZarrGroupHandler:
|
|
|
164
163
|
@property
|
|
165
164
|
def mode(self) -> AccessModeLiteral:
|
|
166
165
|
"""Return the mode of the group."""
|
|
167
|
-
return self._mode # type: ignore
|
|
166
|
+
return self._mode # type: ignore (return type is Literal)
|
|
168
167
|
|
|
169
168
|
@property
|
|
170
169
|
def lock(self) -> BaseFileLock:
|
|
@@ -410,6 +409,3 @@ class ZarrGroupHandler:
|
|
|
410
409
|
f"Error copying group to {handler.full_url}, "
|
|
411
410
|
f"#{n_skipped} files where skipped."
|
|
412
411
|
)
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
# %%
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ngio
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0a2
|
|
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
|
|
@@ -38,11 +38,13 @@ Requires-Dist: napari; extra == 'dev'
|
|
|
38
38
|
Requires-Dist: notebook; extra == 'dev'
|
|
39
39
|
Requires-Dist: pdbpp; extra == 'dev'
|
|
40
40
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
41
|
+
Requires-Dist: pympler; extra == 'dev'
|
|
41
42
|
Requires-Dist: pyqt5; extra == 'dev'
|
|
42
43
|
Requires-Dist: rich; extra == 'dev'
|
|
43
44
|
Requires-Dist: ruff; extra == 'dev'
|
|
44
45
|
Requires-Dist: scikit-image; extra == 'dev'
|
|
45
46
|
Provides-Extra: docs
|
|
47
|
+
Requires-Dist: griffe-typingdoc; extra == 'docs'
|
|
46
48
|
Requires-Dist: markdown-exec[ansi]; extra == 'docs'
|
|
47
49
|
Requires-Dist: matplotlib; extra == 'docs'
|
|
48
50
|
Requires-Dist: mike; extra == 'docs'
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
ngio/__init__.py,sha256=clqwRwmkalSwXvmNLGwtI-385gwvBTnJjohEk3Xp5cE,1463
|
|
2
|
+
ngio/common/__init__.py,sha256=t5FUH7kSTqTT1jHmL_qYiEUCHHwMEKNfcZ6EbrkcpNg,1958
|
|
3
|
+
ngio/common/_array_io_pipes.py,sha256=zxZIVRtPjWUQ8J09_s5RcwoTgCOHDGmYYrkdPQbOPlM,18221
|
|
4
|
+
ngio/common/_array_io_utils.py,sha256=LktLM2_2LkjYkwzyJXHZ0LyuwrQN4GYTqgpByBxNmlg,16303
|
|
5
|
+
ngio/common/_dimensions.py,sha256=ubBSmnQmZOmen1jUn3LWZlNXCjUuV9FTjZWzUYidOwk,4852
|
|
6
|
+
ngio/common/_masking_roi.py,sha256=ZZTXordEZoq_ADk0OzADvq-5dPOwUBSuNobzFR8fpTw,5697
|
|
7
|
+
ngio/common/_pyramid.py,sha256=ElY_nBcchN3eeD9obLZ31IIo42HVlDn8R-legQpNxzQ,7503
|
|
8
|
+
ngio/common/_roi.py,sha256=SJ_YJx5hR35T_OIx7ev9Y-rXInu7B4VEh8VKgcsdkcg,21166
|
|
9
|
+
ngio/common/_synt_images_utils.py,sha256=B6uYOW1NyrM06YMR-csca3_YnAAkPRTbvnbLdy9tk9E,3188
|
|
10
|
+
ngio/common/_zoom.py,sha256=p_trkLLrNM6hYvchJQJOHfYpzSlzzdDJmcyTx6K5J1M,6030
|
|
11
|
+
ngio/common/transforms/__init__.py,sha256=Dn8SpMw_e_bg9kx4ZVPrGHJIu_yOK1FkIlePlN_C7FQ,120
|
|
12
|
+
ngio/common/transforms/_label.py,sha256=_bTK_E0BCWTno-qg3cf4voAB8OLJuEZ-4l0YgEXgl44,424
|
|
13
|
+
ngio/common/transforms/_zoom.py,sha256=mbnPnJZsCCms5x1Tq2akvsRDbsDYomiNRGqiF6KY2nI,3751
|
|
14
|
+
ngio/experimental/__init__.py,sha256=3pmBtHi-i8bKjTsvrOJM56ZyRX3Pv_dceCdt88-8COQ,147
|
|
15
|
+
ngio/experimental/iterators/__init__.py,sha256=on_sUvuRhHBb7-r5u3Ojvu6K9FGjUOrWGUkLQ4aRzbs,556
|
|
16
|
+
ngio/experimental/iterators/_abstract_iterator.py,sha256=p8ZxQuoqPGLZCp79FprhgV-QsN5uuqadffoXnEqSdys,5533
|
|
17
|
+
ngio/experimental/iterators/_feature.py,sha256=6uONbB527SS2NLlpiFtL3AVOazH-QpGhETLEt8pykgU,5987
|
|
18
|
+
ngio/experimental/iterators/_image_processing.py,sha256=4U2FCS5pyDes9VJAGbQn7_e8YMs2TU0ocVr2m1QZhYA,6639
|
|
19
|
+
ngio/experimental/iterators/_rois_utils.py,sha256=LfBKk2XEY-UuomT_9uOg-0b0_GUo6IX5h0OJmrbMs4g,4375
|
|
20
|
+
ngio/experimental/iterators/_segmentation.py,sha256=pCR2eR5LUMV5nouw6vRDjIyIabnvfxp7cE6sukW4GZc,11220
|
|
21
|
+
ngio/hcs/__init__.py,sha256=G8j9vD-liLeB_UeGtKYIgshWvJnUA6ks9GwjvWBLdHs,357
|
|
22
|
+
ngio/hcs/_plate.py,sha256=qfRwbCKaoz_AWTi8RDFFwOxy5geSknfJrPcqFVno9zI,44288
|
|
23
|
+
ngio/images/__init__.py,sha256=9Whvt7GTiCgT_vXaEEqGnDaY1-UsRk3dhLTv091F_g4,1211
|
|
24
|
+
ngio/images/_abstract_image.py,sha256=AmulSId7WMpKke1ROshxX1hYLHHNQMBy_4F4aPkE-Jw,15601
|
|
25
|
+
ngio/images/_create.py,sha256=X0EalQgrcdh_RVgSxIkv0YNQydKXNRpCXHlgn1oVpI0,9445
|
|
26
|
+
ngio/images/_create_synt_container.py,sha256=XjsQjBEnEGiqrfyKBdp_h4dJmScBMpMg1yUEqObo7Nw,5004
|
|
27
|
+
ngio/images/_image.py,sha256=4PwHsD0KiiJwcyuVX4-iuLCv6V05N6JlCDlEggyLJkw,31742
|
|
28
|
+
ngio/images/_label.py,sha256=rv6-oigkpa5mUTdogdPhfC3JYkEbdjXxY6Y6f1oD-RI,10603
|
|
29
|
+
ngio/images/_masked_image.py,sha256=oFApCcPejfapzilh3ecO2NmI_FReU1FJPc-8XJqsYYU,19619
|
|
30
|
+
ngio/images/_ome_zarr_container.py,sha256=uMQcvfwKj1uL3LG6k7pBQuPfG0KiM94fcf3kP7fu9eg,36705
|
|
31
|
+
ngio/images/_table_ops.py,sha256=jFv_AMqoB4JBpoWsMtZppZVW7dAOC_u-JpfNm8b33kY,15292
|
|
32
|
+
ngio/ome_zarr_meta/__init__.py,sha256=oZ8PEsWM7U0KwzpsnvVfX9k4UfuTz5sZ8B6B9eY5hyY,1193
|
|
33
|
+
ngio/ome_zarr_meta/_meta_handlers.py,sha256=ctknNDT8jxwyvxQf9on5gW31H1tRRsnneO38GT2UXoE,25880
|
|
34
|
+
ngio/ome_zarr_meta/ngio_specs/__init__.py,sha256=9mYKQ-1LqIa20dN_cuUuUf_w-V39Y0HdeB8UKqSrpfQ,1660
|
|
35
|
+
ngio/ome_zarr_meta/ngio_specs/_axes.py,sha256=S10x-8yObaGD6HEirkfMjrVGWnIHlDd52_RdYBTfjY0,17498
|
|
36
|
+
ngio/ome_zarr_meta/ngio_specs/_channels.py,sha256=CVsbG52U31TaMdTj8XqvClUdBya2Ar3qBjDo_xhP-NM,16967
|
|
37
|
+
ngio/ome_zarr_meta/ngio_specs/_dataset.py,sha256=bYbqBneOmASGiV_D1sgng3odtbo0ICWdqDs7au99PSU,5844
|
|
38
|
+
ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py,sha256=N1CGPOubwf0pvm8tiTnh-C1cOu9lToyDe3WagnEnPN4,17207
|
|
39
|
+
ngio/ome_zarr_meta/ngio_specs/_ngio_image.py,sha256=Q4bJjU_53-Lw2qrVaw07PKwjaHLmHZy7JIwM8dkqFeg,15689
|
|
40
|
+
ngio/ome_zarr_meta/ngio_specs/_pixel_size.py,sha256=5TT8250XdCKUnk3OwZeyXIMNFKOg_jx4NnoCo9RLsXI,4079
|
|
41
|
+
ngio/ome_zarr_meta/v04/__init__.py,sha256=dJRzzxyYc81kf-0Hip_bqvbdManaM8XTdQX2meWyCSs,583
|
|
42
|
+
ngio/ome_zarr_meta/v04/_custom_models.py,sha256=5GxiDERvLuvq4QvApcA6EiKLS6hLFX1R0R_9rSaa85A,530
|
|
43
|
+
ngio/ome_zarr_meta/v04/_v04_spec_utils.py,sha256=YKBVVWb3mnuE-5L5k1i85WpHmcrbKl9k5KU2jNqt5yg,15868
|
|
44
|
+
ngio/resources/__init__.py,sha256=Hry2odzDaC471_qgVfAQVnWDMK0Io9F8m9_JBNNm4e0,1633
|
|
45
|
+
ngio/resources/resource_model.py,sha256=0Egs0QAJ5PNknqECHuBd_-ZTdi8EDNirt5VyuPdbg30,835
|
|
46
|
+
ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png,sha256=g3QmxQdmeciAtBe5cTCRfR6yw3keG9cBYfjizMo6EGo,11890
|
|
47
|
+
ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png,sha256=QhZ4XiFX7r-8-fbX8wSeUymktX85Ap3Nw1MqeOfRrF8,21649
|
|
48
|
+
ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg,sha256=82lejQAIokj5w9g-qqhysDTWpHtNvJTkdURG_BjqIxQ,37743
|
|
49
|
+
ngio/tables/__init__.py,sha256=_BV3sclNMLITu_J8_3DkkUrCB6Kro0HzeWLDCD1ivKM,877
|
|
50
|
+
ngio/tables/_abstract_table.py,sha256=rwGa47TzbFmosucBWVfFq6JEXtgGvOdUVtU9DIelV88,8204
|
|
51
|
+
ngio/tables/_tables_container.py,sha256=3xmpREaN671l40MPprnl1BD-VoOb6xfjECb5mNoMW0w,12173
|
|
52
|
+
ngio/tables/backends/__init__.py,sha256=MwSRXNF1rWQBFOTDA_vT3oGoNZpviVgytsL5Txnu08I,1619
|
|
53
|
+
ngio/tables/backends/_abstract_backend.py,sha256=54Vh9yPfLx1NixGVfFkW4msD51nsim0zIfHRnO80Xt8,7276
|
|
54
|
+
ngio/tables/backends/_anndata.py,sha256=97RWG4Hjc42JBxm-YxjHEU8HHd14NiayelKlI1PTsCo,2868
|
|
55
|
+
ngio/tables/backends/_anndata_utils.py,sha256=HsmP27fm7JW1kjahl4lUnnViK_iqmu2bnsu86z43U98,3116
|
|
56
|
+
ngio/tables/backends/_csv.py,sha256=Ev61D-AUKo4LIhXRmWPJgYbHI7eQdxiajQR574DevEM,932
|
|
57
|
+
ngio/tables/backends/_json.py,sha256=1ZsEuXDJm1rOZV_KjFm8CB0qhv7L1W7L2EGWPf4q_p0,3137
|
|
58
|
+
ngio/tables/backends/_non_zarr_backends.py,sha256=BybUl800pqCdqJJmsGnUi4jsH1ibpQSUl0ZnumkFDwY,7298
|
|
59
|
+
ngio/tables/backends/_parquet.py,sha256=ic-p86h8lce8q9luBJGRzy6vxlWyJvA0-2l5cUD6OqY,1398
|
|
60
|
+
ngio/tables/backends/_table_backends.py,sha256=ksP2NAosXZkNMZf-IMrLx7bjQgp_eKfvPYK4vMdT1A8,7250
|
|
61
|
+
ngio/tables/backends/_utils.py,sha256=YFB7u2_l8lLAK_jrmlSfzH-2sOAFaDP1bmeUfuNo7YM,19719
|
|
62
|
+
ngio/tables/v1/__init__.py,sha256=Wr1_9RZFpaN8FYMTnxT9Yjkw4AS7y9FMWailmB_uj5g,617
|
|
63
|
+
ngio/tables/v1/_condition_table.py,sha256=T0Uq5BKkmMoEspt_Rx0U99Ow6S9GAMZDHqvUO5obCAM,1780
|
|
64
|
+
ngio/tables/v1/_feature_table.py,sha256=n9uMHwoBh-_dlOhUXCFbmAjXFVXncNCR3SjE2qzXI68,3821
|
|
65
|
+
ngio/tables/v1/_generic_table.py,sha256=1ktJHeuv7U1g5Z8PFUuTkCjOzcYMQd8xegKHKUedJB8,1240
|
|
66
|
+
ngio/tables/v1/_roi_table.py,sha256=szhtLzHWW-DaDz_OsGK89ur-WpNufCSMvEc66DRzv8g,16867
|
|
67
|
+
ngio/utils/__init__.py,sha256=XPYh8ehC7uXNU2cFFXZAw-S3DpWpX1Yq2xGkffZv5vI,1142
|
|
68
|
+
ngio/utils/_datasets.py,sha256=2g-Neg78dNcqyDz39QQw-Ifp9GITHjVHisdqgvvDNDE,5475
|
|
69
|
+
ngio/utils/_errors.py,sha256=pKQ12LUjQLYE1nUawemA5h7HsgznjaSvV1n2PQU33N0,759
|
|
70
|
+
ngio/utils/_fractal_fsspec_store.py,sha256=RdcCFOgHexRKX9zZvJV5RI-5OPc7VOPS6q_IeRxm24I,1548
|
|
71
|
+
ngio/utils/_logger.py,sha256=N5W0a_xwze4blS1MolidBkTMbjTbg8GPguJZNun3mAE,1392
|
|
72
|
+
ngio/utils/_zarr_utils.py,sha256=aYHhjHWGy5Jx7IkPb4nt9N0-HgyvJnyvK9GGqnccZkE,13606
|
|
73
|
+
ngio-0.4.0a2.dist-info/METADATA,sha256=Wd5zLtu8OLbjEbgV9Lb5FDlBP9dFT9QU4S8h2358jKc,5868
|
|
74
|
+
ngio-0.4.0a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
75
|
+
ngio-0.4.0a2.dist-info/licenses/LICENSE,sha256=UgN_a1QCeNh9rZWfz-wORQFxE3elQzLWPQaoK6N6fxQ,1502
|
|
76
|
+
ngio-0.4.0a2.dist-info/RECORD,,
|