ngio 0.2.8__py3-none-any.whl → 0.3.0a0__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.
@@ -1,7 +1,14 @@
1
1
  """Tables implementations for fractal_tables v1."""
2
2
 
3
+ from ngio.tables.v1._condition_table import ConditionTableV1
3
4
  from ngio.tables.v1._feature_table import FeatureTableV1
4
5
  from ngio.tables.v1._generic_table import GenericTable
5
6
  from ngio.tables.v1._roi_table import MaskingRoiTableV1, RoiTableV1
6
7
 
7
- __all__ = ["FeatureTableV1", "GenericTable", "MaskingRoiTableV1", "RoiTableV1"]
8
+ __all__ = [
9
+ "ConditionTableV1",
10
+ "FeatureTableV1",
11
+ "GenericTable",
12
+ "MaskingRoiTableV1",
13
+ "RoiTableV1",
14
+ ]
@@ -0,0 +1,67 @@
1
+ """Implementation of a generic table class."""
2
+
3
+ from ngio.tables.abstract_table import AbstractBaseTable
4
+ from ngio.tables.backends import BackendMeta, TableBackendProtocol, TabularData
5
+ from ngio.utils import ZarrGroupHandler
6
+
7
+
8
+ class ConditionTableMeta(BackendMeta):
9
+ """Metadata for the condition table."""
10
+
11
+ fractal_table_version: str | None = "1"
12
+ type: str | None = "condition_table"
13
+
14
+
15
+ class ConditionTableV1(AbstractBaseTable):
16
+ """Condition table class.
17
+
18
+ This class is used to load a condition table.
19
+ The condition table is a generic table that does not
20
+ have a specific definition.
21
+
22
+ It is used to store informations about the particular conditions
23
+ used to generate the data.
24
+ - How much drug was used in the experiment
25
+ - What treatment was used
26
+ - etc.
27
+ """
28
+
29
+ def __init__(
30
+ self,
31
+ table_data: TabularData | None = None,
32
+ *,
33
+ meta: ConditionTableMeta | None = None,
34
+ ) -> None:
35
+ """Initialize the ConditionTable."""
36
+ if meta is None:
37
+ meta = ConditionTableMeta()
38
+
39
+ super().__init__(
40
+ table_data=table_data,
41
+ meta=meta,
42
+ )
43
+
44
+ @staticmethod
45
+ def table_type() -> str:
46
+ """Return the type of the table."""
47
+ return "condition_table"
48
+
49
+ @staticmethod
50
+ def version() -> str:
51
+ """The generic table does not have a version.
52
+
53
+ Since does not follow a specific schema.
54
+ """
55
+ return "1"
56
+
57
+ @classmethod
58
+ def from_handler(
59
+ cls,
60
+ handler: ZarrGroupHandler,
61
+ backend: str | TableBackendProtocol | None = None,
62
+ ) -> "ConditionTableV1":
63
+ return cls._from_handler(
64
+ handler=handler,
65
+ backend=backend,
66
+ meta_model=ConditionTableMeta,
67
+ )
@@ -6,12 +6,19 @@ https://fractal-analytics-platform.github.io/fractal-tasks-core/tables/
6
6
 
7
7
  from typing import Literal
8
8
 
9
- import pandas as pd
10
9
  from pydantic import BaseModel
11
10
 
12
- from ngio.tables.backends import BackendMeta, ImplementedTableBackends
13
- from ngio.tables.backends._utils import normalize_pandas_df
14
- from ngio.utils import NgioValueError, ZarrGroupHandler
11
+ from ngio.tables.abstract_table import AbstractBaseTable
12
+ from ngio.tables.backends import BackendMeta, TableBackendProtocol, TabularData
13
+ from ngio.utils import NgioValueError
14
+ from ngio.utils._zarr_utils import ZarrGroupHandler
15
+
16
+
17
+ class GenericTableMeta(BackendMeta):
18
+ """Metadata for the ROI table."""
19
+
20
+ fractal_table_version: str | None = None
21
+ type: str | None = None
15
22
 
16
23
 
17
24
  class RegionMeta(BaseModel):
@@ -27,38 +34,43 @@ class FeatureTableMeta(BackendMeta):
27
34
  type: Literal["feature_table"] = "feature_table"
28
35
  region: RegionMeta | None = None
29
36
  instance_key: str = "label"
37
+ index_key: str | None = "label"
38
+ index_type: Literal["int", "str"] | None = "int"
30
39
 
31
40
 
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
-
41
+ class FeatureTableV1(AbstractBaseTable):
39
42
  def __init__(
40
43
  self,
41
- dataframe: pd.DataFrame | None = None,
44
+ table_data: TabularData | None = None,
45
+ *,
42
46
  reference_label: str | None = None,
47
+ meta: FeatureTableMeta | None = None,
43
48
  ) -> None:
