ngio 0.2.0a2__py3-none-any.whl → 0.5.0b4__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.
Files changed (106) hide show
  1. ngio/__init__.py +40 -12
  2. ngio/common/__init__.py +16 -32
  3. ngio/common/_dimensions.py +270 -48
  4. ngio/common/_masking_roi.py +153 -0
  5. ngio/common/_pyramid.py +267 -73
  6. ngio/common/_roi.py +290 -66
  7. ngio/common/_synt_images_utils.py +101 -0
  8. ngio/common/_zoom.py +54 -22
  9. ngio/experimental/__init__.py +5 -0
  10. ngio/experimental/iterators/__init__.py +15 -0
  11. ngio/experimental/iterators/_abstract_iterator.py +390 -0
  12. ngio/experimental/iterators/_feature.py +189 -0
  13. ngio/experimental/iterators/_image_processing.py +130 -0
  14. ngio/experimental/iterators/_mappers.py +48 -0
  15. ngio/experimental/iterators/_rois_utils.py +126 -0
  16. ngio/experimental/iterators/_segmentation.py +235 -0
  17. ngio/hcs/__init__.py +17 -58
  18. ngio/hcs/_plate.py +1354 -0
  19. ngio/images/__init__.py +30 -9
  20. ngio/images/_abstract_image.py +968 -0
  21. ngio/images/_create_synt_container.py +132 -0
  22. ngio/images/_create_utils.py +423 -0
  23. ngio/images/_image.py +926 -0
  24. ngio/images/_label.py +417 -0
  25. ngio/images/_masked_image.py +531 -0
  26. ngio/images/_ome_zarr_container.py +1235 -0
  27. ngio/images/_table_ops.py +471 -0
  28. ngio/io_pipes/__init__.py +75 -0
  29. ngio/io_pipes/_io_pipes.py +361 -0
  30. ngio/io_pipes/_io_pipes_masked.py +488 -0
  31. ngio/io_pipes/_io_pipes_roi.py +146 -0
  32. ngio/io_pipes/_io_pipes_types.py +56 -0
  33. ngio/io_pipes/_match_shape.py +377 -0
  34. ngio/io_pipes/_ops_axes.py +344 -0
  35. ngio/io_pipes/_ops_slices.py +411 -0
  36. ngio/io_pipes/_ops_slices_utils.py +199 -0
  37. ngio/io_pipes/_ops_transforms.py +104 -0
  38. ngio/io_pipes/_zoom_transform.py +180 -0
  39. ngio/ome_zarr_meta/__init__.py +39 -15
  40. ngio/ome_zarr_meta/_meta_handlers.py +490 -96
  41. ngio/ome_zarr_meta/ngio_specs/__init__.py +24 -10
  42. ngio/ome_zarr_meta/ngio_specs/_axes.py +268 -234
  43. ngio/ome_zarr_meta/ngio_specs/_channels.py +125 -41
  44. ngio/ome_zarr_meta/ngio_specs/_dataset.py +42 -87
  45. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +536 -2
  46. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +202 -198
  47. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +72 -34
  48. ngio/ome_zarr_meta/v04/__init__.py +21 -5
  49. ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
  50. ngio/ome_zarr_meta/v04/{_v04_spec_utils.py → _v04_spec.py} +151 -90
  51. ngio/ome_zarr_meta/v05/__init__.py +27 -0
  52. ngio/ome_zarr_meta/v05/_custom_models.py +18 -0
  53. ngio/ome_zarr_meta/v05/_v05_spec.py +511 -0
  54. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png +0 -0
  55. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
  56. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg +0 -0
  57. ngio/resources/__init__.py +55 -0
  58. ngio/resources/resource_model.py +36 -0
  59. ngio/tables/__init__.py +20 -4
  60. ngio/tables/_abstract_table.py +270 -0
  61. ngio/tables/_tables_container.py +449 -0
  62. ngio/tables/backends/__init__.py +50 -1
  63. ngio/tables/backends/_abstract_backend.py +200 -31
  64. ngio/tables/backends/_anndata.py +139 -0
  65. ngio/tables/backends/_anndata_utils.py +10 -114
  66. ngio/tables/backends/_csv.py +19 -0
  67. ngio/tables/backends/_json.py +92 -0
  68. ngio/tables/backends/_parquet.py +19 -0
  69. ngio/tables/backends/_py_arrow_backends.py +222 -0
  70. ngio/tables/backends/_table_backends.py +162 -38
  71. ngio/tables/backends/_utils.py +608 -0
  72. ngio/tables/v1/__init__.py +19 -4
  73. ngio/tables/v1/_condition_table.py +71 -0
  74. ngio/tables/v1/_feature_table.py +79 -115
  75. ngio/tables/v1/_generic_table.py +21 -90
  76. ngio/tables/v1/_roi_table.py +486 -137
  77. ngio/transforms/__init__.py +5 -0
  78. ngio/transforms/_zoom.py +19 -0
  79. ngio/utils/__init__.py +16 -14
  80. ngio/utils/_cache.py +48 -0
  81. ngio/utils/_datasets.py +121 -13
  82. ngio/utils/_fractal_fsspec_store.py +42 -0
  83. ngio/utils/_zarr_utils.py +374 -218
  84. ngio-0.5.0b4.dist-info/METADATA +147 -0
  85. ngio-0.5.0b4.dist-info/RECORD +88 -0
  86. {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/WHEEL +1 -1
  87. ngio/common/_array_pipe.py +0 -160
  88. ngio/common/_axes_transforms.py +0 -63
  89. ngio/common/_common_types.py +0 -5
  90. ngio/common/_slicer.py +0 -97
  91. ngio/images/abstract_image.py +0 -240
  92. ngio/images/create.py +0 -251
  93. ngio/images/image.py +0 -389
  94. ngio/images/label.py +0 -236
  95. ngio/images/omezarr_container.py +0 -535
  96. ngio/ome_zarr_meta/_generic_handlers.py +0 -320
  97. ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -54
  98. ngio/tables/_validators.py +0 -192
  99. ngio/tables/backends/_anndata_v1.py +0 -75
  100. ngio/tables/backends/_json_v1.py +0 -56
  101. ngio/tables/tables_container.py +0 -300
  102. ngio/tables/v1/_masking_roi_table.py +0 -175
  103. ngio/utils/_logger.py +0 -29
  104. ngio-0.2.0a2.dist-info/METADATA +0 -95
  105. ngio-0.2.0a2.dist-info/RECORD +0 -53
  106. {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/licenses/LICENSE +0 -0
@@ -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 pandas as pd
10
- from pydantic import BaseModel
9
+ from pydantic import BaseModel, Field
11
10
 
12
- from ngio.tables._validators import validate_index_key
13
- from ngio.tables.backends import ImplementedTableBackends
14
- from ngio.utils import ZarrGroupHandler
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):
@@ -20,47 +20,88 @@ class RegionMeta(BaseModel):
20
20
  path: str
21
21
 
22
22
 
23
- class FeatureTableMeta(BaseModel):
23
+ class FeatureTableMeta(BackendMeta):
24
24
  """Metadata for the ROI table."""
25
25
 
26
- fractal_table_version: Literal["1"] = "1"
26
+ table_version: Literal["1"] = "1"
27
27
  type: Literal["feature_table"] = "feature_table"
28
- backend: str | None = None
29
28
  region: RegionMeta | None = None
30
- 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)
31
37
 
