ngio 0.3.0a0__py3-none-any.whl → 0.3.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/_array_pipe.py +50 -27
- ngio/common/_table_ops.py +1 -1
- ngio/hcs/__init__.py +1 -1
- ngio/hcs/{plate.py → _plate.py} +27 -12
- ngio/images/__init__.py +3 -3
- ngio/images/{image.py → _image.py} +26 -21
- ngio/images/{label.py → _label.py} +6 -4
- ngio/images/{masked_image.py → _masked_image.py} +2 -2
- ngio/images/{ome_zarr_container.py → _ome_zarr_container.py} +59 -24
- ngio/ome_zarr_meta/_meta_handlers.py +16 -8
- ngio/ome_zarr_meta/ngio_specs/_axes.py +4 -7
- ngio/ome_zarr_meta/ngio_specs/_channels.py +41 -29
- ngio/tables/__init__.py +7 -2
- ngio/tables/{abstract_table.py → _abstract_table.py} +5 -4
- ngio/tables/{tables_container.py → _tables_container.py} +42 -29
- ngio/tables/backends/__init__.py +6 -4
- ngio/tables/backends/_abstract_backend.py +1 -1
- ngio/tables/backends/{_anndata_v1.py → _anndata.py} +1 -1
- ngio/tables/backends/{_csv_v1.py → _csv.py} +2 -2
- ngio/tables/backends/{_json_v1.py → _json.py} +1 -1
- ngio/tables/backends/{_parquet_v1.py → _parquet.py} +2 -2
- ngio/tables/backends/_table_backends.py +41 -17
- ngio/tables/v1/__init__.py +12 -3
- ngio/tables/v1/_condition_table.py +8 -4
- ngio/tables/v1/_feature_table.py +11 -13
- ngio/tables/v1/_generic_table.py +14 -3
- ngio/tables/v1/_roi_table.py +11 -7
- ngio/utils/_fractal_fsspec_store.py +1 -1
- {ngio-0.3.0a0.dist-info → ngio-0.3.1.dist-info}/METADATA +69 -35
- ngio-0.3.1.dist-info/RECORD +61 -0
- ngio-0.3.0a0.dist-info/RECORD +0 -61
- /ngio/images/{abstract_image.py → _abstract_image.py} +0 -0
- /ngio/images/{create.py → _create.py} +0 -0
- /ngio/tables/backends/{_non_zarr_backends_v1.py → _non_zarr_backends.py} +0 -0
- {ngio-0.3.0a0.dist-info → ngio-0.3.1.dist-info}/WHEEL +0 -0
- {ngio-0.3.0a0.dist-info → ngio-0.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Collection
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from logging import Logger
|
|
6
5
|
from typing import Literal, TypeVar
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
from pydantic import BaseModel, ConfigDict, Field
|
|
10
9
|
|
|
11
|
-
from ngio.utils import NgioValidationError, NgioValueError
|
|
12
|
-
|
|
13
|
-
logger = Logger(__name__)
|
|
10
|
+
from ngio.utils import NgioValidationError, NgioValueError, ngio_logger
|
|
14
11
|
|
|
15
12
|
T = TypeVar("T")
|
|
16
13
|
|
|
@@ -102,20 +99,20 @@ class Axis(BaseModel):
|
|
|
102
99
|
def implicit_type_cast(self, cast_type: AxisType) -> "Axis":
|
|
103
100
|
unit = self.unit
|
|
104
101
|
if self.axis_type != cast_type:
|
|
105
|
-
|
|
102
|
+
ngio_logger.warning(
|
|
106
103
|
f"Axis {self.on_disk_name} has type {self.axis_type}. "
|
|
107
104
|
f"Casting to {cast_type}."
|
|
108
105
|
)
|
|
109
106
|
|
|
110
107
|
if cast_type == AxisType.time and unit is None:
|
|
111
|
-
|
|
108
|
+
ngio_logger.warning(
|
|
112
109
|
f"Time axis {self.on_disk_name} has unit {self.unit}. "
|
|
113
110
|
f"Casting to {DefaultSpaceUnit}."
|
|
114
111
|
)
|
|
115
112
|
unit = DefaultTimeUnit
|
|
116
113
|
|
|
117
114
|
if cast_type == AxisType.space and unit is None:
|
|
118
|
-
|
|
115
|
+
ngio_logger.warning(
|
|
119
116
|
f"Space axis {self.on_disk_name} has unit {unit}. "
|
|
120
117
|
f"Casting to {DefaultSpaceUnit}."
|
|
121
118
|
)
|
|
@@ -329,33 +329,35 @@ class ChannelsMeta(BaseModel):
|
|
|
329
329
|
@classmethod
|
|
330
330
|
def default_init(
|
|
331
331
|
cls,
|
|
332
|
-
labels: Collection[str] | int,
|
|
333
|
-
wavelength_id: Collection[str] | None = None,
|
|
334
|
-
colors: Collection[str | NgioColors] | None = None,
|
|
335
|
-
start: Collection[int | float] | int | float | None = None,
|
|
336
|
-
end: Collection[int | float] | int | float | None = None,
|
|
337
|
-
active: Collection[bool] | None = None,
|
|
332
|
+
labels: Collection[str | None] | int,
|
|
333
|
+
wavelength_id: Collection[str | None] | None = None,
|
|
334
|
+
colors: Collection[str | NgioColors | None] | None = None,
|
|
335
|
+
start: Collection[int | float | None] | int | float | None = None,
|
|
336
|
+
end: Collection[int | float | None] | int | float | None = None,
|
|
337
|
+
active: Collection[bool | None] | None = None,
|
|
338
338
|
data_type: Any = np.uint16,
|
|
339
339
|
**omero_kwargs: dict,
|
|
340
340
|
) -> "ChannelsMeta":
|
|
341
341
|
"""Create a ChannelsMeta object with the default unit.
|
|
342
342
|
|
|
343
343
|
Args:
|
|
344
|
-
labels(Collection[str] | int): The list of channels names
|
|
345
|
-
If an integer is provided, the channels will be
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
344
|
+
labels(Collection[str | None] | int): The list of channels names
|
|
345
|
+
in the image. If an integer is provided, the channels will be
|
|
346
|
+
named "channel_i".
|
|
347
|
+
wavelength_id(Collection[str | None] | None): The wavelength ID of the
|
|
348
|
+
channel. If None, the wavelength ID will be the same as the
|
|
349
|
+
channel name.
|
|
350
|
+
colors(Collection[str | NgioColors | None] | None): The list of
|
|
351
|
+
colors for the channels. If None, the colors will be random.
|
|
352
|
+
start(Collection[int | float | None] | int | float | None): The start
|
|
353
|
+
value of the channel. If None, the start value will be the
|
|
354
|
+
minimum value of the data type.
|
|
355
|
+
end(Collection[int | float | None] | int | float | None): The end
|
|
356
|
+
value of the channel. If None, the end value will be the
|
|
357
|
+
maximum value of the data type.
|
|
356
358
|
data_type(Any): The data type of the channel. Will be used to set the
|
|
357
359
|
min and max values of the channel.
|
|
358
|
-
active (Collection[bool] | None):
|
|
360
|
+
active (Collection[bool | None] | None): Whether the channel should
|
|
359
361
|
be shown by default.
|
|
360
362
|
omero_kwargs(dict): Extra fields to store in the omero attributes.
|
|
361
363
|
"""
|
|
@@ -366,25 +368,35 @@ class ChannelsMeta(BaseModel):
|
|
|
366
368
|
labels = _check_unique(labels)
|
|
367
369
|
|
|
368
370
|
_wavelength_id: Collection[str | None] = [None] * len(labels)
|
|
369
|
-
if
|
|
371
|
+
if wavelength_id is None:
|
|
372
|
+
_wavelength_id: Collection[str | None] = [None] * len(labels)
|
|
373
|
+
else:
|
|
370
374
|
_wavelength_id = _check_elements(wavelength_id, str)
|
|
371
375
|
_wavelength_id = _check_unique(wavelength_id)
|
|
372
376
|
|
|
373
|
-
|
|
374
|
-
|
|
377
|
+
if colors is None:
|
|
378
|
+
_colors = [NgioColors.semi_random_pick(label) for label in labels]
|
|
379
|
+
else:
|
|
375
380
|
_colors = _check_elements(colors, str | NgioColors)
|
|
376
381
|
|
|
377
|
-
|
|
378
|
-
|
|
382
|
+
if start is None:
|
|
383
|
+
_start = [None] * len(labels)
|
|
384
|
+
elif isinstance(start, int | float):
|
|
385
|
+
_start = [start] * len(labels)
|
|
386
|
+
else:
|
|
379
387
|
_start = _check_elements(start, (int, float))
|
|
380
388
|
|
|
381
|
-
|
|
382
|
-
|
|
389
|
+
if end is None:
|
|
390
|
+
_end = [None] * len(labels)
|
|
391
|
+
elif isinstance(end, int | float):
|
|
392
|
+
_end = [end] * len(labels)
|
|
393
|
+
else:
|
|
383
394
|
_end = _check_elements(end, (int, float))
|
|
384
395
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
396
|
+
if active is None:
|
|
397
|
+
_active = [True] * len(labels)
|
|
398
|
+
else:
|
|
399
|
+
_active = _check_elements(active, (bool,))
|
|
388
400
|
|
|
389
401
|
all_lengths = [
|
|
390
402
|
len(labels),
|
ngio/tables/__init__.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Ngio Tables implementations."""
|
|
2
2
|
|
|
3
|
-
from ngio.tables.
|
|
4
|
-
from ngio.tables.tables_container import (
|
|
3
|
+
from ngio.tables._tables_container import (
|
|
5
4
|
ConditionTable,
|
|
6
5
|
FeatureTable,
|
|
7
6
|
GenericRoiTable,
|
|
@@ -15,6 +14,11 @@ from ngio.tables.tables_container import (
|
|
|
15
14
|
open_table_as,
|
|
16
15
|
open_tables_container,
|
|
17
16
|
)
|
|
17
|
+
from ngio.tables.backends import (
|
|
18
|
+
ImplementedTableBackends,
|
|
19
|
+
TableBackend,
|
|
20
|
+
TableBackendProtocol,
|
|
21
|
+
)
|
|
18
22
|
from ngio.tables.v1._generic_table import GenericTable
|
|
19
23
|
|
|
20
24
|
__all__ = [
|
|
@@ -26,6 +30,7 @@ __all__ = [
|
|
|
26
30
|
"MaskingRoiTable",
|
|
27
31
|
"RoiTable",
|
|
28
32
|
"Table",
|
|
33
|
+
"TableBackend",
|
|
29
34
|
"TableBackendProtocol",
|
|
30
35
|
"TableType",
|
|
31
36
|
"TablesContainer",
|
|
@@ -11,6 +11,7 @@ from anndata import AnnData
|
|
|
11
11
|
from ngio.tables.backends import (
|
|
12
12
|
BackendMeta,
|
|
13
13
|
ImplementedTableBackends,
|
|
14
|
+
TableBackend,
|
|
14
15
|
TableBackendProtocol,
|
|
15
16
|
TabularData,
|
|
16
17
|
convert_to_anndata,
|
|
@@ -146,7 +147,7 @@ class AbstractBaseTable(ABC):
|
|
|
146
147
|
def _load_backend(
|
|
147
148
|
meta: BackendMeta,
|
|
148
149
|
handler: ZarrGroupHandler,
|
|
149
|
-
backend:
|
|
150
|
+
backend: TableBackend,
|
|
150
151
|
) -> TableBackendProtocol:
|
|
151
152
|
"""Create a new ROI table from a Zarr group handler."""
|
|
152
153
|
if isinstance(backend, str):
|
|
@@ -202,7 +203,7 @@ class AbstractBaseTable(ABC):
|
|
|
202
203
|
def set_backend(
|
|
203
204
|
self,
|
|
204
205
|
handler: ZarrGroupHandler | None = None,
|
|
205
|
-
backend:
|
|
206
|
+
backend: TableBackend = "anndata",
|
|
206
207
|
) -> None:
|
|
207
208
|
"""Set the backend of the table."""
|
|
208
209
|
if handler is None:
|
|
@@ -226,7 +227,7 @@ class AbstractBaseTable(ABC):
|
|
|
226
227
|
cls,
|
|
227
228
|
handler: ZarrGroupHandler,
|
|
228
229
|
meta_model: builtins.type[BackendMeta],
|
|
229
|
-
backend:
|
|
230
|
+
backend: TableBackend | None = None,
|
|
230
231
|
) -> Self:
|
|
231
232
|
"""Create a new ROI table from a Zarr group handler."""
|
|
232
233
|
meta = meta_model(**handler.load_attrs())
|
|
@@ -241,7 +242,7 @@ class AbstractBaseTable(ABC):
|
|
|
241
242
|
def from_handler(
|
|
242
243
|
cls,
|
|
243
244
|
handler: ZarrGroupHandler,
|
|
244
|
-
backend:
|
|
245
|
+
backend: TableBackend | None = None,
|
|
245
246
|
) -> Self:
|
|
246
247
|
"""Create a new ROI table from a Zarr group handler."""
|
|
247
248
|
pass
|
|
@@ -8,7 +8,7 @@ import polars as pl
|
|
|
8
8
|
|
|
9
9
|
from ngio.tables.backends import (
|
|
10
10
|
BackendMeta,
|
|
11
|
-
|
|
11
|
+
TableBackend,
|
|
12
12
|
TabularData,
|
|
13
13
|
)
|
|
14
14
|
from ngio.tables.v1 import (
|
|
@@ -90,7 +90,7 @@ class Table(Protocol):
|
|
|
90
90
|
def set_backend(
|
|
91
91
|
self,
|
|
92
92
|
handler: ZarrGroupHandler | None = None,
|
|
93
|
-
backend:
|
|
93
|
+
backend: TableBackend = "anndata",
|
|
94
94
|
) -> None:
|
|
95
95
|
"""Set the backend store and path for the table.
|
|
96
96
|
|
|
@@ -105,7 +105,7 @@ class Table(Protocol):
|
|
|
105
105
|
def from_handler(
|
|
106
106
|
cls,
|
|
107
107
|
handler: ZarrGroupHandler,
|
|
108
|
-
backend:
|
|
108
|
+
backend: TableBackend | None = None,
|
|
109
109
|
) -> "Table":
|
|
110
110
|
"""Create a new table from a Zarr group handler."""
|
|
111
111
|
...
|
|
@@ -126,25 +126,30 @@ class Table(Protocol):
|
|
|
126
126
|
|
|
127
127
|
|
|
128
128
|
TypedTable = Literal[
|
|
129
|
+
"generic_table",
|
|
129
130
|
"roi_table",
|
|
130
131
|
"masking_roi_table",
|
|
131
132
|
"feature_table",
|
|
132
|
-
"generic_roi_table",
|
|
133
133
|
"condition_table",
|
|
134
134
|
]
|
|
135
135
|
|
|
136
|
+
TypedRoiTable = Literal[
|
|
137
|
+
"roi_table",
|
|
138
|
+
"masking_roi_table",
|
|
139
|
+
]
|
|
140
|
+
|
|
136
141
|
TableType = TypeVar("TableType", bound=Table)
|
|
137
142
|
|
|
138
143
|
|
|
139
144
|
class TableMeta(BackendMeta):
|
|
140
145
|
"""Base class for table metadata."""
|
|
141
146
|
|
|
142
|
-
|
|
147
|
+
table_version: str = "1"
|
|
143
148
|
type: str = "generic_table"
|
|
144
149
|
|
|
145
150
|
def unique_name(self) -> str:
|
|
146
151
|
"""Return the unique name for the table."""
|
|
147
|
-
return f"{self.type}_v{self.
|
|
152
|
+
return f"{self.type}_v{self.table_version}"
|
|
148
153
|
|
|
149
154
|
|
|
150
155
|
def _get_meta(handler: ZarrGroupHandler) -> TableMeta:
|
|
@@ -175,7 +180,7 @@ class ImplementedTables:
|
|
|
175
180
|
self,
|
|
176
181
|
meta: TableMeta,
|
|
177
182
|
handler: ZarrGroupHandler,
|
|
178
|
-
backend:
|
|
183
|
+
backend: TableBackend | None = None,
|
|
179
184
|
strict: bool = True,
|
|
180
185
|
) -> Table:
|
|
181
186
|
"""Try to get a handler for the given store based on the metadata version."""
|
|
@@ -192,19 +197,34 @@ class ImplementedTables:
|
|
|
192
197
|
table = table_cls.from_handler(handler=handler, backend=backend)
|
|
193
198
|
return table
|
|
194
199
|
|
|
195
|
-
def
|
|
200
|
+
def _add_implementation(
|
|
201
|
+
self, handler: type[Table], name: str, overwrite: bool = False
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Register a new table handler."""
|
|
204
|
+
if name in self._implemented_tables and not overwrite:
|
|
205
|
+
raise NgioValueError(
|
|
206
|
+
f"Table handler for {name} already implemented. "
|
|
207
|
+
"Use overwrite=True to replace it."
|
|
208
|
+
)
|
|
209
|
+
self._implemented_tables[name] = handler
|
|
210
|
+
|
|
211
|
+
def add_implementation(
|
|
212
|
+
self,
|
|
213
|
+
handler: type[Table],
|
|
214
|
+
overwrite: bool = False,
|
|
215
|
+
aliases: list[str] | None = None,
|
|
216
|
+
) -> None:
|
|
196
217
|
"""Register a new table handler."""
|
|
197
218
|
meta = TableMeta(
|
|
198
219
|
type=handler.table_type(),
|
|
199
|
-
|
|
220
|
+
table_version=handler.version(),
|
|
200
221
|
)
|
|
201
222
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
self._implemented_tables[meta.unique_name()] = handler
|
|
223
|
+
self._add_implementation(handler, meta.unique_name(), overwrite)
|
|
224
|
+
|
|
225
|
+
if aliases is not None:
|
|
226
|
+
for alias in aliases:
|
|
227
|
+
self._add_implementation(handler, alias, overwrite)
|
|
208
228
|
|
|
209
229
|
|
|
210
230
|
class TablesContainer:
|
|
@@ -240,14 +260,7 @@ class TablesContainer:
|
|
|
240
260
|
handler = self._group_handler.derive_handler(path=name)
|
|
241
261
|
return handler
|
|
242
262
|
|
|
243
|
-
def
|
|
244
|
-
"""List all ROI tables in the group."""
|
|
245
|
-
_tables = []
|
|
246
|
-
for _type in ["roi_table", "masking_roi_table"]:
|
|
247
|
-
_tables.extend(self.list(_type))
|
|
248
|
-
return _tables
|
|
249
|
-
|
|
250
|
-
def list(self, filter_types: str | None = None) -> list[str]:
|
|
263
|
+
def list(self, filter_types: TypedTable | str | None = None) -> list[str]:
|
|
251
264
|
"""List all labels in the group."""
|
|
252
265
|
tables = self._get_tables_list()
|
|
253
266
|
if filter_types is None:
|
|
@@ -264,7 +277,7 @@ class TablesContainer:
|
|
|
264
277
|
def get(
|
|
265
278
|
self,
|
|
266
279
|
name: str,
|
|
267
|
-
backend:
|
|
280
|
+
backend: TableBackend | None = None,
|
|
268
281
|
strict: bool = True,
|
|
269
282
|
) -> Table:
|
|
270
283
|
"""Get a label from the group."""
|
|
@@ -285,7 +298,7 @@ class TablesContainer:
|
|
|
285
298
|
self,
|
|
286
299
|
name: str,
|
|
287
300
|
table_cls: type[TableType],
|
|
288
|
-
backend:
|
|
301
|
+
backend: TableBackend | None = None,
|
|
289
302
|
) -> TableType:
|
|
290
303
|
"""Get a table from the group as a specific type."""
|
|
291
304
|
if name not in self.list():
|
|
@@ -301,7 +314,7 @@ class TablesContainer:
|
|
|
301
314
|
self,
|
|
302
315
|
name: str,
|
|
303
316
|
table: Table,
|
|
304
|
-
backend:
|
|
317
|
+
backend: TableBackend = "anndata",
|
|
305
318
|
overwrite: bool = False,
|
|
306
319
|
) -> None:
|
|
307
320
|
"""Add a table to the group."""
|
|
@@ -357,7 +370,7 @@ def open_tables_container(
|
|
|
357
370
|
|
|
358
371
|
def open_table(
|
|
359
372
|
store: StoreOrGroup,
|
|
360
|
-
backend:
|
|
373
|
+
backend: TableBackend | None = None,
|
|
361
374
|
cache: bool = False,
|
|
362
375
|
mode: AccessModeLiteral = "a",
|
|
363
376
|
parallel_safe: bool = False,
|
|
@@ -375,7 +388,7 @@ def open_table(
|
|
|
375
388
|
def open_table_as(
|
|
376
389
|
store: StoreOrGroup,
|
|
377
390
|
table_cls: type[TableType],
|
|
378
|
-
backend:
|
|
391
|
+
backend: TableBackend | None = None,
|
|
379
392
|
cache: bool = False,
|
|
380
393
|
mode: AccessModeLiteral = "a",
|
|
381
394
|
parallel_safe: bool = False,
|
|
@@ -393,7 +406,7 @@ def open_table_as(
|
|
|
393
406
|
def write_table(
|
|
394
407
|
store: StoreOrGroup,
|
|
395
408
|
table: Table,
|
|
396
|
-
backend:
|
|
409
|
+
backend: TableBackend = "anndata",
|
|
397
410
|
cache: bool = False,
|
|
398
411
|
mode: AccessModeLiteral = "a",
|
|
399
412
|
parallel_safe: bool = False,
|
ngio/tables/backends/__init__.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"""Ngio Tables backend implementations."""
|
|
2
2
|
|
|
3
3
|
from ngio.tables.backends._abstract_backend import AbstractTableBackend, BackendMeta
|
|
4
|
-
from ngio.tables.backends.
|
|
5
|
-
from ngio.tables.backends.
|
|
6
|
-
from ngio.tables.backends.
|
|
7
|
-
from ngio.tables.backends.
|
|
4
|
+
from ngio.tables.backends._anndata import AnnDataBackend
|
|
5
|
+
from ngio.tables.backends._csv import CsvTableBackend
|
|
6
|
+
from ngio.tables.backends._json import JsonTableBackend
|
|
7
|
+
from ngio.tables.backends._parquet import ParquetTableBackend
|
|
8
8
|
from ngio.tables.backends._table_backends import (
|
|
9
9
|
ImplementedTableBackends,
|
|
10
|
+
TableBackend,
|
|
10
11
|
TableBackendProtocol,
|
|
11
12
|
)
|
|
12
13
|
from ngio.tables.backends._utils import (
|
|
@@ -34,6 +35,7 @@ __all__ = [
|
|
|
34
35
|
"ImplementedTableBackends",
|
|
35
36
|
"JsonTableBackend",
|
|
36
37
|
"ParquetTableBackend",
|
|
38
|
+
"TableBackend",
|
|
37
39
|
"TableBackendProtocol",
|
|
38
40
|
"TabularData",
|
|
39
41
|
"convert_anndata_to_pandas",
|
|
@@ -19,7 +19,7 @@ from ngio.utils import NgioValueError, ZarrGroupHandler
|
|
|
19
19
|
class BackendMeta(BaseModel):
|
|
20
20
|
"""Metadata for the backend."""
|
|
21
21
|
|
|
22
|
-
backend: str = "
|
|
22
|
+
backend: str = "anndata"
|
|
23
23
|
index_key: str | None = None
|
|
24
24
|
index_type: Literal["int", "str"] | None = None
|
|
25
25
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import polars as pl
|
|
3
3
|
|
|
4
|
-
from ngio.tables.backends.
|
|
4
|
+
from ngio.tables.backends._non_zarr_backends import NonZarrBaseBackend
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def write_lf_to_csv(path: str, table: pl.DataFrame) -> None:
|
|
@@ -32,4 +32,4 @@ class CsvTableBackend(NonZarrBaseBackend):
|
|
|
32
32
|
@staticmethod
|
|
33
33
|
def backend_name() -> str:
|
|
34
34
|
"""Return the name of the backend."""
|
|
35
|
-
return "
|
|
35
|
+
return "csv"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import polars as pl
|
|
3
3
|
|
|
4
|
-
from ngio.tables.backends.
|
|
4
|
+
from ngio.tables.backends._non_zarr_backends import NonZarrBaseBackend
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def write_lf_to_parquet(path: str, table: pl.DataFrame) -> None:
|
|
@@ -44,4 +44,4 @@ class ParquetTableBackend(NonZarrBaseBackend):
|
|
|
44
44
|
@staticmethod
|
|
45
45
|
def backend_name() -> str:
|
|
46
46
|
"""Return the name of the backend."""
|
|
47
|
-
return "
|
|
47
|
+
return "parquet"
|
|
@@ -7,10 +7,10 @@ from pandas import DataFrame
|
|
|
7
7
|
from polars import DataFrame as PolarsDataFrame
|
|
8
8
|
from polars import LazyFrame
|
|
9
9
|
|
|
10
|
-
from ngio.tables.backends.
|
|
11
|
-
from ngio.tables.backends.
|
|
12
|
-
from ngio.tables.backends.
|
|
13
|
-
from ngio.tables.backends.
|
|
10
|
+
from ngio.tables.backends._anndata import AnnDataBackend
|
|
11
|
+
from ngio.tables.backends._csv import CsvTableBackend
|
|
12
|
+
from ngio.tables.backends._json import JsonTableBackend
|
|
13
|
+
from ngio.tables.backends._parquet import ParquetTableBackend
|
|
14
14
|
from ngio.tables.backends._utils import TabularData
|
|
15
15
|
from ngio.utils import NgioValueError, ZarrGroupHandler
|
|
16
16
|
|
|
@@ -167,7 +167,7 @@ class ImplementedTableBackends:
|
|
|
167
167
|
self,
|
|
168
168
|
*,
|
|
169
169
|
group_handler: ZarrGroupHandler,
|
|
170
|
-
backend_name: str = "
|
|
170
|
+
backend_name: str = "anndata",
|
|
171
171
|
index_key: str | None = None,
|
|
172
172
|
index_type: Literal["int", "str"] | None = None,
|
|
173
173
|
) -> TableBackendProtocol:
|
|
@@ -180,22 +180,46 @@ class ImplementedTableBackends:
|
|
|
180
180
|
)
|
|
181
181
|
return backend
|
|
182
182
|
|
|
183
|
-
def
|
|
183
|
+
def _add_backend(
|
|
184
184
|
self,
|
|
185
|
-
|
|
185
|
+
table_backend: type[TableBackendProtocol],
|
|
186
|
+
name: str,
|
|
186
187
|
overwrite: bool = False,
|
|
187
|
-
):
|
|
188
|
+
) -> None:
|
|
188
189
|
"""Register a new handler."""
|
|
189
|
-
|
|
190
|
-
if backend_name in self._implemented_backends and not overwrite:
|
|
190
|
+
if name in self._implemented_backends and not overwrite:
|
|
191
191
|
raise NgioValueError(
|
|
192
|
-
f"Table backend {
|
|
192
|
+
f"Table backend {name} already implemented. "
|
|
193
193
|
"Use the `overwrite=True` parameter to overwrite it."
|
|
194
194
|
)
|
|
195
|
-
self._implemented_backends[
|
|
196
|
-
|
|
195
|
+
self._implemented_backends[name] = table_backend
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
def add_backend(
|
|
198
|
+
self,
|
|
199
|
+
table_backend: type[TableBackendProtocol],
|
|
200
|
+
overwrite: bool = False,
|
|
201
|
+
aliases: list[str] | None = None,
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Register a new handler."""
|
|
204
|
+
self._add_backend(
|
|
205
|
+
table_backend=table_backend,
|
|
206
|
+
name=table_backend.backend_name(),
|
|
207
|
+
overwrite=overwrite,
|
|
208
|
+
)
|
|
209
|
+
if aliases is not None:
|
|
210
|
+
for alias in aliases:
|
|
211
|
+
self._add_backend(
|
|
212
|
+
table_backend=table_backend, name=alias, overwrite=overwrite
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
ImplementedTableBackends().add_backend(AnnDataBackend, aliases=["anndata_v1"])
|
|
217
|
+
ImplementedTableBackends().add_backend(
|
|
218
|
+
JsonTableBackend, aliases=["experimental_json_v1"]
|
|
219
|
+
)
|
|
220
|
+
ImplementedTableBackends().add_backend(CsvTableBackend, aliases=["experimental_csv_v1"])
|
|
221
|
+
ImplementedTableBackends().add_backend(
|
|
222
|
+
ParquetTableBackend, aliases=["experimental_parquet_v1"]
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
TableBackend = Literal["anndata", "json", "csv", "parquet"] | str | TableBackendProtocol
|
ngio/tables/v1/__init__.py
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
"""Tables implementations for fractal_tables v1."""
|
|
2
2
|
|
|
3
|
-
from ngio.tables.v1._condition_table import ConditionTableV1
|
|
4
|
-
from ngio.tables.v1._feature_table import FeatureTableV1
|
|
3
|
+
from ngio.tables.v1._condition_table import ConditionTableMeta, ConditionTableV1
|
|
4
|
+
from ngio.tables.v1._feature_table import FeatureTableMeta, FeatureTableV1
|
|
5
5
|
from ngio.tables.v1._generic_table import GenericTable
|
|
6
|
-
from ngio.tables.v1._roi_table import
|
|
6
|
+
from ngio.tables.v1._roi_table import (
|
|
7
|
+
MaskingRoiTableV1,
|
|
8
|
+
MaskingRoiTableV1Meta,
|
|
9
|
+
RoiTableV1,
|
|
10
|
+
RoiTableV1Meta,
|
|
11
|
+
)
|
|
7
12
|
|
|
8
13
|
__all__ = [
|
|
14
|
+
"ConditionTableMeta",
|
|
9
15
|
"ConditionTableV1",
|
|
16
|
+
"FeatureTableMeta",
|
|
10
17
|
"FeatureTableV1",
|
|
11
18
|
"GenericTable",
|
|
12
19
|
"MaskingRoiTableV1",
|
|
20
|
+
"MaskingRoiTableV1Meta",
|
|
13
21
|
"RoiTableV1",
|
|
22
|
+
"RoiTableV1Meta",
|
|
14
23
|
]
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
"""Implementation of a generic table class."""
|
|
2
2
|
|
|
3
|
-
from ngio.tables.
|
|
4
|
-
from ngio.tables.backends import
|
|
3
|
+
from ngio.tables._abstract_table import AbstractBaseTable
|
|
4
|
+
from ngio.tables.backends import (
|
|
5
|
+
BackendMeta,
|
|
6
|
+
TableBackend,
|
|
7
|
+
TabularData,
|
|
8
|
+
)
|
|
5
9
|
from ngio.utils import ZarrGroupHandler
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
class ConditionTableMeta(BackendMeta):
|
|
9
13
|
"""Metadata for the condition table."""
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
table_version: str | None = "1"
|
|
12
16
|
type: str | None = "condition_table"
|
|
13
17
|
|
|
14
18
|
|
|
@@ -58,7 +62,7 @@ class ConditionTableV1(AbstractBaseTable):
|
|
|
58
62
|
def from_handler(
|
|
59
63
|
cls,
|
|
60
64
|
handler: ZarrGroupHandler,
|
|
61
|
-
backend:
|
|
65
|
+
backend: TableBackend | None = None,
|
|
62
66
|
) -> "ConditionTableV1":
|
|
63
67
|
return cls._from_handler(
|
|
64
68
|
handler=handler,
|