ngio 0.5.0a2__py3-none-any.whl → 0.5.0a3__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 (47) hide show
  1. ngio/__init__.py +2 -2
  2. ngio/common/__init__.py +11 -6
  3. ngio/common/_masking_roi.py +12 -41
  4. ngio/common/_pyramid.py +206 -76
  5. ngio/common/_roi.py +257 -329
  6. ngio/experimental/iterators/_feature.py +3 -3
  7. ngio/experimental/iterators/_rois_utils.py +10 -11
  8. ngio/hcs/_plate.py +50 -43
  9. ngio/images/_abstract_image.py +417 -35
  10. ngio/images/_create_synt_container.py +35 -42
  11. ngio/images/_create_utils.py +423 -0
  12. ngio/images/_image.py +154 -176
  13. ngio/images/_label.py +144 -119
  14. ngio/images/_ome_zarr_container.py +361 -196
  15. ngio/io_pipes/_io_pipes.py +9 -9
  16. ngio/io_pipes/_io_pipes_masked.py +7 -7
  17. ngio/io_pipes/_io_pipes_roi.py +6 -6
  18. ngio/io_pipes/_io_pipes_types.py +3 -3
  19. ngio/io_pipes/_match_shape.py +5 -4
  20. ngio/io_pipes/_ops_slices_utils.py +8 -5
  21. ngio/ome_zarr_meta/__init__.py +15 -18
  22. ngio/ome_zarr_meta/_meta_handlers.py +334 -713
  23. ngio/ome_zarr_meta/ngio_specs/_axes.py +1 -0
  24. ngio/ome_zarr_meta/ngio_specs/_dataset.py +13 -22
  25. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +54 -61
  26. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +14 -68
  27. ngio/ome_zarr_meta/v04/__init__.py +1 -1
  28. ngio/ome_zarr_meta/v04/{_v04_spec_utils.py → _v04_spec.py} +16 -61
  29. ngio/ome_zarr_meta/v05/__init__.py +1 -1
  30. ngio/ome_zarr_meta/v05/{_v05_spec_utils.py → _v05_spec.py} +18 -61
  31. ngio/tables/_tables_container.py +2 -4
  32. ngio/tables/backends/_anndata.py +57 -8
  33. ngio/tables/backends/_anndata_utils.py +1 -6
  34. ngio/tables/backends/_csv.py +3 -19
  35. ngio/tables/backends/_json.py +10 -13
  36. ngio/tables/backends/_parquet.py +3 -31
  37. ngio/tables/backends/_py_arrow_backends.py +222 -0
  38. ngio/tables/v1/_roi_table.py +41 -24
  39. ngio/utils/__init__.py +4 -12
  40. ngio/utils/_zarr_utils.py +160 -53
  41. {ngio-0.5.0a2.dist-info → ngio-0.5.0a3.dist-info}/METADATA +6 -2
  42. {ngio-0.5.0a2.dist-info → ngio-0.5.0a3.dist-info}/RECORD +44 -45
  43. {ngio-0.5.0a2.dist-info → ngio-0.5.0a3.dist-info}/WHEEL +1 -1
  44. ngio/images/_create.py +0 -287
  45. ngio/tables/backends/_non_zarr_backends.py +0 -196
  46. ngio/utils/_logger.py +0 -50
  47. {ngio-0.5.0a2.dist-info → ngio-0.5.0a3.dist-info}/licenses/LICENSE +0 -0