32
38
 
33
- class FeatureTableV1:
34
- """Class to represent a feature table.
35
-
36
- This can be used to load any table that does not have
37
- a specific definition.
38
- """
39
-
39
+ class FeatureTableV1(AbstractBaseTable):
40
40
  def __init__(
41
41
  self,
42
- dataframe: pd.DataFrame | None = None,
42
+ table_data: TabularData | None = None,
43
+ *,
43
44
  reference_label: str | None = None,
45
+ meta: FeatureTableMeta | None = None,
44
46
  ) -> None:
45
47
  """Initialize the GenericTable."""
46
- if reference_label is None:
47
- self._meta = FeatureTableMeta()
48
- else:
48
+ if meta is None:
49
+ meta = FeatureTableMeta()
50
+
51
+ if reference_label is not None:
49
52
  path = f"../labels/{reference_label}"
50
- self._meta = FeatureTableMeta(region=RegionMeta(path=path))
51
-
52
- self._reference_label = reference_label
53
- self._instance_key = "label"
54
- if dataframe is None:
55
- self._dataframe = None
56
- else:
57
- self._dataframe = validate_index_key(
58
- dataframe, self._instance_key, overwrite=True
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)}"
58
+ )
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
+ )
72
+
73
+ def __repr__(self) -> str:
74
+ """Return a string representation of the table."""
75
+ num_rows = len(self.dataframe) if self.dataframe is not None else 0
76
+ num_columns = len(self.dataframe.columns) if self.dataframe is not None else 0
77
+ properties = f"num_rows={num_rows}, num_columns={num_columns}"
78
+ if self.reference_label is not None:
79
+ properties += f", reference_label={self.reference_label}"
80
+ return f"FeatureTableV1({properties})"
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."
59
100
  )
