ngio 0.5.0__py3-none-any.whl → 0.5.0a2__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 (53) hide show
  1. ngio/__init__.py +2 -5
  2. ngio/common/__init__.py +6 -11
  3. ngio/common/_masking_roi.py +54 -34
  4. ngio/common/_pyramid.py +85 -309
  5. ngio/common/_roi.py +330 -258
  6. ngio/experimental/iterators/_feature.py +3 -3
  7. ngio/experimental/iterators/_rois_utils.py +11 -10
  8. ngio/hcs/_plate.py +60 -132
  9. ngio/images/_abstract_image.py +35 -539
  10. ngio/images/_create.py +287 -0
  11. ngio/images/_create_synt_container.py +42 -39
  12. ngio/images/_image.py +250 -516
  13. ngio/images/_label.py +172 -249
  14. ngio/images/_masked_image.py +2 -2
  15. ngio/images/_ome_zarr_container.py +241 -644
  16. ngio/io_pipes/_io_pipes.py +9 -9
  17. ngio/io_pipes/_io_pipes_masked.py +7 -7
  18. ngio/io_pipes/_io_pipes_roi.py +6 -6
  19. ngio/io_pipes/_io_pipes_types.py +3 -3
  20. ngio/io_pipes/_match_shape.py +8 -6
  21. ngio/io_pipes/_ops_slices_utils.py +5 -8
  22. ngio/ome_zarr_meta/__init__.py +18 -29
  23. ngio/ome_zarr_meta/_meta_handlers.py +708 -392
  24. ngio/ome_zarr_meta/ngio_specs/__init__.py +0 -4
  25. ngio/ome_zarr_meta/ngio_specs/_axes.py +51 -152
  26. ngio/ome_zarr_meta/ngio_specs/_dataset.py +22 -13
  27. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +91 -129
  28. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +68 -57
  29. ngio/ome_zarr_meta/v04/__init__.py +1 -5
  30. ngio/ome_zarr_meta/v04/{_v04_spec.py → _v04_spec_utils.py} +85 -54
  31. ngio/ome_zarr_meta/v05/__init__.py +1 -5
  32. ngio/ome_zarr_meta/v05/{_v05_spec.py → _v05_spec_utils.py} +87 -64
  33. ngio/resources/__init__.py +1 -1
  34. ngio/resources/resource_model.py +1 -1
  35. ngio/tables/_tables_container.py +11 -62
  36. ngio/tables/backends/_anndata.py +8 -58
  37. ngio/tables/backends/_anndata_utils.py +6 -1
  38. ngio/tables/backends/_csv.py +19 -3
  39. ngio/tables/backends/_json.py +13 -10
  40. ngio/tables/backends/_non_zarr_backends.py +196 -0
  41. ngio/tables/backends/_parquet.py +31 -3
  42. ngio/tables/v1/_roi_table.py +24 -41
  43. ngio/utils/__init__.py +12 -6
  44. ngio/utils/_datasets.py +0 -6
  45. ngio/utils/_logger.py +50 -0
  46. ngio/utils/_zarr_utils.py +58 -167
  47. {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/METADATA +4 -11
  48. ngio-0.5.0a2.dist-info/RECORD +89 -0
  49. {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/WHEEL +1 -1
  50. ngio/images/_create_utils.py +0 -406
  51. ngio/tables/backends/_py_arrow_backends.py +0 -222
  52. ngio-0.5.0.dist-info/RECORD +0 -88
  53. {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -1,406 +0,0 @@
1
- """Utility functions for working with OME-Zarr images."""
2
-
3
- import warnings
4
- from collections.abc import Mapping, Sequence
5
- from typing import Any, Literal, TypeVar
6
-
7
- from zarr.core.array import CompressorLike
8
-
9
- from ngio.common._pyramid import ChunksLike, ImagePyramidBuilder, ShardsLike
10
- from ngio.ome_zarr_meta import (
11
- NgioImageMeta,
12
- NgioLabelMeta,
13
- update_ngio_meta,
14
- )
15
- from ngio.ome_zarr_meta.ngio_specs import (
16
- AxesHandler,
17
- Channel,
18
- ChannelsMeta,
19
- DefaultNgffVersion,
20
- DefaultSpaceUnit,
21
- DefaultTimeUnit,
22
- NgffVersions,
23
- SpaceUnits,
24
- TimeUnits,
25
- build_axes_handler,
26
- build_canonical_axes_handler,
27
- canonical_axes_order,
28
- canonical_label_axes_order,
29
- )
30
- from ngio.ome_zarr_meta.ngio_specs._axes import AxesSetup
31
- from ngio.utils import NgioValueError, StoreOrGroup, ZarrGroupHandler
32
-
33
- _image_or_label_meta = TypeVar("_image_or_label_meta", NgioImageMeta, NgioLabelMeta)
34
-
35
-
36
- def _align_to_axes(
37
- *,
38
- values: dict[str, float],
39
- axes_handler: AxesHandler,
40
- default_value: float = 1.0,
41
- ) -> tuple[float, ...]:
42
- """Align given values to axes names."""
43
- aligned_values = [default_value] * len(axes_handler.axes_names)
44
- for ax, value in values.items():
45
- index = axes_handler.get_index(ax)
46
- if index is not None:
47
- aligned_values[index] = value
48
- return tuple(aligned_values)
49
-
50
-
51
- def _check_deprecated_scaling_factors(
52
- *,
53
- yx_scaling_factor: float | tuple[float, float] | None = None,
54
- z_scaling_factor: float | None = None,
55
- scaling_factors: Sequence[float] | Literal["auto"] = "auto",
56
- shape: tuple[int, ...],
57
- ) -> Sequence[float] | Literal["auto"]:
58
- if yx_scaling_factor is not None or z_scaling_factor is not None:
59
- warnings.warn(
60
- "The 'yx_scaling_factor' and 'z_scaling_factor' arguments are deprecated "
61
- "and will be removed in ngio=0.6. Please use the 'scaling_factors' "
62
- "argument instead.",
63
- DeprecationWarning,
64
- stacklevel=2,
65
- )
66
- if scaling_factors != "auto":
67
- raise NgioValueError(
68
- "Cannot use both 'scaling_factors' and deprecated "
69
- "'yx_scaling_factor'/'z_scaling_factor' arguments."
70
- )
71
- if isinstance(yx_scaling_factor, tuple):
72
- if len(yx_scaling_factor) != 2:
73
- raise NgioValueError(
74
- "yx_scaling_factor tuple must have length 2 for y and x scaling."
75
- )
76
- y_scale = yx_scaling_factor[0]
77
- x_scale = yx_scaling_factor[1]
78
- else:
79
- y_scale = yx_scaling_factor if yx_scaling_factor is not None else 2.0
80
- x_scale = yx_scaling_factor if yx_scaling_factor is not None else 2.0
81
- z_scale = z_scaling_factor if z_scaling_factor is not None else 1.0
82
- scaling_factors = (z_scale, x_scale, y_scale)
83
- if len(scaling_factors) < len(shape):
84
- padding = (1.0,) * (len(shape) - len(scaling_factors))
85
- scaling_factors = padding + scaling_factors
86
-
87
- return scaling_factors
88
- return scaling_factors
89
-
90
-
91
- def _compute_scaling_factors(
92
- *,
93
- scaling_factors: Sequence[float] | Literal["auto"],
94
- shape: tuple[int, ...],
95
- axes_handler: AxesHandler,
96
- xy_scaling_factor: float | tuple[float, float] | None = None,
97
- z_scaling_factor: float | None = None,
98
- ) -> tuple[float, ...]:
99
- """Compute scaling factors for given axes names."""
100
- # TODO remove with ngio 0.6
101
- scaling_factors = _check_deprecated_scaling_factors(
102
- yx_scaling_factor=xy_scaling_factor,
103
- z_scaling_factor=z_scaling_factor,
104
- scaling_factors=scaling_factors,
105
- shape=shape,
106
- )
107
- if scaling_factors == "auto":
108
- return _align_to_axes(
109
- values={
110
- "x": 2.0,
111
- "y": 2.0,
112
- "z": 1.0,
113
- },
114
- axes_handler=axes_handler,
115
- )
116
- if len(scaling_factors) != len(shape):
117
- raise NgioValueError(
118
- "Length of scaling_factors does not match the number of dimensions."
119
- )
120
- return tuple(scaling_factors)
121
-
122
-
123
- def compute_base_scale(
124
- *,
125
- pixelsize: float | tuple[float, float],
126
- z_spacing: float,
127
- time_spacing: float,
128
- axes_handler: AxesHandler,
129
- ) -> tuple[float, ...]:
130
- """Compute base scale for given axes names."""
131
- if isinstance(pixelsize, tuple):
132
- if len(pixelsize) != 2:
133
- raise NgioValueError(
134
- "pixelsize tuple must have length 2 for y and x pixel sizes."
135
- )
136
- x_size = pixelsize[1]
137
- y_size = pixelsize[0]
138
- else:
139
- x_size = pixelsize
140
- y_size = pixelsize
141
- return _align_to_axes(
142
- values={
143
- "x": x_size,
144
- "y": y_size,
145
- "z": z_spacing,
146
- "t": time_spacing,
147
- },
148
- axes_handler=axes_handler,
149
- )
150
-
151
-
152
- def _create_image_like_group(
153
- *,
154
- store: StoreOrGroup,
155
- pyramid_builder: ImagePyramidBuilder,
156
- meta: _image_or_label_meta,
157
- overwrite: bool = False,
158
- ) -> ZarrGroupHandler:
159
- """Advanced create empty image container function placeholder."""
160
- mode = "w" if overwrite else "w-"
161
- group_handler = ZarrGroupHandler(
162
- store=store, mode=mode, cache=False, zarr_format=meta.zarr_format
163
- )
164
- update_ngio_meta(group_handler, meta)
165
- # Reopen in r+ mode
166
- group_handler = group_handler.reopen_handler()
167
- # Write the pyramid
168
- pyramid_builder.to_zarr(group=group_handler.group)
169
- return group_handler
170
-
171
-
172
- def _add_channels_meta(
173
- *,
174
- meta: _image_or_label_meta,
175
- channels_meta: Sequence[str | Channel] | None = None,
176
- ) -> _image_or_label_meta:
177
- """Create ChannelsMeta from given channels_meta input."""
178
- if isinstance(meta, NgioLabelMeta):
179
- if channels_meta is not None:
180
- raise NgioValueError(
181
- "Cannot add channels_meta to NgioLabelMeta. "
182
- "Labels do not have channels."
183
- )
184
- else:
185
- return meta
186
- if channels_meta is None:
187
- return meta
188
- list_of_channels = []
189
- for c in channels_meta:
190
- if isinstance(c, str):
191
- channel = Channel.default_init(label=c)
192
- elif isinstance(c, Channel):
193
- channel = c
194
- else:
195
- raise NgioValueError(
196
- "channels_meta must be a list of strings or Channel objects."
197
- )
198
- list_of_channels.append(channel)
199
-
200
- channels_meta_ = ChannelsMeta(channels=list_of_channels)
201
- meta.set_channels_meta(channels_meta=channels_meta_)
202
- return meta
203
-
204
-
205
- def _build_axes_handler(
206
- *,
207
- shape: tuple[int, ...],
208
- meta_type: type[_image_or_label_meta],
209
- axes_names: Sequence[str] | None = None,
210
- axes_setup: AxesSetup | None = None,
211
- ) -> AxesHandler:
212
- """Build axes handler for given shape and axes names."""
213
- if meta_type is NgioImageMeta:
214
- canonical_axes_order_ = canonical_axes_order()
215
- else:
216
- canonical_axes_order_ = canonical_label_axes_order()
217
- if axes_names is None:
218
- axes_names = canonical_axes_order_[-len(shape) :]
219
-
220
- if axes_setup is None:
221
- return build_canonical_axes_handler(
222
- axes_names=axes_names,
223
- canonical_channel_order=canonical_axes_order_,
224
- )
225
- return build_axes_handler(
226
- axes_names=axes_names,
227
- axes_setup=axes_setup,
228
- )
229
-
230
-
231
- def init_image_like(
232
- *,
233
- # Where to create the image
234
- store: StoreOrGroup,
235
- # Ngff image parameters
236
- meta_type: type[_image_or_label_meta],
237
- shape: Sequence[int],
238
- pixelsize: float | tuple[float, float],
239
- z_spacing: float = 1.0,
240
- time_spacing: float = 1.0,
241
- scaling_factors: Sequence[float] | Literal["auto"] = "auto",
242
- levels: int | list[str] = 5,
243
- translation: Sequence[float] | None = None,
244
- space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
245
- time_unit: TimeUnits | str | None = DefaultTimeUnit,
246
- axes_names: Sequence[str] | None = None,
247
- name: str | None = None,
248
- channels_meta: Sequence[str | Channel] | None = None,
249
- ngff_version: NgffVersions = DefaultNgffVersion,
250
- # Zarr Array parameters
251
- chunks: ChunksLike = "auto",
252
- shards: ShardsLike | None = None,
253
- dtype: str = "uint16",
254
- dimension_separator: Literal[".", "/"] = "/",
255
- compressors: CompressorLike = "auto",
256
- extra_array_kwargs: Mapping[str, Any] | None = None,
257
- # internal axes configuration for advanced use cases
258
- axes_setup: AxesSetup | None = None,
259
- # Whether to overwrite existing image
260
- overwrite: bool = False,
261
- # Deprecated arguments
262
- yx_scaling_factor: float | tuple[float, float] | None = None,
263
- z_scaling_factor: float | None = None,
264
- ) -> tuple[ZarrGroupHandler, AxesSetup]:
265
- """Create an empty OME-Zarr image with the given shape and metadata."""
266
- shape = tuple(shape)
267
- axes_handler = _build_axes_handler(
268
- shape=shape,
269
- meta_type=meta_type,
270
- axes_names=axes_names,
271
- axes_setup=axes_setup,
272
- )
273
- if len(shape) != len(axes_handler.axes_names):
274
- raise NgioValueError(
275
- f"Mismatch between shape {shape} "
276
- f"and number of axes {len(axes_handler.axes_names)}."
277
- )
278
- base_scale = compute_base_scale(
279
- pixelsize=pixelsize,
280
- z_spacing=z_spacing,
281
- time_spacing=time_spacing,
282
- axes_handler=axes_handler,
283
- )
284
- scaling_factors = _compute_scaling_factors(
285
- scaling_factors=scaling_factors,
286
- shape=shape,
287
- axes_handler=axes_handler,
288
- xy_scaling_factor=yx_scaling_factor,
289
- z_scaling_factor=z_scaling_factor,
290
- )
291
- if isinstance(levels, int):
292
- levels_paths = tuple(str(i) for i in range(levels))
293
- else:
294
- levels_paths = tuple(levels)
295
-
296
- pyramid_builder = ImagePyramidBuilder.from_scaling_factors(
297
- levels_paths=levels_paths,
298
- scaling_factors=scaling_factors,
299
- base_shape=shape,
300
- base_scale=base_scale,
301
- base_translation=translation,
302
- axes=axes_handler.axes_names,
303
- chunks=chunks,
304
- data_type=dtype,
305
- dimension_separator=dimension_separator,
306
- compressors=compressors,
307
- shards=shards,
308
- zarr_format=2 if ngff_version == "0.4" else 3,
309
- other_array_kwargs=extra_array_kwargs,
310
- )
311
- meta = meta_type.default_init(
312
- levels=[p.path for p in pyramid_builder.levels],
313
- axes_handler=axes_handler,
314
- scales=[p.scale for p in pyramid_builder.levels],
315
- translations=[p.translation for p in pyramid_builder.levels],
316
- name=name,
317
- version=ngff_version,
318
- )
319
- meta = _add_channels_meta(meta=meta, channels_meta=channels_meta)
320
- # Keep this creation at the end to avoid partial creations on errors
321
- image_handler = _create_image_like_group(
322
- store=store,
323
- pyramid_builder=pyramid_builder,
324
- meta=meta,
325
- overwrite=overwrite,
326
- )
327
- return image_handler, axes_handler.axes_setup
328
-
329
-
330
- def init_image_like_from_shapes(
331
- *,
332
- # Where to create the image
333
- store: StoreOrGroup,
334
- # Ngff image parameters
335
- meta_type: type[_image_or_label_meta],
336
- shapes: Sequence[tuple[int, ...]],
337
- base_scale: tuple[float, ...] | list[tuple[float, ...]],
338
- levels: list[str] | None = None,
339
- translation: Sequence[float] | None = None,
340
- space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
341
- time_unit: TimeUnits | str | None = DefaultTimeUnit,
342
- axes_names: Sequence[str] | None = None,
343
- name: str | None = None,
344
- channels_meta: Sequence[str | Channel] | None = None,
345
- ngff_version: NgffVersions = DefaultNgffVersion,
346
- # Zarr Array parameters
347
- chunks: ChunksLike = "auto",
348
- shards: ShardsLike | None = None,
349
- dtype: str = "uint16",
350
- dimension_separator: Literal[".", "/"] = "/",
351
- compressors: CompressorLike = "auto",
352
- extra_array_kwargs: Mapping[str, Any] | None = None,
353
- # internal axes configuration for advanced use cases
354
- axes_setup: AxesSetup | None = None,
355
- # Whether to overwrite existing image
356
- overwrite: bool = False,
357
- ) -> tuple[ZarrGroupHandler, AxesSetup]:
358
- """Create an empty OME-Zarr image with the given shape and metadata."""
359
- base_shape = shapes[0]
360
- axes_handler = _build_axes_handler(
361
- shape=base_shape,
362
- meta_type=meta_type,
363
- axes_names=axes_names,
364
- axes_setup=axes_setup,
365
- )
366
- if len(base_shape) != len(axes_handler.axes_names):
367
- raise NgioValueError(
368
- f"Mismatch between shape {base_shape} "
369
- f"and number of axes {len(axes_handler.axes_names)}."
370
- )
371
- if levels is None:
372
- levels_paths = tuple(str(i) for i in range(len(shapes)))
373
- else:
374
- levels_paths = tuple(levels)
375
-
376
- pyramid_builder = ImagePyramidBuilder.from_shapes(
377
- shapes=shapes,
378
- base_scale=base_scale,
379
- base_translation=translation,
380
- levels_paths=levels_paths,
381
- axes=axes_handler.axes_names,
382
- chunks=chunks,
383
- data_type=dtype,
384
- dimension_separator=dimension_separator,
385
- compressors=compressors,
386
- shards=shards,
387
- zarr_format=2 if ngff_version == "0.4" else 3,
388
- other_array_kwargs=extra_array_kwargs,
389
- )
390
- meta = meta_type.default_init(
391
- levels=[p.path for p in pyramid_builder.levels],
392
- axes_handler=axes_handler,
393
- scales=[p.scale for p in pyramid_builder.levels],
394
- translations=[p.translation for p in pyramid_builder.levels],
395
- name=name,
396
- version=ngff_version,
397
- )
398
- meta = _add_channels_meta(meta=meta, channels_meta=channels_meta)
399
- # Keep this creation at the end to avoid partial creations on errors
400
- image_handler = _create_image_like_group(
401
- store=store,
402
- pyramid_builder=pyramid_builder,
403
- meta=meta,
404
- overwrite=overwrite,
405
- )
406
- return image_handler, axes_handler.axes_setup
@@ -1,222 +0,0 @@
1
- from typing import Literal
2
-
3
- import polars as pl
4
- import pyarrow as pa
5
- import pyarrow.csv as pa_csv
6
- import pyarrow.dataset as pa_ds
7
- import pyarrow.fs as pa_fs
8
- import pyarrow.parquet as pa_parquet
9
- from pandas import DataFrame
10
- from polars import DataFrame as PolarsDataFrame
11
- from polars import LazyFrame
12
- from zarr.storage import FsspecStore, LocalStore, MemoryStore, ZipStore
13
-
14
- from ngio.tables.backends._abstract_backend import AbstractTableBackend
15
- from ngio.tables.backends._utils import normalize_pandas_df, normalize_polars_lf
16
- from ngio.utils import NgioValueError
17
- from ngio.utils._zarr_utils import _make_sync_fs
18
-
19
-
20
- class PyArrowBackend(AbstractTableBackend):
21
- """A class to load and write small tables in CSV format."""
22
-
23
- def __init__(
24
- self,
25
- table_name: str,
26
- table_format: Literal["csv", "parquet"] = "parquet",
27
- ):
28
- self.table_name = table_name
29
- self.table_format = table_format
30
-
31
- @staticmethod
32
- def implements_anndata() -> bool:
33
- """Whether the handler implements the anndata protocol."""
34
- return False
35
-
36
- @staticmethod
37
- def implements_pandas() -> bool:
38
- """Whether the handler implements the dataframe protocol."""
39
- return True
40
-
41
- @staticmethod
42
- def implements_polars() -> bool:
43
- """Whether the handler implements the polars protocol."""
44
- return True
45
-
46
- @staticmethod
47
- def backend_name() -> str:
48
- """Return the name of the backend."""
49
- raise NotImplementedError(
50
- "The backend_name method must be implemented in the subclass."
51
- )
52
-
53
- def _raise_store_type_not_supported(self):
54
- """Raise an error for unsupported store types."""
55
- ext = self.table_name.split(".")[-1]
56
- store = self._group_handler.store
57
- raise NgioValueError(
58
- f"Ngio does not support reading a {ext} table from a "
59
- f"store of type {type(store)}. "
60
- "Please make sure to use a compatible "
61
- "store like a LocalStore, or "
62
- "FsspecStore, or MemoryStore, or ZipStore."
63
- )
64
-
65
- def _load_from_local_store(self, store: LocalStore, path: str) -> pa_ds.Dataset:
66
- """Load the table from a directory store."""
67
- root_path = store.root
68
- table_path = f"{root_path}/{path}/{self.table_name}"
69
- dataset = pa_ds.dataset(table_path, format=self.table_format)
70
- return dataset
71
-
72
- def _load_from_fsspec_store(self, store: FsspecStore, path: str) -> pa_ds.Dataset:
73
- """Load the table from an FS store."""
74
- table_path = f"{store.path}/{path}/{self.table_name}"
75
- fs = _make_sync_fs(store.fs)
76
- dataset = pa_ds.dataset(table_path, format=self.table_format, filesystem=fs)
77
- return dataset
78
-
79
- def _load_from_in_memory_store(
80
- self, store: MemoryStore, path: str
81
- ) -> pa_ds.Dataset:
82
- """Load the table from an in-memory store."""
83
- table_path = f"{path}/{self.table_name}"
84
- table = store._store_dict.get(table_path, None)
85
- if table is None:
86
- raise NgioValueError(
87
- f"Table {self.table_name} not found in the in-memory store at "
88
- f"path {path}."
89
- )
90
- assert isinstance(table, pa.Table)
91
- dataset = pa_ds.dataset(table)
92
- return dataset
93
-
94
- def _load_from_zip_store(self, store: ZipStore, path: str) -> pa_ds.Dataset:
95
- """Load the table from a zip store."""
96
- raise NotImplementedError("Zip store loading is not implemented yet.")
97
-
98
- def _load_pyarrow_dataset(self) -> pa_ds.Dataset:
99
- """Load the table as a pyarrow Dataset."""
100
- store = self._group_handler.store
101
- path = self._group_handler.group.path
102
- if isinstance(store, LocalStore):
103
- return self._load_from_local_store(store, path)
104
- elif isinstance(store, FsspecStore):
105
- return self._load_from_fsspec_store(store, path)
106
- elif isinstance(store, MemoryStore):
107
- return self._load_from_in_memory_store(store, path)
108
- elif isinstance(store, ZipStore):
109
- return self._load_from_zip_store(store, path)
110
- self._raise_store_type_not_supported()
111
-
112
- def load_as_pandas_df(self) -> DataFrame:
113
- """Load the table as a pandas DataFrame."""
114
- dataset = self._load_pyarrow_dataset()
115
- dataframe = dataset.to_table().to_pandas()
116
- dataframe = normalize_pandas_df(
117
- dataframe,
118
- index_key=self.index_key,
119
- index_type=self.index_type,
120
- reset_index=False,
121
- )
122
- return dataframe
123
-
124
- def load(self) -> DataFrame:
125
- """Load the table as a pandas DataFrame."""
126
- return self.load_as_pandas_df()
127
-
128
- def load_as_polars_lf(self) -> LazyFrame:
129
- """Load the table as a polars LazyFrame."""
130
- dataset = self._load_pyarrow_dataset()
131
- lazy_frame = pl.scan_pyarrow_dataset(dataset)
132
- if not isinstance(lazy_frame, LazyFrame):
133
- raise NgioValueError(
134
- "Table is not a lazy frame. Please report this issue as an ngio bug."
135
- f" {type(lazy_frame)}"
136
- )
137
-
138
- lazy_frame = normalize_polars_lf(
139
- lazy_frame,
140
- index_key=self.index_key,
141
- index_type=self.index_type,
142
- )
143
- return lazy_frame
144
-
145
- def _write_to_stream(self, stream, table: pa.Table) -> None:
146
- """Write the table to a stream."""
147
- if self.table_format == "parquet":
148
- pa_parquet.write_table(table, stream)
149
- elif self.table_format == "csv":
150
- pa_csv.write_csv(table, stream)
151
- else:
152
- raise NgioValueError(
153
- f"Unsupported table format: {self.table_format}. "
154
- "Supported formats are 'parquet' and 'csv'."
155
- )
156
-
157
- def _write_to_local_store(
158
- self, store: LocalStore, path: str, table: pa.Table
159
- ) -> None:
160
- """Write the table to a directory store."""
161
- root_path = store.root
162
- table_path = f"{root_path}/{path}/{self.table_name}"
163
- self._write_to_stream(table_path, table)
164
-
165
- def _write_to_fsspec_store(
166
- self, store: FsspecStore, path: str, table: pa.Table
167
- ) -> None:
168
- """Write the table to an FS store."""
169
- table_path = f"{store.path}/{path}/{self.table_name}"
170
- fs = _make_sync_fs(store.fs)
171
- fs = pa_fs.PyFileSystem(pa_fs.FSSpecHandler(fs))
172
- with fs.open_output_stream(table_path) as out_stream:
173
- self._write_to_stream(out_stream, table)
174
-
175
- def _write_to_in_memory_store(
176
- self, store: MemoryStore, path: str, table: pa.Table
177
- ) -> None:
178
- """Write the table to an in-memory store."""
179
- table_path = f"{path}/{self.table_name}"
180
- store._store_dict[table_path] = table
181
-
182
- def _write_to_zip_store(self, store: ZipStore, path: str, table: pa.Table) -> None:
183
- """Write the table to a zip store."""
184
- raise NotImplementedError("Writing to zip store is not implemented yet.")
185
-
186
- def _write_pyarrow_dataset(self, dataset: pa.Table) -> None:
187
- """Write the table from a pyarrow Dataset."""
188
- store = self._group_handler.store
189
- path = self._group_handler.group.path
190
- if isinstance(store, LocalStore):
191
- return self._write_to_local_store(store=store, path=path, table=dataset)
192
- elif isinstance(store, FsspecStore):
193
- return self._write_to_fsspec_store(store=store, path=path, table=dataset)
194
- elif isinstance(store, MemoryStore):
195
- return self._write_to_in_memory_store(store=store, path=path, table=dataset)
196
- elif isinstance(store, ZipStore):
197
- return self._write_to_zip_store(store=store, path=path, table=dataset)
198
- self._raise_store_type_not_supported()
199
-
200
- def write_from_pandas(self, table: DataFrame) -> None:
201
- """Write the table from a pandas DataFrame."""
202
- table = normalize_pandas_df(
203
- table,
204
- index_key=self.index_key,
205
- index_type=self.index_type,
206
- reset_index=True,
207
- )
208
- table = pa.Table.from_pandas(table, preserve_index=False)
209
- self._write_pyarrow_dataset(table)
210
-
211
- def write_from_polars(self, table: PolarsDataFrame | LazyFrame) -> None:
212
- """Write the table from a polars DataFrame or LazyFrame."""
213
- table = normalize_polars_lf(
214
- table,
215
- index_key=self.index_key,
216
- index_type=self.index_type,
217
- )
218
-
219
- if isinstance(table, LazyFrame):
220
- table = table.collect()
221
- table = table.to_arrow()
222
- self._write_pyarrow_dataset(table)