ngio 0.2.9__py3-none-any.whl → 0.3.0__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/__init__.py +16 -0
- ngio/common/_array_pipe.py +50 -27
- ngio/common/_table_ops.py +471 -0
- ngio/hcs/__init__.py +1 -1
- ngio/hcs/{plate.py → _plate.py} +451 -78
- 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} +152 -86
- ngio/ome_zarr_meta/_meta_handlers.py +16 -8
- ngio/ome_zarr_meta/ngio_specs/_channels.py +41 -29
- ngio/tables/__init__.py +14 -2
- ngio/tables/_abstract_table.py +269 -0
- ngio/tables/{tables_container.py → _tables_container.py} +186 -100
- ngio/tables/backends/__init__.py +20 -0
- ngio/tables/backends/_abstract_backend.py +58 -80
- ngio/tables/backends/{_anndata_v1.py → _anndata.py} +5 -1
- ngio/tables/backends/_csv.py +35 -0
- ngio/tables/backends/{_json_v1.py → _json.py} +4 -1
- ngio/tables/backends/{_csv_v1.py → _non_zarr_backends.py} +61 -27
- ngio/tables/backends/_parquet.py +47 -0
- ngio/tables/backends/_table_backends.py +39 -18
- ngio/tables/backends/_utils.py +147 -1
- ngio/tables/v1/__init__.py +19 -3
- ngio/tables/v1/_condition_table.py +71 -0
- ngio/tables/v1/_feature_table.py +63 -129
- ngio/tables/v1/_generic_table.py +21 -159
- ngio/tables/v1/_roi_table.py +285 -201
- ngio/utils/_fractal_fsspec_store.py +29 -0
- {ngio-0.2.9.dist-info → ngio-0.3.0.dist-info}/METADATA +4 -3
- ngio-0.3.0.dist-info/RECORD +61 -0
- ngio/tables/_validators.py +0 -108
- ngio-0.2.9.dist-info/RECORD +0 -57
- /ngio/images/{abstract_image.py → _abstract_image.py} +0 -0
- /ngio/images/{create.py → _create.py} +0 -0
- {ngio-0.2.9.dist-info → ngio-0.3.0.dist-info}/WHEEL +0 -0
- {ngio-0.2.9.dist-info → ngio-0.3.0.dist-info}/licenses/LICENSE +0 -0
ngio/tables/backends/_utils.py
CHANGED
|
@@ -9,7 +9,6 @@ These functions are used to validate and normalize the tables
|
|
|
9
9
|
to ensure that conversion between formats is consistent.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
# %%
|
|
13
12
|
from copy import deepcopy
|
|
14
13
|
from typing import Literal
|
|
15
14
|
|
|
@@ -24,6 +23,8 @@ from polars import LazyFrame
|
|
|
24
23
|
|
|
25
24
|
from ngio.utils import NgioTableValidationError, NgioValueError
|
|
26
25
|
|
|
26
|
+
TabularData = AnnData | DataFrame | PolarsDataFrame | LazyFrame
|
|
27
|
+
|
|
27
28
|
# -----------------
|
|
28
29
|
# Validation utils
|
|
29
30
|
# -----------------
|
|
@@ -460,3 +461,148 @@ def convert_polars_to_anndata(
|
|
|
460
461
|
pandas_df,
|
|
461
462
|
index_key=index_key,
|
|
462
463
|
)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
# -----------------
|
|
467
|
+
# Conversion functions
|
|
468
|
+
# -----------------
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def normalize_table(
|
|
472
|
+
table_data: TabularData,
|
|
473
|
+
index_key: str | None = None,
|
|
474
|
+
index_type: Literal["int", "str"] | None = None,
|
|
475
|
+
) -> TabularData:
|
|
476
|
+
"""Normalize a table to a specific format.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
table_data (TabularData): The table to normalize.
|
|
480
|
+
index_key (str | None): The column name to use as the index of the DataFrame.
|
|
481
|
+
Default is None.
|
|
482
|
+
index_type (str | None): The type of the index column in the DataFrame.
|
|
483
|
+
Either 'str' or 'int'. Default is None.
|
|
484
|
+
|
|
485
|
+
Returns:
|
|
486
|
+
DataFrame | AnnData | PolarsDataFrame | LazyFrame: Normalized table.
|
|
487
|
+
"""
|
|
488
|
+
if isinstance(table_data, DataFrame):
|
|
489
|
+
return normalize_pandas_df(
|
|
490
|
+
table_data,
|
|
491
|
+
index_key=index_key,
|
|
492
|
+
index_type=index_type,
|
|
493
|
+
reset_index=False,
|
|
494
|
+
)
|
|
495
|
+
if isinstance(table_data, AnnData):
|
|
496
|
+
return normalize_anndata(table_data, index_key=index_key)
|
|
497
|
+
if isinstance(table_data, PolarsDataFrame) or isinstance(table_data, LazyFrame):
|
|
498
|
+
return normalize_polars_lf(
|
|
499
|
+
table_data,
|
|
500
|
+
index_key=index_key,
|
|
501
|
+
index_type=index_type,
|
|
502
|
+
)
|
|
503
|
+
raise NgioValueError(f"Unsupported table type: {type(table_data)}")
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def convert_to_anndata(
|
|
507
|
+
table_data: TabularData,
|
|
508
|
+
index_key: str | None = None,
|
|
509
|
+
) -> AnnData:
|
|
510
|
+
"""Convert a table to an AnnData object.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
table_data (TabularData): The table to convert.
|
|
514
|
+
index_key (str | None): The column name to use as the index of the DataFrame.
|
|
515
|
+
Default is None.
|
|
516
|
+
|
|
517
|
+
Returns:
|
|
518
|
+
AnnData: Converted AnnData object.
|
|
519
|
+
"""
|
|
520
|
+
if isinstance(table_data, AnnData):
|
|
521
|
+
return normalize_anndata(table_data, index_key=index_key)
|
|
522
|
+
if isinstance(table_data, DataFrame):
|
|
523
|
+
return convert_pandas_to_anndata(table_data, index_key=index_key)
|
|
524
|
+
if isinstance(table_data, PolarsDataFrame) or isinstance(table_data, LazyFrame):
|
|
525
|
+
return convert_polars_to_anndata(table_data, index_key=index_key)
|
|
526
|
+
raise NgioValueError(f"Unsupported table type: {type(table_data)}")
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def convert_to_pandas(
|
|
530
|
+
table_data: TabularData,
|
|
531
|
+
index_key: str | None = None,
|
|
532
|
+
index_type: Literal["int", "str"] | None = None,
|
|
533
|
+
reset_index: bool = False,
|
|
534
|
+
) -> DataFrame:
|
|
535
|
+
"""Convert a table to a pandas DataFrame.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
table_data (TabularData): The table to convert.
|
|
539
|
+
index_key (str | None): The column name to use as the index of the DataFrame.
|
|
540
|
+
Default is None.
|
|
541
|
+
index_type (str | None): The type of the index column in the DataFrame.
|
|
542
|
+
Either 'str' or 'int'. Default is None.
|
|
543
|
+
reset_index (bool): If True the index will be reset (i.e., the index will be
|
|
544
|
+
converted to a column). If False, the index will be kept as is.
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
DataFrame: Converted pandas DataFrame.
|
|
548
|
+
"""
|
|
549
|
+
if isinstance(table_data, DataFrame):
|
|
550
|
+
return normalize_pandas_df(
|
|
551
|
+
table_data,
|
|
552
|
+
index_key=index_key,
|
|
553
|
+
index_type=index_type,
|
|
554
|
+
reset_index=reset_index,
|
|
555
|
+
)
|
|
556
|
+
if isinstance(table_data, AnnData):
|
|
557
|
+
return convert_anndata_to_pandas(
|
|
558
|
+
table_data,
|
|
559
|
+
index_key=index_key,
|
|
560
|
+
index_type=index_type,
|
|
561
|
+
reset_index=reset_index,
|
|
562
|
+
)
|
|
563
|
+
if isinstance(table_data, PolarsDataFrame) or isinstance(table_data, LazyFrame):
|
|
564
|
+
return convert_polars_to_pandas(
|
|
565
|
+
table_data,
|
|
566
|
+
index_key=index_key,
|
|
567
|
+
index_type=index_type,
|
|
568
|
+
reset_index=reset_index,
|
|
569
|
+
)
|
|
570
|
+
raise NgioValueError(f"Unsupported table type: {type(table_data)}")
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def convert_to_polars(
|
|
574
|
+
table_data: TabularData,
|
|
575
|
+
index_key: str | None = None,
|
|
576
|
+
index_type: Literal["int", "str"] | None = None,
|
|
577
|
+
) -> LazyFrame:
|
|
578
|
+
"""Convert a table to a polars LazyFrame.
|
|
579
|
+
|
|
580
|
+
Args:
|
|
581
|
+
table_data (TabularData): The table to convert.
|
|
582
|
+
index_key (str | None): The column name to use as the index of the DataFrame.
|
|
583
|
+
Default is None.
|
|
584
|
+
index_type (str | None): The type of the index column in the DataFrame.
|
|
585
|
+
Either 'str' or 'int'. Default is None.
|
|
586
|
+
|
|
587
|
+
Returns:
|
|
588
|
+
LazyFrame: Converted polars LazyFrame.
|
|
589
|
+
"""
|
|
590
|
+
if isinstance(table_data, PolarsDataFrame) or isinstance(table_data, LazyFrame):
|
|
591
|
+
return normalize_polars_lf(
|
|
592
|
+
table_data,
|
|
593
|
+
index_key=index_key,
|
|
594
|
+
index_type=index_type,
|
|
595
|
+
)
|
|
596
|
+
if isinstance(table_data, DataFrame):
|
|
597
|
+
return convert_pandas_to_polars(
|
|
598
|
+
table_data,
|
|
599
|
+
index_key=index_key,
|
|
600
|
+
index_type=index_type,
|
|
601
|
+
)
|
|
602
|
+
if isinstance(table_data, AnnData):
|
|
603
|
+
return convert_anndata_to_polars(
|
|
604
|
+
table_data,
|
|
605
|
+
index_key=index_key,
|
|
606
|
+
index_type=index_type,
|
|
607
|
+
)
|
|
608
|
+
raise NgioValueError(f"Unsupported table type: {type(table_data)}")
|
ngio/tables/v1/__init__.py
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
"""Tables implementations for fractal_tables v1."""
|
|
2
2
|
|
|
3
|
-
from ngio.tables.v1.
|
|
3
|
+
from ngio.tables.v1._condition_table import ConditionTableMeta, ConditionTableV1
|
|
4
|
+
from ngio.tables.v1._feature_table import FeatureTableMeta, FeatureTableV1
|
|
4
5
|
from ngio.tables.v1._generic_table import GenericTable
|
|
5
|
-
from ngio.tables.v1._roi_table import
|
|
6
|
+
from ngio.tables.v1._roi_table import (
|
|
7
|
+
MaskingRoiTableV1,
|
|
8
|
+
MaskingRoiTableV1Meta,
|
|
9
|
+
RoiTableV1,
|
|
10
|
+
RoiTableV1Meta,
|
|
11
|
+
)
|
|
6
12
|
|
|
7
|
-
__all__ = [
|
|
13
|
+
__all__ = [
|
|
14
|
+
"ConditionTableMeta",
|
|
15
|
+
"ConditionTableV1",
|
|
16
|
+
"FeatureTableMeta",
|
|
17
|
+
"FeatureTableV1",
|
|
18
|
+
"GenericTable",
|
|
19
|
+
"MaskingRoiTableV1",
|
|
20
|
+
"MaskingRoiTableV1Meta",
|
|
21
|
+
"RoiTableV1",
|
|
22
|
+
"RoiTableV1Meta",
|
|
23
|
+
]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Implementation of a generic table class."""
|
|
2
|
+
|
|
3
|
+
from ngio.tables._abstract_table import AbstractBaseTable
|
|
4
|
+
from ngio.tables.backends import (
|
|
5
|
+
BackendMeta,
|
|
6
|
+
TableBackend,
|
|
7
|
+
TabularData,
|
|
8
|
+
)
|
|
9
|
+
from ngio.utils import ZarrGroupHandler
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConditionTableMeta(BackendMeta):
|
|
13
|
+
"""Metadata for the condition table."""
|
|
14
|
+
|
|
15
|
+
table_version: str | None = "1"
|
|
16
|
+
type: str | None = "condition_table"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ConditionTableV1(AbstractBaseTable):
|
|
20
|
+
"""Condition table class.
|
|
21
|
+
|
|
22
|
+
This class is used to load a condition table.
|
|
23
|
+
The condition table is a generic table that does not
|
|
24
|
+
have a specific definition.
|
|
25
|
+
|
|
26
|
+
It is used to store informations about the particular conditions
|
|
27
|
+
used to generate the data.
|
|
28
|
+
- How much drug was used in the experiment
|
|
29
|
+
- What treatment was used
|
|
30
|
+
- etc.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
table_data: TabularData | None = None,
|
|
36
|
+
*,
|
|
37
|
+
meta: ConditionTableMeta | None = None,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Initialize the ConditionTable."""
|
|
40
|
+
if meta is None:
|
|
41
|
+
meta = ConditionTableMeta()
|
|
42
|
+
|
|
43
|
+
super().__init__(
|
|
44
|
+
table_data=table_data,
|
|
45
|
+
meta=meta,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def table_type() -> str:
|
|
50
|
+
"""Return the type of the table."""
|
|
51
|
+
return "condition_table"
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def version() -> str:
|
|
55
|
+
"""The generic table does not have a version.
|
|
56
|
+
|
|
57
|
+
Since does not follow a specific schema.
|
|
58
|
+
"""
|
|
59
|
+
return "1"
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def from_handler(
|
|
63
|
+
cls,
|
|
64
|
+
handler: ZarrGroupHandler,
|
|
65
|
+
backend: TableBackend | None = None,
|
|
66
|
+
) -> "ConditionTableV1":
|
|
67
|
+
return cls._from_handler(
|
|
68
|
+
handler=handler,
|
|
69
|
+
backend=backend,
|
|
70
|
+
meta_model=ConditionTableMeta,
|
|
71
|
+
)
|
ngio/tables/v1/_feature_table.py
CHANGED
|
@@ -6,12 +6,12 @@ https://fractal-analytics-platform.github.io/fractal-tasks-core/tables/
|
|
|
6
6
|
|
|
7
7
|
from typing import Literal
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
from pydantic import BaseModel
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
11
10
|
|
|
12
|
-
from ngio.tables.
|
|
13
|
-
from ngio.tables.backends
|
|
14
|
-
from ngio.utils import NgioValueError
|
|
11
|
+
from ngio.tables._abstract_table import AbstractBaseTable
|
|
12
|
+
from ngio.tables.backends import BackendMeta, TableBackend, TabularData
|
|
13
|
+
from ngio.utils import NgioValueError
|
|
14
|
+
from ngio.utils._zarr_utils import ZarrGroupHandler
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class RegionMeta(BaseModel):
|
|
@@ -23,42 +23,52 @@ class RegionMeta(BaseModel):
|
|
|
23
23
|
class FeatureTableMeta(BackendMeta):
|
|
24
24
|
"""Metadata for the ROI table."""
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
table_version: Literal["1"] = "1"
|
|
27
27
|
type: Literal["feature_table"] = "feature_table"
|
|
28
28
|
region: RegionMeta | None = None
|
|
29
|
-
instance_key: str = "label"
|
|
29
|
+
instance_key: str = "label" # Legacy field, kept for compatibility
|
|
30
|
+
# Backend metadata
|
|
31
|
+
index_key: str | None = "label"
|
|
32
|
+
index_type: Literal["int", "str"] | None = "int"
|
|
33
|
+
# Columns optional types
|
|
34
|
+
categorical_columns: list[str] = Field(default_factory=list)
|
|
35
|
+
measurement_columns: list[str] = Field(default_factory=list)
|
|
36
|
+
metadata_columns: list[str] = Field(default_factory=list)
|
|
30
37
|
|
|
31
38
|
|
|
32
|
-
class FeatureTableV1:
|
|
33
|
-
"""Class to represent a feature table.
|
|
34
|
-
|
|
35
|
-
This can be used to load any table that does not have
|
|
36
|
-
a specific definition.
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
+
class FeatureTableV1(AbstractBaseTable):
|
|
39
40
|
def __init__(
|
|
40
41
|
self,
|
|
41
|
-
|
|
42
|
+
table_data: TabularData | None = None,
|
|
43
|
+
*,
|
|
42
44
|
reference_label: str | None = None,
|
|
45
|
+
meta: FeatureTableMeta | None = None,
|
|
43
46
|
) -> None:
|
|
44
47
|
"""Initialize the GenericTable."""
|
|
45
|
-
if
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
if meta is None:
|
|
49
|
+
meta = FeatureTableMeta()
|
|
50
|
+
|
|
51
|
+
if reference_label is not None:
|
|
48
52
|
path = f"../labels/{reference_label}"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
else:
|
|
55
|
-
self._dataframe = normalize_pandas_df(
|
|
56
|
-
dataframe,
|
|
57
|
-
index_key=self._instance_key,
|
|
58
|
-
index_type="int",
|
|
59
|
-
reset_index=False,
|
|
53
|
+
meta = FeatureTableMeta(region=RegionMeta(path=path))
|
|
54
|
+
|
|
55
|
+
if table_data is not None and not isinstance(table_data, TabularData):
|
|
56
|
+
raise NgioValueError(
|
|
57
|
+
f"The table is not of type SupportedTables. Got {type(table_data)}"
|
|
60
58
|
)
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
if meta.index_key is None:
|
|
61
|
+
meta.index_key = "label"
|
|
62
|
+
|
|
63
|
+
if meta.index_type is None:
|
|
64
|
+
meta.index_type = "int"
|
|
65
|
+
|
|
66
|
+
meta.instance_key = meta.index_key
|
|
67
|
+
|
|
68
|
+
super().__init__(
|
|
69
|
+
table_data=table_data,
|
|
70
|
+
meta=meta,
|
|
71
|
+
)
|
|
62
72
|
|
|
63
73
|
def __repr__(self) -> str:
|
|
64
74
|
"""Return a string representation of the table."""
|
|
@@ -69,8 +79,29 @@ class FeatureTableV1:
|
|
|
69
79
|
properties += f", reference_label={self.reference_label}"
|
|
70
80
|
return f"FeatureTableV1({properties})"
|
|
71
81
|
|
|
82
|
+
@classmethod
|
|
83
|
+
def from_handler(
|
|
84
|
+
cls,
|
|
85
|
+
handler: ZarrGroupHandler,
|
|
86
|
+
backend: TableBackend | None = None,
|
|
87
|
+
) -> "FeatureTableV1":
|
|
88
|
+
return cls._from_handler(
|
|
89
|
+
handler=handler,
|
|
90
|
+
backend=backend,
|
|
91
|
+
meta_model=FeatureTableMeta,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def meta(self) -> FeatureTableMeta:
|
|
96
|
+
"""Return the metadata of the table."""
|
|
97
|
+
if not isinstance(self._meta, FeatureTableMeta):
|
|
98
|
+
raise NgioValueError(
|
|
99
|
+
"The metadata of the table is not of type FeatureTableMeta."
|
|
100
|
+
)
|
|
101
|
+
return self._meta
|
|
102
|
+
|
|
72
103
|
@staticmethod
|
|
73
|
-
def
|
|
104
|
+
def table_type() -> str:
|
|
74
105
|
"""Return the type of the table."""
|
|
75
106
|
return "feature_table"
|
|
76
107
|
|
|
@@ -82,110 +113,13 @@ class FeatureTableV1:
|
|
|
82
113
|
"""
|
|
83
114
|
return "1"
|
|
84
115
|
|
|
85
|
-
@property
|
|
86
|
-
def backend_name(self) -> str | None:
|
|
87
|
-
"""Return the name of the backend."""
|
|
88
|
-
if self._table_backend is None:
|
|
89
|
-
return None
|
|
90
|
-
return self._table_backend.backend_name()
|
|
91
|
-
|
|
92
116
|
@property
|
|
93
117
|
def reference_label(self) -> str | None:
|
|
94
118
|
"""Return the reference label."""
|
|
95
|
-
path = self.
|
|
119
|
+
path = self.meta.region
|
|
96
120
|
if path is None:
|
|
97
121
|
return None
|
|
98
122
|
|
|
99
123
|
path = path.path
|
|
100
124
|
path = path.split("/")[-1]
|
|
101
125
|
return path
|
|
102
|
-
|
|
103
|
-
@property
|
|
104
|
-
def dataframe(self) -> pd.DataFrame:
|
|
105
|
-
"""Return the table as a DataFrame."""
|
|
106
|
-
if self._dataframe is None and self._table_backend is None:
|
|
107
|
-
raise NgioValueError(
|
|
108
|
-
"The table does not have a DataFrame in memory nor a backend."
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
if self._dataframe is None and self._table_backend is not None:
|
|
112
|
-
self._dataframe = self._table_backend.load_as_pandas_df()
|
|
113
|
-
|
|
114
|
-
if self._dataframe is None:
|
|
115
|
-
raise NgioValueError(
|
|
116
|
-
"The table does not have a DataFrame in memory nor a backend."
|
|
117
|
-
)
|
|
118
|
-
return self._dataframe
|
|
119
|
-
|
|
120
|
-
@dataframe.setter
|
|
121
|
-
def dataframe(self, dataframe: pd.DataFrame) -> None:
|
|
122
|
-
"""Set the table as a DataFrame."""
|
|
123
|
-
self._dataframe = normalize_pandas_df(
|
|
124
|
-
dataframe,
|
|
125
|
-
index_key=self._instance_key,
|
|
126
|
-
index_type="int",
|
|
127
|
-
reset_index=False,
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
@classmethod
|
|
131
|
-
def _from_handler(
|
|
132
|
-
cls, handler: ZarrGroupHandler, backend_name: str | None = None
|
|
133
|
-
) -> "FeatureTableV1":
|
|
134
|
-
"""Create a new ROI table from a Zarr group handler."""
|
|
135
|
-
meta = FeatureTableMeta(**handler.load_attrs())
|
|
136
|
-
instance_key = "label" if meta.instance_key is None else meta.instance_key
|
|
137
|
-
if backend_name is None:
|
|
138
|
-
backend = ImplementedTableBackends().get_backend(
|
|
139
|
-
backend_name=meta.backend,
|
|
140
|
-
group_handler=handler,
|
|
141
|
-
index_key=instance_key,
|
|
142
|
-
index_type="int",
|
|
143
|
-
)
|
|
144
|
-
else:
|
|
145
|
-
backend = ImplementedTableBackends().get_backend(
|
|
146
|
-
backend_name=backend_name,
|
|
147
|
-
group_handler=handler,
|
|
148
|
-
index_key=instance_key,
|
|
149
|
-
index_type="int",
|
|
150
|
-
)
|
|
151
|
-
meta.backend = backend_name
|
|
152
|
-
|
|
153
|
-
if not backend.implements_pandas:
|
|
154
|
-
raise NgioValueError(
|
|
155
|
-
"The backend does not implement the dataframe protocol."
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
table = cls()
|
|
159
|
-
table._meta = meta
|
|
160
|
-
table._table_backend = backend
|
|
161
|
-
return table
|
|
162
|
-
|
|
163
|
-
def _set_backend(
|
|
164
|
-
self,
|
|
165
|
-
handler: ZarrGroupHandler,
|
|
166
|
-
backend_name: str | None = None,
|
|
167
|
-
) -> None:
|
|
168
|
-
"""Set the backend of the table."""
|
|
169
|
-
instance_key = "label" if self._instance_key is None else self._instance_key
|
|
170
|
-
backend = ImplementedTableBackends().get_backend(
|
|
171
|
-
backend_name=backend_name,
|
|
172
|
-
group_handler=handler,
|
|
173
|
-
index_key=instance_key,
|
|
174
|
-
index_type="int",
|
|
175
|
-
)
|
|
176
|
-
self._meta.backend = backend_name
|
|
177
|
-
self._table_backend = backend
|
|
178
|
-
|
|
179
|
-
def consolidate(self) -> None:
|
|
180
|
-
"""Write the current state of the table to the Zarr file."""
|
|
181
|
-
if self._table_backend is None:
|
|
182
|
-
raise NgioValueError(
|
|
183
|
-
"No backend set for the table. "
|
|
184
|
-
"Please add the table to a OME-Zarr Image before calling consolidate."
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
self._table_backend.write(
|
|
188
|
-
self.dataframe,
|
|
189
|
-
metadata=self._meta.model_dump(exclude_none=True),
|
|
190
|
-
mode="pandas",
|
|
191
|
-
)
|