60
- self._table_backend = None
101
+ return self._meta
61
102
 
62
103
  @staticmethod
63
- def type() -> str:
104
+ def table_type() -> str:
64
105
  """Return the type of the table."""
65
106
  return "feature_table"
66
107
 
@@ -73,89 +114,12 @@ class FeatureTableV1:
73
114
  return "1"
74
115
 
75
116
  @property
76
- def backend_name(self) -> str | None:
77
- """Return the name of the backend."""
78
- if self._table_backend is None:
117
+ def reference_label(self) -> str | None:
118
+ """Return the reference label."""
119
+ path = self.meta.region
120
+ if path is None:
79
121
  return None
80
- return self._table_backend.backend_name()
81
122
 
82
- @property
83
- def dataframe(self) -> pd.DataFrame:
84
- """Return the table as a DataFrame."""
85
- if self._dataframe is None and self._table_backend is None:
86
- raise ValueError(
87
- "The table does not have a DataFrame in memory nor a backend."
88
- )
89
-
90
- if self._dataframe is None and self._table_backend is not None:
91
- self._dataframe = self._table_backend.load_as_dataframe()
92
-
93
- if self._dataframe is None:
94
- raise ValueError(
95
- "The table does not have a DataFrame in memory nor a backend."
96
- )
97
- return self._dataframe
98
-
99
- @dataframe.setter
100
- def dataframe(self, dataframe: pd.DataFrame) -> None:
101
- """Set the table as a DataFrame."""
102
- self._dataframe = dataframe
103
-
104
- @classmethod
105
- def _from_handler(
106
- cls, handler: ZarrGroupHandler, backend_name: str | None = None
107
- ) -> "FeatureTableV1":
108
- """Create a new ROI table from a Zarr group handler."""
109
- meta = FeatureTableMeta(**handler.load_attrs())
110
- instance_key = "label" if meta.instance_key is None else meta.instance_key
111
- if backend_name is None:
112
- backend = ImplementedTableBackends().get_backend(
113
- backend_name=meta.backend,
114
- group_handler=handler,
115
- index_key=instance_key,
116
- index_type="int",
117
- )
118
- else:
119
- backend = ImplementedTableBackends().get_backend(
120
- backend_name=backend_name,
121
- group_handler=handler,
122
- index_key=instance_key,
123
- index_type="int",
124
- )
125
- meta.backend = backend_name
126
-
127
- if not backend.implements_dataframe:
128
- raise ValueError("The backend does not implement the dataframe protocol.")
129
-
130
- table = cls()
131
- table._meta = meta
132
- table._table_backend = backend
133
- return table
134
-
135
- def _set_backend(
136
- self,
137
- handler: ZarrGroupHandler,
138
- backend_name: str | None = None,
139
- ) -> None:
140
- """Set the backend of the table."""
141
- instance_key = "label" if self._instance_key is None else self._instance_key
142
- backend = ImplementedTableBackends().get_backend(
143
- backend_name=backend_name,
144
- group_handler=handler,
145
- index_key=instance_key,
146
- index_type="int",
147
- )
148
- self._meta.backend = backend_name
149
- self._table_backend = backend
150
-
151
- def consolidate(self) -> None:
152
- """Write the current state of the table to the Zarr file."""
153
- if self._table_backend is None:
154
- raise ValueError(
155
- "No backend set for the table. "
156
- "Please add the table to a OME-Zarr Image before calling consolidate."
157
- )
158
-
159
- self._table_backend.write_from_dataframe(
160
- self.dataframe, metadata=self._meta.model_dump(exclude_none=True)
161
- )
123
+ path = path.path
124
+ path = path.split("/")[-1]
125
+ return path
@@ -1,40 +1,32 @@
1
1
  """Implementation of a generic table class."""
2
2
 