ngio/images/_create.py DELETED
@@ -1,287 +0,0 @@
1
- """Utility functions for working with OME-Zarr images."""
2
-
3
- from collections.abc import Sequence
4
- from typing import Literal, TypeVar
5
-
6
- from zarr.core.array import CompressorLike
7
-
8
- from ngio.common._pyramid import init_empty_pyramid
9
- from ngio.ome_zarr_meta import (
10
- NgioImageMeta,
11
- NgioLabelMeta,
12
- PixelSize,
13
- get_image_meta_handler,
14
- get_label_meta_handler,
15
- )
16
- from ngio.ome_zarr_meta.ngio_specs import (
17
- DefaultNgffVersion,
18
- DefaultSpaceUnit,
19
- DefaultTimeUnit,
20
- NgffVersions,
21
- SpaceUnits,
22
- TimeUnits,
23
- canonical_axes_order,
24
- canonical_label_axes_order,
25
- )
26
- from ngio.utils import NgioValueError, StoreOrGroup, ZarrGroupHandler
27
-
28
- _image_or_label_meta = TypeVar("_image_or_label_meta", NgioImageMeta, NgioLabelMeta)
29
-
30
-
31
- def _init_generic_meta(
32
- meta_type: type[_image_or_label_meta],
33
- pixelsize: float,
34
- axes_names: Sequence[str],
35
- z_spacing: float = 1.0,
36
- time_spacing: float = 1.0,
37
- levels: int | list[str] = 5,
38
- yx_scaling_factor: float | tuple[float, float] = 2.0,
39
- z_scaling_factor: float = 1.0,
40
- space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
41
- time_unit: TimeUnits | str | None = DefaultTimeUnit,
42
- name: str | None = None,
43
- ngff_version: NgffVersions = DefaultNgffVersion,
44
- ) -> tuple[_image_or_label_meta, list[float]]:
45
- """Initialize the metadata for an image or label."""
46
- scaling_factors = []
47
- for ax in axes_names:
48
- if ax == "z":
49
- scaling_factors.append(z_scaling_factor)
50
- elif ax in ["x"]:
51
- if isinstance(yx_scaling_factor, tuple):
52
- scaling_factors.append(yx_scaling_factor[1])
53
- else:
54
- scaling_factors.append(yx_scaling_factor)
55
- elif ax in ["y"]:
56
- if isinstance(yx_scaling_factor, tuple):
57
- scaling_factors.append(yx_scaling_factor[0])
58
- else:
59
- scaling_factors.append(yx_scaling_factor)
60
- else:
61
- scaling_factors.append(1.0)
62
-
63
- pixel_sizes = PixelSize(
64
- x=pixelsize,
65
- y=pixelsize,
66
- z=z_spacing,
67
- t=time_spacing,
68
- space_unit=space_unit,
69
- time_unit=time_unit,
70
- )
71
-
72
- meta = meta_type.default_init(
73
- name=name,
74
- levels=levels,
75
- axes_names=axes_names,
76
- pixel_size=pixel_sizes,
77
- scaling_factors=scaling_factors,
78
- version=ngff_version,
79
- )
80
- return meta, scaling_factors
81
-
82
-
83
- def create_empty_label_container(
84
- store: StoreOrGroup,
85
- shape: Sequence[int],
86
- pixelsize: float,
87
- z_spacing: float = 1.0,
88
- time_spacing: float = 1.0,
89
- levels: int | list[str] = 5,
90
- yx_scaling_factor: float | tuple[float, float] = 2.0,
91
- z_scaling_factor: float = 1.0,
92
- space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
93
- time_unit: TimeUnits | str | None = DefaultTimeUnit,
94
- axes_names: Sequence[str] | None = None,
95
- name: str | None = None,
96
- chunks: Sequence[int] | Literal["auto"] = "auto",
97
- dtype: str = "uint32",
98
- dimension_separator: Literal[".", "/"] = "/",
99
- compressors: CompressorLike = "auto",
100
- overwrite: bool = False,
101
- ngff_version: NgffVersions = DefaultNgffVersion,
102
- ) -> ZarrGroupHandler:
103
- """Create an empty label with the given shape and metadata.
104
-
105
- Args:
106
- store (StoreOrGroup): The Zarr store or group to create the image in.
107
- shape (Sequence[int]): The shape of the image.
108
- pixelsize (float): The pixel size in x and y dimensions.
109
- z_spacing (float, optional): The spacing between z slices. Defaults to 1.0.
110
- time_spacing (float, optional): The spacing between time points.
111
- Defaults to 1.0.
112
- levels (int | list[str], optional): The number of levels in the pyramid or a
113
- list of level names. Defaults to 5.
114
- yx_scaling_factor (float, optional): The down-scaling factor in x and y
115
- dimensions. Defaults to 2.0.
116
- z_scaling_factor (float, optional): The down-scaling factor in z dimension.
117
- Defaults to 1.0.
118
- space_unit (SpaceUnits, optional): The unit of space. Defaults to
119
- DefaultSpaceUnit.
120
- time_unit (TimeUnits, optional): The unit of time. Defaults to
121
- DefaultTimeUnit.
122
- axes_names (Sequence[str] | None, optional): The names of the axes.
123
- If None the canonical names are used. Defaults to None.
124
- name (str | None, optional): The name of the image. Defaults to None.
125
- chunks (Sequence[int] | Literal["auto"]): The chunk shape. If None the shape
126
- is used. Defaults to None.
127
- dimension_separator (DIMENSION_SEPARATOR): The separator to use for
128
- dimensions. Defaults to "/".
129
- compressors (CompressorLike): The compressors to use. Defaults to "auto".
130
- dtype (str, optional): The data type of the image. Defaults to "uint16".
131
- overwrite (bool, optional): Whether to overwrite an existing image.
132
- Defaults to True.
133
- ngff_version (str, optional): The version of the OME-Zarr specification.
134
- Defaults to DefaultVersion.
135
-
136
- """
137
- if axes_names is None:
138
- axes_names = canonical_label_axes_order()[-len(shape) :]
139
-
140
- if len(axes_names) != len(shape):
141
- raise NgioValueError(
142
- f"Number of axes names {axes_names} does not match the number of "
143
- f"dimensions {shape}."
144
- )
145
-
146
- meta, scaling_factors = _init_generic_meta(
147
- meta_type=NgioLabelMeta,
148
- pixelsize=pixelsize,
149
- z_spacing=z_spacing,
150
- time_spacing=time_spacing,
151
- levels=levels,
152
- yx_scaling_factor=yx_scaling_factor,
153
- z_scaling_factor=z_scaling_factor,
154
- space_unit=space_unit,
155
- time_unit=time_unit,
156
- axes_names=axes_names,
157
- name=name,
158
- ngff_version=ngff_version,
159
- )
160
-
161
- mode = "w" if overwrite else "w-"
162
- group_handler = ZarrGroupHandler(
163
- store=store, mode=mode, cache=False, zarr_format=meta.zarr_format
164
- )
165
- image_handler = get_label_meta_handler(
166
- version=ngff_version, group_handler=group_handler
167
- )
168
- image_handler.write_meta(meta)
169
-
170
- init_empty_pyramid(
171
- store=store,
172
- paths=meta.paths,
173
- scaling_factors=scaling_factors,
174
- ref_shape=shape,
175
- chunks=chunks,
176
- axes=axes_names,
177
- dtype=dtype,
178
- mode="a",
179
- dimension_separator=dimension_separator,
180
- compressors=compressors,
181
- )
182
- group_handler._mode = "r+"
183
- return group_handler
184
-
185
-
186
- def create_empty_image_container(
187
- store: StoreOrGroup,
188
- shape: Sequence[int],
189
- pixelsize: float,
190
- z_spacing: float = 1.0,
191
- time_spacing: float = 1.0,
192
- levels: int | list[str] = 5,
193
- yx_scaling_factor: float | tuple[float, float] = 2,
194
- z_scaling_factor: float = 1.0,
195
- space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
196
- time_unit: TimeUnits | str | None = DefaultTimeUnit,
197
- axes_names: Sequence[str] | None = None,
198
- name: str | None = None,
199
- chunks: Sequence[int] | Literal["auto"] = "auto",
200
- dtype: str = "uint16",
201
- dimension_separator: Literal[".", "/"] = "/",
202
- compressors: CompressorLike = "auto",
203
- overwrite: bool = False,
204
- ngff_version: NgffVersions = DefaultNgffVersion,
205
- ) -> ZarrGroupHandler:
206
- """Create an empty OME-Zarr image with the given shape and metadata.
207
-
208
- Args:
209
- store (StoreOrGroup): The Zarr store or group to create the image in.
210
- shape (Sequence[int]): The shape of the image.
211
- pixelsize (float): The pixel size in x and y dimensions.
212
- z_spacing (float, optional): The spacing between z slices. Defaults to 1.0.
213
- time_spacing (float, optional): The spacing between time points.
214
- Defaults to 1.0.
215
- levels (int | list[str], optional): The number of levels in the pyramid or a
216
- list of level names. Defaults to 5.
217
- yx_scaling_factor (float, optional): The down-scaling factor in x and y
218
- dimensions. Defaults to 2.0.
219
- z_scaling_factor (float, optional): The down-scaling factor in z dimension.
220
- Defaults to 1.0.
221
- space_unit (SpaceUnits, optional): The unit of space. Defaults to
222
- DefaultSpaceUnit.
223
- time_unit (TimeUnits, optional): The unit of time. Defaults to
224
- DefaultTimeUnit.
225
- axes_names (Sequence[str] | None, optional): The names of the axes.
226
- If None the canonical names are used. Defaults to None.
227
- name (str | None, optional): The name of the image. Defaults to None.
228
- chunks (Sequence[int] | Literal["auto"]): The chunk shape. If None the shape
229
- is used. Defaults to None.
230
- dtype (str, optional): The data type of the image. Defaults to "uint16".
231
- dimension_separator (DIMENSION_SEPARATOR): The separator to use for
232
- dimensions. Defaults to "/".
233
- compressors (CompressorLike): The compressors to use. Defaults to "auto".
234
- overwrite (bool, optional): Whether to overwrite an existing image.
235
- Defaults to True.
236
- ngff_version (str, optional): The version of the OME-Zarr specification.
237
- Defaults to DefaultVersion.
238
-
239
- """
240
- if axes_names is None:
241
- axes_names = canonical_axes_order()[-len(shape) :]
242
-
243
- if len(axes_names) != len(shape):
244
- raise NgioValueError(
245
- f"Number of axes names {axes_names} does not match the number of "
246
- f"dimensions {shape}."
247
- )
248
-
249
- meta, scaling_factors = _init_generic_meta(
250
- meta_type=NgioImageMeta,
251
- pixelsize=pixelsize,
252
- z_spacing=z_spacing,
253
- time_spacing=time_spacing,
254
- levels=levels,
255
- yx_scaling_factor=yx_scaling_factor,
256
- z_scaling_factor=z_scaling_factor,
257
- space_unit=space_unit,
258
- time_unit=time_unit,
259
- axes_names=axes_names,
260
- name=name,
261
- ngff_version=ngff_version,
262
- )
263
- mode = "w" if overwrite else "w-"
264
- group_handler = ZarrGroupHandler(
265
- store=store, mode=mode, cache=False, zarr_format=meta.zarr_format
266
- )
267
- image_handler = get_image_meta_handler(
268
- version=ngff_version, group_handler=group_handler
269
- )
270
- image_handler.write_meta(meta)
271
-
272
- init_empty_pyramid(
273
- store=store,
274
- paths=meta.paths,
275
- scaling_factors=scaling_factors,
276
- ref_shape=shape,
277
- chunks=chunks,
278
- axes=axes_names,
279
- dtype=dtype,
280
- mode="a",
281
- dimension_separator=dimension_separator,
282
- compressors=compressors,
283
- zarr_format=meta.zarr_format,
284
- )
285
-
286
- group_handler._mode = "r+"
287
- return group_handler
@@ -1,196 +0,0 @@
1
- import io
2
- from collections.abc import Callable
3
- from typing import Any
4
-
5
- from pandas import DataFrame
6
- from polars import DataFrame as PolarsDataFrame
7
- from polars import LazyFrame
8
- from zarr.storage import FsspecStore, LocalStore
9
-
10
- from ngio.tables.backends._abstract_backend import AbstractTableBackend
11
- from ngio.tables.backends._utils import normalize_pandas_df, normalize_polars_lf
12
- from ngio.utils import NgioFileNotFoundError, NgioValueError
13
-
14
-
15
- class NonZarrBaseBackend(AbstractTableBackend):
16
- """A class to load and write small tables in CSV format."""
17
-
18
- def __init__(
19
- self,
20
- df_reader: Callable[[Any], DataFrame],
21
- lf_reader: Callable[[Any], LazyFrame],
22
- df_writer: Callable[[str, DataFrame], None],
23
- lf_writer: Callable[[str, PolarsDataFrame], None],
24
- table_name: str,
25
- ):
26
- self.df_reader = df_reader
27
- self.lf_reader = lf_reader
28
- self.df_writer = df_writer
29
- self.lf_writer = lf_writer
30
- self.table_name = table_name
31
-
32
- @staticmethod
33
- def implements_anndata() -> bool:
34
- """Whether the handler implements the anndata protocol."""
35
- return False
36
-
37
- @staticmethod
38
- def implements_pandas() -> bool:
39
- """Whether the handler implements the dataframe protocol."""
40
- return True
41
-
42
- @staticmethod
43
- def implements_polars() -> bool:
44
- """Whether the handler implements the polars protocol."""
45
- return True
46
-
47
- @staticmethod
48
- def backend_name() -> str:
49
- """Return the name of the backend."""
50
- raise NotImplementedError(
51
- "The backend_name method must be implemented in the subclass."
52
- )
53
-
54
- def _load_from_directory_store(self, reader):
55
- """Load the table from a directory store."""
56
- url = self._group_handler.full_url
57
- if url is None:
58
- ext = self.table_name.split(".")[-1]
59
- raise NgioValueError(
60
- f"Ngio does not support reading a {ext} table from a "
61
- f"store of type {type(self._group_handler)}. "
62
- "Please make sure to use a compatible "
63
- "store like a zarr.DirectoryStore."
64
- )
65
- table_path = f"{url}/{self.table_name}"
66
- dataframe = reader(table_path)
67
- return dataframe
68
-
69
- def _load_from_fs_store_df(self, reader):
70
- """Load the table from an FS store."""
71
- path = self._group_handler.group.path
72
- table_path = f"{path}/{self.table_name}"
73
- bytes_table = self._group_handler.store.get(table_path)
74
- if bytes_table is None:
75
- raise NgioFileNotFoundError(f"No table found at {table_path}. ")
76
- dataframe = reader(io.BytesIO(bytes_table))
77
- return dataframe
78
-
79
- def _load_from_fs_store_lf(self, reader):
80
- """Load the table from an FS store."""
81
- full_url = self._group_handler.full_url
82
- parquet_path = f"{full_url}/{self.table_name}"
83
- store_fs = self._group_handler.store.fs # type: ignore (in this context, store_fs is a fs.FSStore)
84
- with store_fs.open(parquet_path, "rb") as f:
85
- dataframe = reader(f)
86
- return dataframe
87
-
88
- def load_as_pandas_df(self) -> DataFrame:
89
- """Load the table as a pandas DataFrame."""
90
- store = self._group_handler.store
91
- if isinstance(store, LocalStore):
92
- dataframe = self._load_from_directory_store(reader=self.df_reader)
93
- elif isinstance(store, FsspecStore):
94
- dataframe = self._load_from_fs_store_df(reader=self.df_reader)
95
- else:
96
- ext = self.table_name.split(".")[-1]
97
- raise NgioValueError(
98
- f"Ngio does not support reading a {ext} table from a "
99
- f"store of type {type(store)}. "
100
- "Please make sure to use a compatible "
101
- "store like a zarr.DirectoryStore or "
102
- "zarr.FSStore."
103
- )
104
-
105
- dataframe = normalize_pandas_df(
106
- dataframe,
107
- index_key=self.index_key,
108
- index_type=self.index_type,
109
- reset_index=False,
110
- )
111
- return dataframe
112
-
113
- def load(self) -> DataFrame:
114
- """Load the table as a pandas DataFrame."""
115
- return self.load_as_pandas_df()
116
-
117
- def load_as_polars_lf(self) -> LazyFrame:
118
- """Load the table as a polars LazyFrame."""
119
- store = self._group_handler.store
120
- if isinstance(store, LocalStore):
121
- lazy_frame = self._load_from_directory_store(reader=self.lf_reader)
122
- elif isinstance(store, FsspecStore):
123
- lazy_frame = self._load_from_fs_store_lf(reader=self.lf_reader)
124
- else:
125
- ext = self.table_name.split(".")[-1]
126
- raise NgioValueError(
127
- f"Ngio does not support reading a {ext} from a "
128
- f"store of type {type(store)}. "
129
- "Please make sure to use a compatible "
130
- "store like a zarr.DirectoryStore or "
131
- "zarr.FSStore."
132
- )
133
- if not isinstance(lazy_frame, LazyFrame):
134
- raise NgioValueError(
135
- "Table is not a lazy frame. Please report this issue as an ngio bug."
136
- f" {type(lazy_frame)}"
137
- )
138
-
139
- lazy_frame = normalize_polars_lf(
140
- lazy_frame,
141
- index_key=self.index_key,
142
- index_type=self.index_type,
143
- )
144
- return lazy_frame
145
-
146
- def _get_store_url(self) -> str:
147
- """Get the store URL."""
148
- store = self._group_handler.store
149
- if isinstance(store, LocalStore):
150
- full_url = self._group_handler.full_url
151
- else:
152
- ext = self.table_name.split(".")[-1]
153
- raise NgioValueError(
154
- f"Ngio does not support writing a {ext} file to a "
155
- f"store of type {type(store)}. "
156
- "Please make sure to use a compatible "
157
- "store like a zarr.DirectoryStore or "
158
- "zarr.FSStore."
159
- )
160
- if full_url is None:
161
- ext = self.table_name.split(".")[-1]
162
- raise NgioValueError(
163
- f"Ngio does not support writing a {ext} file to a "
164
- f"store of type {type(store)}. "
165
- "Please make sure to use a compatible "
166
- "store like a zarr.DirectoryStore or "
167
- "zarr.FSStore."
168
- )
169
- return full_url
170
-
171
- def write_from_pandas(self, table: DataFrame) -> None:
172
- """Write the table from a pandas DataFrame."""
173
- table = normalize_pandas_df(
174
- table,
175
- index_key=self.index_key,
176
- index_type=self.index_type,
177
- reset_index=True,
178
- )
179
- full_url = self._get_store_url()
180
- table_path = f"{full_url}/{self.table_name}"
181
- self.df_writer(table_path, table)
182
-
183
- def write_from_polars(self, table: PolarsDataFrame | LazyFrame) -> None:
184
- """Write the table from a polars DataFrame or LazyFrame."""
185
- table = normalize_polars_lf(
186
- table,
187
- index_key=self.index_key,
188
- index_type=self.index_type,
189
- )
190
-
191
- if isinstance(table, LazyFrame):
192
- table = table.collect()
193
-
194
- full_url = self._get_store_url()
195
- table_path = f"{full_url}/{self.table_name}"
196
- self.lf_writer(table_path, table)
ngio/utils/_logger.py DELETED
@@ -1,50 +0,0 @@
1
- import logging
2
- import time
3
- from functools import cache
4
-
5
- from ngio.utils._errors import NgioValueError
6
-
7
- # Configure the logger
8
- ngio_logger = logging.getLogger("NgioLogger")
9
- ngio_logger.setLevel(logging.ERROR)
10
-
11
- # Set up a console handler with a custom format
12
- console_handler = logging.StreamHandler()
13
- formatter = logging.Formatter(
14
- "%(asctime)s - %(levelname)s - %(name)s - "
15
- "[%(module)s.%(funcName)s:%(lineno)d]: %(message)s"
16
- )
17
- console_handler.setFormatter(formatter)
18
-
19
- # Add the handler to the logger
20
- ngio_logger.addHandler(console_handler)
21
-
22
-
23
- def set_logger_level(level: str) -> None:
24
- """Set the logger level.
25
-
26
- Args:
27
- level: The level to set the logger to.
28
- Must be one of "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL".
29
- """
30
- if level not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
31
- raise NgioValueError(f"Invalid log level: {level}")
32
-
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)