44
49
  """Initialize the GenericTable."""
45
- if reference_label is None:
46
- self._meta = FeatureTableMeta()
47
- else:
50
+ if meta is None:
51
+ meta = FeatureTableMeta()
52
+
53
+ if reference_label is not None:
48
54
  path = f"../labels/{reference_label}"
49
- self._meta = FeatureTableMeta(region=RegionMeta(path=path))
50
-
51
- self._instance_key = "label"
52
- if dataframe is None:
53
- self._dataframe = None
54
- else:
55
- self._dataframe = normalize_pandas_df(
56
- dataframe,
57
- index_key=self._instance_key,
58
- index_type="int",
59
- reset_index=False,
55
+ meta = FeatureTableMeta(region=RegionMeta(path=path))
56
+
57
+ if table_data is not None and not isinstance(table_data, TabularData):
58
+ raise NgioValueError(
59
+ f"The table is not of type SupportedTables. Got {type(table_data)}"
60
60
  )
61
- self._table_backend = None
61
+
62
+ if meta.index_key is None:
63
+ meta.index_key = "label"
64
+
65
+ if meta.index_type is None:
66
+ meta.index_type = "int"
67
+
68
+ meta.instance_key = meta.index_key
69
+
70
+ super().__init__(
71
+ table_data=table_data,
72
+ meta=meta,
73
+ )
62
74
 
63
75
  def __repr__(self) -> str:
64
76
  """Return a string representation of the table."""
@@ -69,8 +81,29 @@ class FeatureTableV1:
69
81
  properties += f", reference_label={self.reference_label}"
70
82
  return f"FeatureTableV1({properties})"
71
83
 
84
+ @classmethod
85
+ def from_handler(
86
+ cls,
87
+ handler: ZarrGroupHandler,
88
+ backend: str | TableBackendProtocol | None = None,
89
+ ) -> "FeatureTableV1":
90
+ return cls._from_handler(
91
+ handler=handler,
92
+ backend=backend,
93
+ meta_model=FeatureTableMeta,
94
+ )
95
+
96
+ @property
97
+ def meta(self) -> FeatureTableMeta:
98
+ """Return the metadata of the table."""
99
+ if not isinstance(self._meta, FeatureTableMeta):
100
+ raise NgioValueError(
101
+ "The metadata of the table is not of type FeatureTableMeta."
102
+ )
103
+ return self._meta
104
+
72
105
  @staticmethod
73
- def type() -> str:
106
+ def table_type() -> str:
74
107
  """Return the type of the table."""
75
108
  return "feature_table"
76
109
 
@@ -82,110 +115,13 @@ class FeatureTableV1:
82
115
  """
83
116
  return "1"
84
117
 
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
118
  @property
93
119
  def reference_label(self) -> str | None:
94
120
  """Return the reference label."""
95
- path = self._meta.region
121
+ path = self.meta.region
96
122
  if path is None:
97
123
  return None
98
124
 
99
125
  path = path.path
100
126
  path = path.split("/")[-1]
101
127
  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
- )
@@ -1,69 +1,21 @@
1
1
  """Implementation of a generic table class."""
2
2
 
3
- import pandas as pd
4
- from anndata import AnnData
3
+ from ngio.tables.abstract_table import AbstractBaseTable
4
+ from ngio.tables.backends import BackendMeta, TableBackendProtocol
5
+ from ngio.utils import ZarrGroupHandler
5
6
 
6
- from ngio.tables.backends import (
7
- BackendMeta,
8
- ImplementedTableBackends,
9
- convert_anndata_to_pandas,
10
- convert_pandas_to_anndata,
11
- )
12
- from ngio.utils import NgioValueError, ZarrGroupHandler
13
7
 
14
-
15
- class GenericTableMeta(BackendMeta):
16
- """Metadata for the ROI table."""
17
-
18
- fractal_table_version: str | None = None
19
- type: str | None = None
20
-
21
-
22
- class GenericTable:
8
+ class GenericTable(AbstractBaseTable):
23
9
  """Class to a non-specific table.
24
10
 
25
11
  This can be used to load any table that does not have
26
12
  a specific definition.
27
13
  """
28
14
 
29
- def __init__(
30
- self,
31
- dataframe: pd.DataFrame | None = None,
32
- anndata: AnnData | None = None,
33
- ) -> None:
34
- """Initialize the GenericTable."""
35
- self._meta = GenericTableMeta()
36
- if dataframe is None and anndata is None:
37
- raise NgioValueError(
38
- "Either a DataFrame or an AnnData object must be provided."
39
- )
40
-
41
- if dataframe is not None and anndata is not None:
42
- raise NgioValueError(
43
- "Only one of DataFrame or AnnData object can be provided."
44
- )
45
-
46
- self._dataframe = dataframe
47
- self._anndata = anndata
48
-
49
- self.anndata_native = True if anndata is not None else False
50
-
51
- self._table_backend = None
52
-
53
- def __repr__(self) -> str:
54
- """Return a string representation of the table."""
55
- if self._dataframe is not None:
56
- num_rows = len(self.dataframe)
57
- num_columns = len(self.dataframe.columns)
58
- prop = f"num_rows={num_rows}, num_columns={num_columns}, mode=dataframe"
59
- else:
60
- prop = "mode=anndata"
61
- return f"GenericTable({prop})"
62
-
63
15
  @staticmethod
64
- def type() -> str:
16
+ def table_type() -> str:
65
17
  """Return the type of the table."""
66
- return "generic"
18
+ return "generic_table"
67
19
 
68
20
  @staticmethod
69
21
  def version() -> str:
@@ -73,115 +25,14 @@ class GenericTable:
73
25
  """
74
26
  return "1"
75
27
 
76
- @property
77
- def backend_name(self) -> str | None:
78
- """Return the name of the backend."""
79
- if self._table_backend is None:
80
- return None
81
- return self._table_backend.backend_name()
82
-
83
- @property
84
- def dataframe(self) -> pd.DataFrame:
85
- """Return the table as a DataFrame."""
86
- if self._dataframe is not None:
87
- return self._dataframe
88
-
89
- if self._anndata is not None:
90
- return convert_anndata_to_pandas(self._anndata)
91
-
92
- raise NgioValueError("No table loaded.")
93
-
94
- @dataframe.setter
95
- def dataframe(self, dataframe: pd.DataFrame) -> None:
96
- """Set the table as a DataFrame."""
97
- self._dataframe = dataframe
98
- self.anndata_native = False
99
-
100
- @property
101
- def anndata(self) -> AnnData:
102
- """Return the table as an AnnData object."""
103
- if self._anndata is not None:
104
- return self._anndata
105
-
106
- if self._dataframe is not None:
107
- return convert_pandas_to_anndata(
108
- self._dataframe,
109
- )
110
- raise NgioValueError("No table loaded.")
111
-
112
- @anndata.setter
113
- def anndata(self, anndata: AnnData) -> None:
114
- """Set the table as an AnnData object."""
115
- self._anndata = anndata
116
- self.anndata_native = True
117
-
118
28
  @classmethod
119
- def _from_handler(
120
- cls, handler: ZarrGroupHandler, backend_name: str | None = None
121
- ) -> "GenericTable":
122
- """Create a new ROI table from a Zarr group handler."""
123
- meta = GenericTableMeta(**handler.load_attrs())
124
- if backend_name is None:
125
- backend = ImplementedTableBackends().get_backend(
126
- backend_name=meta.backend,
127
- group_handler=handler,
128
- index_key=None,
129
- )
130
- else:
131
- backend = ImplementedTableBackends().get_backend(
132
- backend_name=backend_name,
133
- group_handler=handler,
134
- index_key=None,
135
- )
136
- meta.backend = backend_name
137
-
138
- if backend.implements_anndata():
139
- anndata = backend.load_as_anndata()
140
- table = cls(anndata=anndata)
141
-
142
- elif backend.implements_pandas():
143
- dataframe = backend.load_as_pandas_df()
144
- table = cls(dataframe=dataframe)
145
- else:
146
- raise NgioValueError(
147
- "The backend does not implement the dataframe protocol."
148
- )
149
-
150
- table._meta = meta
151
- table._table_backend = backend
152
- return table
153
-
154
- def _set_backend(
155
- self,
29
+ def from_handler(
30
+ cls,
156
31
  handler: ZarrGroupHandler,
157
- backend_name: str | None = None,
158
- ) -> None:
159
- """Set the backend of the table."""
160
- backend = ImplementedTableBackends().get_backend(
161
- backend_name=backend_name,
162
- group_handler=handler,
163
- index_key=None,
32
+ backend: str | TableBackendProtocol | None = None,
33
+ ) -> "GenericTable":
34
+ return cls._from_handler(
35
+ handler=handler,
36
+ backend=backend,
37
+ meta_model=BackendMeta,
164
38
  )
165
- self._meta.backend = backend_name
166
- self._table_backend = backend
167
-
168
- def consolidate(self) -> None:
169
- """Write the current state of the table to the Zarr file."""
170
- if self._table_backend is None:
171
- raise NgioValueError(
172
- "No backend set for the table. "
173
- "Please add the table to a OME-Zarr Image before calling consolidate."
174
- )
175
-
176
- if self.anndata_native:
177
- self._table_backend.write(
178
- self.anndata,
179
- metadata=self._meta.model_dump(exclude_none=True),
180
- mode="anndata",
181
- )
182
- else:
183
- self._table_backend.write(
184
- self.dataframe,
185
- metadata=self._meta.model_dump(exclude_none=True),
186
- mode="pandas",
187
- )