3
- import pandas as pd
4
- from pydantic import BaseModel
5
-
6
- from ngio.tables.backends import ImplementedTableBackends
3
+ from ngio.tables._abstract_table import AbstractBaseTable
4
+ from ngio.tables.backends import BackendMeta, TableBackend
7
5
  from ngio.utils import ZarrGroupHandler
8
6
 
9
7
 
10
- class GenericTableMeta(BaseModel):
11
- """Metadata for the ROI table."""
8
+ class GenericTableMeta(BackendMeta):
9
+ """Metadata for the generic table.
10
+
11
+ This is used to store metadata for a generic table.
12
+ It does not have a specific definition.
13
+ """
12
14
 
13
- fractal_table_version: str | None = None
14
- type: str | None = None
15
- backend: str | None = None
15
+ table_version: str | None = "1"
16
+ type: str | None = "generic_table"
16
17
 
17
18
 
18
- class GenericTable:
19
+ class GenericTable(AbstractBaseTable):
19
20
  """Class to a non-specific table.
20
21
 
21
22
  This can be used to load any table that does not have
22
23
  a specific definition.
23
24
  """
24
25
 
25
- def __init__(
26
- self,
27
- dataframe: pd.DataFrame,
28
- ) -> None:
29
- """Initialize the GenericTable."""
30
- self._meta = GenericTableMeta()
31
- self._dataframe = dataframe
32
- self._table_backend = None
33
-
34
26
  @staticmethod
35
- def type() -> str:
27
+ def table_type() -> str:
36
28
  """Return the type of the table."""
37
- return "generic"
29
+ return "generic_table"
38
30
 
39
31
  @staticmethod
40
32
  def version() -> str:
@@ -44,75 +36,14 @@ class GenericTable:
44
36
  """
45
37
  return "1"
46
38
 
47
- @property
48
- def backend_name(self) -> str | None:
49
- """Return the name of the backend."""
50
- if self._table_backend is None:
51
- return None
52
- return self._table_backend.backend_name()
53
-
54
- @property
55
- def dataframe(self) -> pd.DataFrame:
56
- """Return the table as a DataFrame."""
57
- return self._dataframe
58
-
59
- @dataframe.setter
60
- def dataframe(self, dataframe: pd.DataFrame) -> None:
61
- """Set the table as a DataFrame."""
62
- self._dataframe = dataframe
63
-
64
39
  @classmethod
65
- def _from_handler(
66
- cls, handler: ZarrGroupHandler, backend_name: str | None = None
67
- ) -> "GenericTable":
68
- """Create a new ROI table from a Zarr group handler."""
69
- meta = GenericTableMeta(**handler.load_attrs())
70
- if backend_name is None:
71
- backend = ImplementedTableBackends().get_backend(
72
- backend_name=meta.backend,
73
- group_handler=handler,
74
- index_key=None,
75
- )
76
- else:
77
- backend = ImplementedTableBackends().get_backend(
78
- backend_name=backend_name,
79
- group_handler=handler,
80
- index_key=None,
81
- )
82
- meta.backend = backend_name
83
-
84
- if not backend.implements_dataframe:
85
- raise ValueError("The backend does not implement the dataframe protocol.")
86
-
87
- dataframe = backend.load_as_dataframe()
88
-
89
- table = cls(dataframe)
90
- table._meta = meta
91
- table._table_backend = backend
92
- return table
93
-
94
- def _set_backend(
95
- self,
40
+ def from_handler(
41
+ cls,
96
42
  handler: ZarrGroupHandler,
97
- backend_name: str | None = None,
98
- ) -> None:
99
- """Set the backend of the table."""
100
- backend = ImplementedTableBackends().get_backend(
101
- backend_name=backend_name,
102
- group_handler=handler,
103
- index_key=None,
104
- )
105
- self._meta.backend = backend_name
106
- self._table_backend = backend
107
-
108
- def consolidate(self) -> None:
109
- """Write the current state of the table to the Zarr file."""
110
- if self._table_backend is None:
111
- raise ValueError(
112
- "No backend set for the table. "
113
- "Please add the table to a OME-Zarr Image before calling consolidate."
114
- )
115
-
116
- self._table_backend.write_from_dataframe(
117
- self._dataframe, metadata=self._meta.model_dump(exclude_none=True)
43
+ backend: TableBackend | None = None,
44
+ ) -> "GenericTable":
45
+ return cls._from_handler(
46
+ handler=handler,
47
+ backend=backend,
48
+ meta_model=BackendMeta,
118
49
  )