ngio 0.3.0a1__py3-none-any.whl → 0.3.1__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,10 +1,11 @@
1
1
  from collections.abc import Collection, Iterable
2
2
  from typing import Literal
3
3
 
4
- import dask
5
- import dask.delayed
4
+ import dask.array as da
6
5
  import numpy as np
7
6
  import zarr
7
+ from dask.array import Array as DaskArray
8
+ from dask.delayed import Delayed, delayed
8
9
 
9
10
  from ngio.common._axes_transforms import transform_dask_array, transform_numpy_array
10
11
  from ngio.common._common_types import ArrayLike
@@ -55,26 +56,26 @@ def _numpy_get_pipe(
55
56
  slices: SliceTransform,
56
57
  transformations: tuple[AxesTransformation, ...],
57
58
  ) -> np.ndarray:
58
- array = numpy_get_slice(array, slices)
59
- return transform_numpy_array(array, transformations)
59
+ _array = numpy_get_slice(array, slices)
60
+ return transform_numpy_array(_array, transformations)
60
61
 
61
62
 
62
63
  def _delayed_numpy_get_pipe(
63
64
  array: zarr.Array,
64
65
  slices: SliceTransform,
65
66
  transformations: tuple[AxesTransformation, ...],
66
- ) -> dask.delayed:
67
- array = dask.delayed(numpy_get_slice)(array, slices)
68
- return dask.delayed(transform_numpy_array)(array, transformations)
67
+ ) -> Delayed:
68
+ _array = delayed(numpy_get_slice)(array, slices)
69
+ return delayed(transform_numpy_array)(_array, transformations)
69
70
 
70
71
 
71
72
  def _dask_get_pipe(
72
73
  array: zarr.Array,
73
74
  slices: SliceTransform,
74
75
  transformations: tuple[AxesTransformation, ...],
75
- ) -> dask.array:
76
- array = dask_get_slice(array, slices)
77
- return transform_dask_array(array, transformations)
76
+ ) -> DaskArray:
77
+ _array = dask_get_slice(array, slices)
78
+ return transform_dask_array(_array, transformations)
78
79
 
79
80
 
80
81
  def _numpy_set_pipe(
@@ -89,22 +90,22 @@ def _numpy_set_pipe(
89
90
 
90
91
  def _dask_set_pipe(
91
92
  array: zarr.Array,
92
- patch: np.ndarray,
93
+ patch: DaskArray,
93
94
  slices: SliceTransform,
94
95
  transformations: tuple[AxesTransformation, ...],
95
96
  ) -> None:
96
- patch = transform_dask_array(patch, transformations)
97
- dask_set_slice(array, patch, slices)
97
+ _patch = transform_dask_array(patch, transformations)
98
+ dask_set_slice(array, _patch, slices)
98
99
 
99
100
 
100
101
  def _delayed_numpy_set_pipe(
101
102
  array: zarr.Array,
102
- patch: np.ndarray,
103
+ patch: np.ndarray | Delayed,
103
104
  slices: SliceTransform,
104
105
  transformations: tuple[AxesTransformation, ...],
105
- ) -> dask.delayed:
106
- patch = dask.delayed(transform_numpy_array)(patch, transformations)
107
- return dask.delayed(numpy_set_slice)(array, patch, slices)
106
+ ) -> Delayed:
107
+ _patch = delayed(transform_numpy_array)(patch, transformations)
108
+ return delayed(numpy_set_slice)(array, _patch, slices)
108
109
 
109
110
 
110
111
  def get_pipe(
@@ -144,7 +145,7 @@ def set_pipe(
144
145
  slices, transformations = _compute_to_disk_transforms(
145
146
  dimensions=dimensions, axes_order=axes_order, **slice_kwargs
146
147
  )
147
- if isinstance(patch, dask.array.Array):
148
+ if isinstance(patch, DaskArray):
148
149
  _dask_set_pipe(
149
150
  array=array, patch=patch, slices=slices, transformations=transformations
150
151
  )
@@ -152,7 +153,7 @@ def set_pipe(
152
153
  _numpy_set_pipe(
153
154
  array=array, patch=patch, slices=slices, transformations=transformations
154
155
  )
155
- elif isinstance(patch, dask.delayed.Delayed):
156
+ elif isinstance(patch, Delayed):
156
157
  _delayed_numpy_set_pipe(
157
158
  array=array, patch=patch, slices=slices, transformations=transformations
158
159
  )
@@ -193,12 +194,15 @@ def _mask_pipe_common(
193
194
  **slice_kwargs,
194
195
  )
195
196
 
196
- if isinstance(array_patch, np.ndarray):
197
+ if isinstance(array_patch, np.ndarray) and isinstance(label_patch, np.ndarray):
197
198
  label_patch = np.broadcast_to(label_patch, array_patch.shape)
198
- elif isinstance(array_patch, dask.array.Array):
199
- label_patch = dask.array.broadcast_to(label_patch, array_patch.shape)
199
+ elif isinstance(array_patch, DaskArray) and isinstance(label_patch, DaskArray):
200
+ label_patch = da.broadcast_to(label_patch, array_patch.shape)
200
201
  else:
201
- raise NgioValueError(f"Mode {mode} not yet supported for masked array.")
202
+ raise NgioValueError(
203
+ "Incompatible types for array and label: "
204
+ f"{type(array_patch)} and {type(label_patch)}"
205
+ )
202
206
 
203
207
  mask = label_patch == label
204
208
  return array_patch, mask
@@ -225,7 +229,14 @@ def get_masked_pipe(
225
229
  mode=mode,
226
230
  **slice_kwargs,
227
231
  )
228
- array_patch[~mask] = 0
232
+ if isinstance(array_patch, np.ndarray):
233
+ array_patch[~mask] = 0
234
+ elif isinstance(array_patch, DaskArray):
235
+ array_patch = da.where(mask, array_patch, 0)
236
+ else:
237
+ raise NgioValueError(
238
+ "Mode not yet supported for masked array. Expected a numpy or dask array."
239
+ )
229
240
  return array_patch
230
241
 
231
242
 
@@ -240,7 +251,7 @@ def set_masked_pipe(
240
251
  axes_order: Collection[str] | None = None,
241
252
  **slice_kwargs: slice | int | Iterable[int],
242
253
  ):
243
- if isinstance(patch, dask.array.Array):
254
+ if isinstance(patch, DaskArray):
244
255
  mode = "dask"
245
256
  elif isinstance(patch, np.ndarray):
246
257
  mode = "numpy"
@@ -259,7 +270,19 @@ def set_masked_pipe(
259
270
  mode=mode,
260
271
  **slice_kwargs,
261
272
  )
262
- patch = np.where(mask, patch, array_patch)
273
+ if isinstance(patch, np.ndarray):
274
+ assert isinstance(array_patch, np.ndarray)
275
+ _patch = np.where(mask, patch, array_patch)
276
+ elif isinstance(patch, DaskArray):
277
+ _patch = da.where(mask, patch, array_patch)
278
+ else:
279
+ raise NgioValueError(
280
+ "Mode not yet supported for masked array. Expected a numpy or dask array."
281
+ )
263
282
  set_pipe(
264
- array, patch, dimensions=dimensions_array, axes_order=axes_order, **slice_kwargs
283
+ array,
284
+ _patch,
285
+ dimensions=dimensions_array,
286
+ axes_order=axes_order,
287
+ **slice_kwargs,
265
288
  )
ngio/common/_table_ops.py CHANGED
@@ -9,7 +9,7 @@ from typing import Literal
9
9
  import pandas as pd
10
10
  import polars as pl
11
11
 
12
- from ngio.images.ome_zarr_container import OmeZarrContainer
12
+ from ngio.images._ome_zarr_container import OmeZarrContainer
13
13
  from ngio.tables import Table, TableType
14
14
 
15
15
 
ngio/hcs/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """OME-Zarr HCS objects models."""
2
2
 
3
- from ngio.hcs.plate import (
3
+ from ngio.hcs._plate import (
4
4
  OmeZarrPlate,
5
5
  OmeZarrWell,
6
6
  create_empty_plate,
@@ -39,7 +39,6 @@ from ngio.tables import (
39
39
  )
40
40
  from ngio.utils import (
41
41
  AccessModeLiteral,
42
- NgioValidationError,
43
42
  NgioValueError,
44
43
  StoreOrGroup,
45
44
  ZarrGroupHandler,
@@ -805,22 +804,38 @@ class OmeZarrPlate:
805
804
  parallel_safe=parallel_safe,
806
805
  )
807
806
 
808
- @property
809
- def tables_container(self) -> TablesContainer:
807
+ def _get_tables_container(self) -> TablesContainer | None:
810
808
  """Return the tables container."""
811
809
  if self._tables_container is None:
812
- self._tables_container = _default_table_container(self._group_handler)
813
- if self._tables_container is None:
814
- raise NgioValidationError("No tables found in the image.")
810
+ _tables_container = _default_table_container(self._group_handler)
811
+ if _tables_container is None:
812
+ return None
813
+ self._tables_container = _tables_container
815
814
  return self._tables_container
816
815
 
817
- def list_tables(self, filter_types: str | None = None) -> list[str]:
816
+ @property
817
+ def tables_container(self) -> TablesContainer:
818
+ """Return the tables container."""
819
+ _table_container = self._get_tables_container()
820
+ if _table_container is None:
821
+ raise NgioValueError(
822
+ "No tables container found. Please add a tables container to the plate."
823
+ )
824
+ return _table_container
825
+
826
+ def list_tables(self, filter_types: TypedTable | str | None = None) -> list[str]:
818
827
  """List all tables in the image."""
819
828
  return self.tables_container.list(filter_types=filter_types)
820
829
 
821
830
  def list_roi_tables(self) -> list[str]:
822
831
  """List all ROI tables in the image."""
823
- return self.tables_container.list_roi_tables()
832
+ masking_roi = self.tables_container.list(
833
+ filter_types="masking_roi_table",
834
+ )
835
+ roi = self.tables_container.list(
836
+ filter_types="roi_table",
837
+ )
838
+ return masking_roi + roi
824
839
 
825
840
  def get_roi_table(self, name: str) -> RoiTable:
826
841
  """Get a ROI table from the image.
ngio/images/__init__.py CHANGED
@@ -1,8 +1,8 @@
1
1
  """OME-Zarr object models."""
2
2
 
3
- from ngio.images.image import Image, ImagesContainer
4
- from ngio.images.label import Label, LabelsContainer
5
- from ngio.images.ome_zarr_container import (
3
+ from ngio.images._image import Image, ImagesContainer
4
+ from ngio.images._label import Label, LabelsContainer
5
+ from ngio.images._ome_zarr_container import (
6
6
  OmeZarrContainer,
7
7
  create_empty_ome_zarr,
8
8
  create_ome_zarr_from_array,
@@ -3,11 +3,11 @@
3
3
  from collections.abc import Collection
4
4
  from typing import Literal
5
5
 
6
- from dask import array as da
6
+ import dask.array as da
7
7
 
8
8
  from ngio.common import Dimensions
9
- from ngio.images.abstract_image import AbstractImage, consolidate_image
10
- from ngio.images.create import create_empty_image_container
9
+ from ngio.images._abstract_image import AbstractImage, consolidate_image
10
+ from ngio.images._create import create_empty_image_container
11
11
  from ngio.ome_zarr_meta import (
12
12
  ImageMetaHandler,
13
13
  NgioImageMeta,
@@ -152,31 +152,33 @@ class ImagesContainer:
152
152
 
153
153
  def set_channel_meta(
154
154
  self,
155
- labels: Collection[str] | int | None = None,
156
- wavelength_id: Collection[str] | None = None,
157
- start: Collection[float] | None = None,
158
- end: Collection[float] | None = None,
155
+ labels: Collection[str | None] | int | None = None,
156
+ wavelength_id: Collection[str | None] | None = None,
157
+ start: Collection[float | None] | None = None,
158
+ end: Collection[float | None] | None = None,
159
159
  percentiles: tuple[float, float] | None = None,
160
- colors: Collection[str] | None = None,
161
- active: Collection[bool] | None = None,
160
+ colors: Collection[str | None] | None = None,
161
+ active: Collection[bool | None] | None = None,
162
162
  **omero_kwargs: dict,
163
163
  ) -> None:
164
164
  """Create a ChannelsMeta object with the default unit.
165
165
 
166
166
  Args:
167
- labels(Collection[str] | int): The list of channels names in the image.
168
- If an integer is provided, the channels will be named "channel_i".
169
- wavelength_id(Collection[str] | None): The wavelength ID of the channel.
167
+ labels(Collection[str | None] | int): The list of channels names
168
+ in the image. If an integer is provided, the channels will
169
+ be named "channel_i".
170
+ wavelength_id(Collection[str | None]): The wavelength ID of the channel.
170
171
  If None, the wavelength ID will be the same as the channel name.
171
- start(Collection[float] | None): The start value for each channel.
172
+ start(Collection[float | None]): The start value for each channel.
172
173
  If None, the start value will be computed from the image.
173
- end(Collection[float] | None): The end value for each channel.
174
+ end(Collection[float | None]): The end value for each channel.
174
175
  If None, the end value will be computed from the image.
175
- percentiles(tuple[float, float] | None): The start and end percentiles
176
- for each channel. If None, the percentiles will not be computed.
177
- colors(Collection[str, NgioColors] | None): The list of colors for the
176
+ percentiles(tuple[float, float] | None): The start and end
177
+ percentiles for each channel. If None, the percentiles will
178
+ not be computed.
179
+ colors(Collection[str | None]): The list of colors for the
178
180
  channels. If None, the colors will be random.
179
- active (Collection[bool] | None):active(bool): Whether the channel should
181
+ active (Collection[bool | None]): Whether the channel should
180
182
  be shown by default.
181
183
  omero_kwargs(dict): Extra fields to store in the omero attributes.
182
184
  """
@@ -376,9 +378,12 @@ def compute_image_percentile(
376
378
  starts, ends = [], []
377
379
  for c in range(image.num_channels):
378
380
  if image.num_channels == 1:
379
- data = image.get_array(mode="dask").ravel()
381
+ data = image.get_array(mode="dask")
380
382
  else:
381
- data = image.get_array(c=c, mode="dask").ravel()
383
+ data = image.get_array(c=c, mode="dask")
384
+
385
+ assert isinstance(data, da.Array), "Data must be a Dask array."
386
+ data = da.ravel(data)
382
387
  # remove all the zeros
383
388
  mask = data > 1e-16
384
389
  data = data[mask]
@@ -391,7 +396,7 @@ def compute_image_percentile(
391
396
  # compute the percentiles
392
397
  _s_perc, _e_perc = da.percentile(
393
398
  data, [start_percentile, end_percentile], method="nearest"
394
- ).compute()
399
+ ).compute() # type: ignore
395
400
 
396
401
  starts.append(float(_s_perc))
397
402
  ends.append(float(_e_perc))
@@ -3,10 +3,12 @@
3
3
  from collections.abc import Collection
4
4
  from typing import Literal
5
5
 
6
+ import dask.array as da
7
+
6
8
  from ngio.common import compute_masking_roi
7
- from ngio.images.abstract_image import AbstractImage, consolidate_image
8
- from ngio.images.create import create_empty_label_container
9
- from ngio.images.image import Image
9
+ from ngio.images._abstract_image import AbstractImage, consolidate_image
10
+ from ngio.images._create import create_empty_label_container
11
+ from ngio.images._image import Image
10
12
  from ngio.ome_zarr_meta import (
11
13
  LabelMetaHandler,
12
14
  NgioLabelMeta,
@@ -309,6 +311,6 @@ def build_masking_roi_table(label: Label) -> MaskingRoiTable:
309
311
  raise NgioValueError("Time series labels are not supported.")
310
312
 
311
313
  array = label.get_array(axes_order=["z", "y", "x"], mode="dask")
312
-
314
+ assert isinstance(array, da.Array), "Array must be a Dask array."
313
315
  rois = compute_masking_roi(array, label.pixel_size)
314
316
  return MaskingRoiTable(rois, reference_label=label.meta.name)
@@ -4,8 +4,8 @@ from collections.abc import Collection, Iterable
4
4
  from typing import Literal
5
5
 
6
6
  from ngio.common import ArrayLike, get_masked_pipe, roi_to_slice_kwargs, set_masked_pipe
7
- from ngio.images.image import Image
8
- from ngio.images.label import Label
7
+ from ngio.images._image import Image
8
+ from ngio.images._label import Label
9
9
  from ngio.ome_zarr_meta import ImageMetaHandler, LabelMetaHandler
10
10
  from ngio.tables import MaskingRoiTable
11
11
  from ngio.utils import (
@@ -5,10 +5,10 @@ from collections.abc import Collection
5
5
 
6
6
  import numpy as np
7
7
 
8
- from ngio.images.create import create_empty_image_container
9
- from ngio.images.image import Image, ImagesContainer
10
- from ngio.images.label import Label, LabelsContainer
11
- from ngio.images.masked_image import MaskedImage, MaskedLabel
8
+ from ngio.images._create import create_empty_image_container
9
+ from ngio.images._image import Image, ImagesContainer
10
+ from ngio.images._label import Label, LabelsContainer
11
+ from ngio.images._masked_image import MaskedImage, MaskedLabel
12
12
  from ngio.ome_zarr_meta import (
13
13
  NgioImageMeta,
14
14
  PixelSize,
@@ -68,7 +68,7 @@ class OmeZarrContainer:
68
68
  group_handler: ZarrGroupHandler,
69
69
  table_container: TablesContainer | None = None,
70
70
  label_container: LabelsContainer | None = None,
71
- validate_arrays: bool = True,
71
+ validate_paths: bool = False,
72
72
  ) -> None:
73
73
  """Initialize the OmeZarrContainer."""
74
74
  self._group_handler = group_handler
@@ -77,6 +77,10 @@ class OmeZarrContainer:
77
77
  self._labels_container = label_container
78
78
  self._tables_container = table_container
79
79
 
80
+ if validate_paths:
81
+ for level_path in self._images_container.levels_paths:
82
+ self.get_image(path=level_path)
83
+
80
84
  def __repr__(self) -> str:
81
85
  """Return a string representation of the image."""
82
86
  num_labels = len(self.list_labels())
@@ -99,24 +103,40 @@ class OmeZarrContainer:
99
103
  """Return the image container."""
100
104
  return self._images_container
101
105
 
102
- @property
103
- def labels_container(self) -> LabelsContainer:
106
+ def _get_labels_container(self) -> LabelsContainer | None:
104
107
  """Return the labels container."""
105
108
  if self._labels_container is None:
106
- self._labels_container = _default_label_container(self._group_handler)
107
- if self._labels_container is None:
108
- raise NgioValidationError("No labels found in the image.")
109
+ _labels_container = _default_label_container(self._group_handler)
110
+ if _labels_container is None:
111
+ return None
112
+ self._labels_container = _labels_container
109
113
  return self._labels_container
110
114
 
111
115
  @property
112
- def tables_container(self) -> TablesContainer:
116
+ def labels_container(self) -> LabelsContainer:
117
+ """Return the labels container."""
118
+ _labels_container = self._get_labels_container()
119
+ if _labels_container is None:
120
+ raise NgioValidationError("No labels found in the image.")
121
+ return _labels_container
122
+
123
+ def _get_tables_container(self) -> TablesContainer | None:
113
124
  """Return the tables container."""
114
125
  if self._tables_container is None:
115
- self._tables_container = _default_table_container(self._group_handler)
116
- if self._tables_container is None:
117
- raise NgioValidationError("No tables found in the image.")
126
+ _tables_container = _default_table_container(self._group_handler)
127
+ if _tables_container is None:
128
+ return None
129
+ self._tables_container = _tables_container
118
130
  return self._tables_container
119
131
 
132
+ @property
133
+ def tables_container(self) -> TablesContainer:
134
+ """Return the tables container."""
135
+ _tables_container = self._get_tables_container()
136
+ if _tables_container is None:
137
+ raise NgioValidationError("No tables found in the image.")
138
+ return _tables_container
139
+
120
140
  @property
121
141
  def image_meta(self) -> NgioImageMeta:
122
142
  """Return the image metadata."""
@@ -332,7 +352,7 @@ class OmeZarrContainer:
332
352
 
333
353
  new_ome_zarr = OmeZarrContainer(
334
354
  group_handler=handler,
335
- validate_arrays=False,
355
+ validate_paths=False,
336
356
  )
337
357
 
338
358
  if copy_labels:
@@ -346,13 +366,25 @@ class OmeZarrContainer:
346
366
  )
347
367
  return new_ome_zarr
348
368
 
349
- def list_tables(self, filter_types: str | None = None) -> list[str]:
369
+ def list_tables(self, filter_types: TypedTable | str | None = None) -> list[str]:
350
370
  """List all tables in the image."""
351
- return self.tables_container.list(filter_types=filter_types)
371
+ table_container = self._get_tables_container()
372
+ if table_container is None:
373
+ return []
374
+
375
+ return table_container.list(
376
+ filter_types=filter_types,
377
+ )
352
378
 
353
379
  def list_roi_tables(self) -> list[str]:
354
380
  """List all ROI tables in the image."""
355
- return self.tables_container.list_roi_tables()
381
+ masking_roi = self.tables_container.list(
382
+ filter_types="masking_roi_table",
383
+ )
384
+ roi = self.tables_container.list(
385
+ filter_types="roi_table",
386
+ )
387
+ return masking_roi + roi
356
388
 
357
389
  def get_roi_table(self, name: str) -> RoiTable:
358
390
  """Get a ROI table from the image.
@@ -479,7 +511,10 @@ class OmeZarrContainer:
479
511
 
480
512
  def list_labels(self) -> list[str]:
481
513
  """List all labels in the image."""
482
- return self.labels_container.list()
514
+ label_container = self._get_labels_container()
515
+ if label_container is None:
516
+ return []
517
+ return label_container.list()
483
518
 
484
519
  def get_label(
485
520
  self,
@@ -597,7 +632,7 @@ def open_ome_zarr_container(
597
632
  handler = ZarrGroupHandler(store=store, cache=cache, mode=mode)
598
633
  return OmeZarrContainer(
599
634
  group_handler=handler,
600
- validate_arrays=validate_arrays,
635
+ validate_paths=validate_arrays,
601
636
  )
602
637
 
603
638
 
@@ -2,15 +2,12 @@
2
2
 
3
3
  from collections.abc import Collection
4
4
  from enum import Enum
5
- from logging import Logger
6
5
  from typing import Literal, TypeVar
7
6
 
8
7
  import numpy as np
9
8
  from pydantic import BaseModel, ConfigDict, Field
10
9
 
11
- from ngio.utils import NgioValidationError, NgioValueError
12
-
13
- logger = Logger(__name__)
10
+ from ngio.utils import NgioValidationError, NgioValueError, ngio_logger
14
11
 
15
12
  T = TypeVar("T")
16
13
 
@@ -102,20 +99,20 @@ class Axis(BaseModel):
102
99
  def implicit_type_cast(self, cast_type: AxisType) -> "Axis":
103
100
  unit = self.unit
104
101
  if self.axis_type != cast_type:
105
- logger.warning(
102
+ ngio_logger.warning(
106
103
  f"Axis {self.on_disk_name} has type {self.axis_type}. "
107
104
  f"Casting to {cast_type}."
108
105
  )
109
106
 
110
107
  if cast_type == AxisType.time and unit is None:
111
- logger.warning(
108
+ ngio_logger.warning(
112
109
  f"Time axis {self.on_disk_name} has unit {self.unit}. "
113
110
  f"Casting to {DefaultSpaceUnit}."
114
111
  )
115
112
  unit = DefaultTimeUnit
116
113
 
117
114
  if cast_type == AxisType.space and unit is None:
118
- logger.warning(
115
+ ngio_logger.warning(
119
116
  f"Space axis {self.on_disk_name} has unit {unit}. "
120
117
  f"Casting to {DefaultSpaceUnit}."
121
118
  )
@@ -329,33 +329,35 @@ class ChannelsMeta(BaseModel):
329
329
  @classmethod
330
330
  def default_init(
331
331
  cls,
332
- labels: Collection[str] | int,
333
- wavelength_id: Collection[str] | None = None,
334
- colors: Collection[str | NgioColors] | None = None,
335
- start: Collection[int | float] | int | float | None = None,
336
- end: Collection[int | float] | int | float | None = None,
337
- active: Collection[bool] | None = None,
332
+ labels: Collection[str | None] | int,
333
+ wavelength_id: Collection[str | None] | None = None,
334
+ colors: Collection[str | NgioColors | None] | None = None,
335
+ start: Collection[int | float | None] | int | float | None = None,
336
+ end: Collection[int | float | None] | int | float | None = None,
337
+ active: Collection[bool | None] | None = None,
338
338
  data_type: Any = np.uint16,
339
339
  **omero_kwargs: dict,
340
340
  ) -> "ChannelsMeta":
341
341
  """Create a ChannelsMeta object with the default unit.
342
342
 
343
343
  Args:
344
- labels(Collection[str] | int): The list of channels names in the image.
345
- If an integer is provided, the channels will be named "channel_i".
346
- wavelength_id(Collection[str] | None): The wavelength ID of the channel.
347
- If None, the wavelength ID will be the same as the channel name.
348
- colors(Collection[str, NgioColors] | None): The list of colors for the
349
- channels. If None, the colors will be random.
350
- start(Collection[int | float] | int | float | None): The start value of the
351
- channel. If None, the start value will be the minimum value of the
352
- data type.
353
- end(Collection[int | float] | int | float | None): The end value of the
354
- channel. If None, the end value will be the maximum value of the
355
- data type.
344
+ labels(Collection[str | None] | int): The list of channels names
345
+ in the image. If an integer is provided, the channels will be
346
+ named "channel_i".
347
+ wavelength_id(Collection[str | None] | None): The wavelength ID of the
348
+ channel. If None, the wavelength ID will be the same as the
349
+ channel name.
350
+ colors(Collection[str | NgioColors | None] | None): The list of
351
+ colors for the channels. If None, the colors will be random.
352
+ start(Collection[int | float | None] | int | float | None): The start
353
+ value of the channel. If None, the start value will be the
354
+ minimum value of the data type.
355
+ end(Collection[int | float | None] | int | float | None): The end
356
+ value of the channel. If None, the end value will be the
357
+ maximum value of the data type.
356
358
  data_type(Any): The data type of the channel. Will be used to set the
357
359
  min and max values of the channel.
358
- active (Collection[bool] | None):active(bool): Whether the channel should
360
+ active (Collection[bool | None] | None): Whether the channel should
359
361
  be shown by default.
360
362
  omero_kwargs(dict): Extra fields to store in the omero attributes.
361
363
  """
@@ -366,25 +368,35 @@ class ChannelsMeta(BaseModel):
366
368
  labels = _check_unique(labels)
367
369
 
368
370
  _wavelength_id: Collection[str | None] = [None] * len(labels)
369
- if isinstance(wavelength_id, Collection):
371
+ if wavelength_id is None:
372
+ _wavelength_id: Collection[str | None] = [None] * len(labels)
373
+ else:
370
374
  _wavelength_id = _check_elements(wavelength_id, str)
371
375
  _wavelength_id = _check_unique(wavelength_id)
372
376
 
373
- _colors: Collection[str | NgioColors | None] = [None] * len(labels)
374
- if isinstance(colors, Collection):
377
+ if colors is None:
378
+ _colors = [NgioColors.semi_random_pick(label) for label in labels]
379
+ else:
375
380
  _colors = _check_elements(colors, str | NgioColors)
376
381
 
377
- _start: Collection[int | float | None] = [None] * len(labels)
378
- if isinstance(start, Collection):
382
+ if start is None:
383
+ _start = [None] * len(labels)
384
+ elif isinstance(start, int | float):
385
+ _start = [start] * len(labels)
386
+ else:
379
387
  _start = _check_elements(start, (int, float))
380
388
 
381
- _end: Collection[int | float | None] = [None] * len(labels)
382
- if isinstance(end, Collection):
389
+ if end is None:
390
+ _end = [None] * len(labels)
391
+ elif isinstance(end, int | float):
392
+ _end = [end] * len(labels)
393
+ else:
383
394
  _end = _check_elements(end, (int, float))
384
395
 
385
- _active: Collection[bool] = [True] * len(labels)
386
- if isinstance(active, Collection):
387
- _active = _check_elements(active, bool)
396
+ if active is None:
397
+ _active = [True] * len(labels)
398
+ else:
399
+ _active = _check_elements(active, (bool,))
388
400
 
389
401
  all_lengths = [
390
402
  len(labels),
ngio/tables/__init__.py CHANGED
@@ -1,11 +1,6 @@
1
1
  """Ngio Tables implementations."""
2
2
 
3
- from ngio.tables.backends import (
4
- ImplementedTableBackends,
5
- TableBackend,
6
- TableBackendProtocol,
7
- )
8
- from ngio.tables.tables_container import (
3
+ from ngio.tables._tables_container import (
9
4
  ConditionTable,
10
5
  FeatureTable,
11
6
  GenericRoiTable,
@@ -19,6 +14,11 @@ from ngio.tables.tables_container import (
19
14
  open_table_as,
20
15
  open_tables_container,
21
16
  )
17
+ from ngio.tables.backends import (
18
+ ImplementedTableBackends,
19
+ TableBackend,
20
+ TableBackendProtocol,
21
+ )
22
22
  from ngio.tables.v1._generic_table import GenericTable
23
23
 
24
24
  __all__ = [
@@ -126,13 +126,18 @@ class Table(Protocol):
126
126
 
127
127
 
128
128
  TypedTable = Literal[
129
+ "generic_table",
129
130
  "roi_table",
130
131
  "masking_roi_table",
131
132
  "feature_table",
132
- "generic_roi_table",
133
133
  "condition_table",
134
134
  ]
135
135
 
136
+ TypedRoiTable = Literal[
137
+ "roi_table",
138
+ "masking_roi_table",
139
+ ]
140
+
136
141
  TableType = TypeVar("TableType", bound=Table)
137
142
 
138
143
 
@@ -192,19 +197,34 @@ class ImplementedTables:
192
197
  table = table_cls.from_handler(handler=handler, backend=backend)
193
198
  return table
194
199
 
195
- def add_implementation(self, handler: type[Table], overwrite: bool = False):
200
+ def _add_implementation(
201
+ self, handler: type[Table], name: str, overwrite: bool = False
202
+ ) -> None:
203
+ """Register a new table handler."""
204
+ if name in self._implemented_tables and not overwrite:
205
+ raise NgioValueError(
206
+ f"Table handler for {name} already implemented. "
207
+ "Use overwrite=True to replace it."
208
+ )
209
+ self._implemented_tables[name] = handler
210
+
211
+ def add_implementation(
212
+ self,
213
+ handler: type[Table],
214
+ overwrite: bool = False,
215
+ aliases: list[str] | None = None,
216
+ ) -> None:
196
217
  """Register a new table handler."""
197
218
  meta = TableMeta(
198
219
  type=handler.table_type(),
199
220
  table_version=handler.version(),
200
221
  )
201
222
 
202
- if meta.unique_name() in self._implemented_tables and not overwrite:
203
- raise NgioValueError(
204
- f"Table handler for {meta.unique_name()} already implemented. "
205
- "Use overwrite=True to replace it."
206
- )
207
- self._implemented_tables[meta.unique_name()] = handler
223
+ self._add_implementation(handler, meta.unique_name(), overwrite)
224
+
225
+ if aliases is not None:
226
+ for alias in aliases:
227
+ self._add_implementation(handler, alias, overwrite)
208
228
 
209
229
 
210
230
  class TablesContainer:
@@ -240,14 +260,7 @@ class TablesContainer:
240
260
  handler = self._group_handler.derive_handler(path=name)
241
261
  return handler
242
262
 
243
- def list_roi_tables(self) -> list[str]:
244
- """List all ROI tables in the group."""
245
- _tables = []
246
- for _type in ["roi_table", "masking_roi_table"]:
247
- _tables.extend(self.list(_type))
248
- return _tables
249
-
250
- def list(self, filter_types: str | None = None) -> list[str]:
263
+ def list(self, filter_types: TypedTable | str | None = None) -> list[str]:
251
264
  """List all labels in the group."""
252
265
  tables = self._get_tables_list()
253
266
  if filter_types is None:
@@ -180,24 +180,46 @@ class ImplementedTableBackends:
180
180
  )
181
181
  return backend
182
182
 
183
- def add_backend(
183
+ def _add_backend(
184
184
  self,
185
- table_beckend: type[TableBackendProtocol],
185
+ table_backend: type[TableBackendProtocol],
186
+ name: str,
186
187
  overwrite: bool = False,
187
- ):
188
+ ) -> None:
188
189
  """Register a new handler."""
189
- backend_name = table_beckend.backend_name()
190
- if backend_name in self._implemented_backends and not overwrite:
190
+ if name in self._implemented_backends and not overwrite:
191
191
  raise NgioValueError(
192
- f"Table backend {backend_name} already implemented. "
192
+ f"Table backend {name} already implemented. "
193
193
  "Use the `overwrite=True` parameter to overwrite it."
194
194
  )
195
- self._implemented_backends[backend_name] = table_beckend
196
-
195
+ self._implemented_backends[name] = table_backend
197
196
 
198
- ImplementedTableBackends().add_backend(AnnDataBackend)
199
- ImplementedTableBackends().add_backend(JsonTableBackend)
200
- ImplementedTableBackends().add_backend(CsvTableBackend)
201
- ImplementedTableBackends().add_backend(ParquetTableBackend)
197
+ def add_backend(
198
+ self,
199
+ table_backend: type[TableBackendProtocol],
200
+ overwrite: bool = False,
201
+ aliases: list[str] | None = None,
202
+ ) -> None:
203
+ """Register a new handler."""
204
+ self._add_backend(
205
+ table_backend=table_backend,
206
+ name=table_backend.backend_name(),
207
+ overwrite=overwrite,
208
+ )
209
+ if aliases is not None:
210
+ for alias in aliases:
211
+ self._add_backend(
212
+ table_backend=table_backend, name=alias, overwrite=overwrite
213
+ )
214
+
215
+
216
+ ImplementedTableBackends().add_backend(AnnDataBackend, aliases=["anndata_v1"])
217
+ ImplementedTableBackends().add_backend(
218
+ JsonTableBackend, aliases=["experimental_json_v1"]
219
+ )
220
+ ImplementedTableBackends().add_backend(CsvTableBackend, aliases=["experimental_csv_v1"])
221
+ ImplementedTableBackends().add_backend(
222
+ ParquetTableBackend, aliases=["experimental_parquet_v1"]
223
+ )
202
224
 
203
225
  TableBackend = Literal["anndata", "json", "csv", "parquet"] | str | TableBackendProtocol
@@ -1,6 +1,6 @@
1
1
  """Implementation of a generic table class."""
2
2
 
3
- from ngio.tables.abstract_table import AbstractBaseTable
3
+ from ngio.tables._abstract_table import AbstractBaseTable
4
4
  from ngio.tables.backends import (
5
5
  BackendMeta,
6
6
  TableBackend,
@@ -8,7 +8,7 @@ from typing import Literal
8
8
 
9
9
  from pydantic import BaseModel, Field
10
10
 
11
- from ngio.tables.abstract_table import AbstractBaseTable
11
+ from ngio.tables._abstract_table import AbstractBaseTable
12
12
  from ngio.tables.backends import BackendMeta, TableBackend, TabularData
13
13
  from ngio.utils import NgioValueError
14
14
  from ngio.utils._zarr_utils import ZarrGroupHandler
@@ -26,7 +26,7 @@ class FeatureTableMeta(BackendMeta):
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" # Legacy field, kept for compatibility
29
+ instance_key: str = "label" # Legacy field, kept for compatibility
30
30
  # Backend metadata
31
31
  index_key: str | None = "label"
32
32
  index_type: Literal["int", "str"] | None = "int"
@@ -1,6 +1,6 @@
1
1
  """Implementation of a generic table class."""
2
2
 
3
- from ngio.tables.abstract_table import AbstractBaseTable
3
+ from ngio.tables._abstract_table import AbstractBaseTable
4
4
  from ngio.tables.backends import BackendMeta, TableBackend
5
5
  from ngio.utils import ZarrGroupHandler
6
6
 
@@ -13,7 +13,7 @@ import pandas as pd
13
13
  from pydantic import BaseModel
14
14
 
15
15
  from ngio.common import Roi
16
- from ngio.tables.abstract_table import (
16
+ from ngio.tables._abstract_table import (
17
17
  AbstractBaseTable,
18
18
  TabularData,
19
19
  )
@@ -37,6 +37,6 @@ def fractal_fsspec_store(
37
37
  raise NgioValueError(
38
38
  f"Store {url} can not be read. Possible problems are: \n"
39
39
  "- The url does not exist. \n"
40
- f"- The url is not a valid .zarr. \n"
40
+ "- The url is not a valid .zarr. \n"
41
41
  )
42
42
  return store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngio
3
- Version: 0.3.0a1
3
+ Version: 0.3.1
4
4
  Summary: Next Generation file format IO
5
5
  Project-URL: homepage, https://github.com/fractal-analytics-platform/ngio
6
6
  Project-URL: repository, https://github.com/fractal-analytics-platform/ngio
@@ -63,7 +63,7 @@ Requires-Dist: pytest-cov; extra == 'test'
63
63
  Requires-Dist: scikit-image; extra == 'test'
64
64
  Description-Content-Type: text/markdown
65
65
 
66
- # NGIO - Next Generation file format IO
66
+ # Ngio - Next Generation file format IO
67
67
 
68
68
  [![License](https://img.shields.io/pypi/l/ngio.svg?color=green)](https://github.com/lorenzocerrone/ngio/raw/main/LICENSE)
69
69
  [![PyPI](https://img.shields.io/pypi/v/ngio.svg?color=green)](https://pypi.org/project/ngio)
@@ -71,36 +71,69 @@ Description-Content-Type: text/markdown
71
71
  [![CI](https://github.com/fractal-analytics-platform/ngio/actions/workflows/ci.yml/badge.svg)](https://github.com/fractal-analytics-platform/ngio/actions/workflows/ci.yml)
72
72
  [![codecov](https://codecov.io/gh/fractal-analytics-platform/ngio/graph/badge.svg?token=FkmF26FZki)](https://codecov.io/gh/fractal-analytics-platform/ngio)
73
73
 
74
- NGIO is a Python library to streamline OME-Zarr image analysis workflows.
75
-
76
- **Main Goals:**
77
-
78
- - Abstract object base API for handling OME-Zarr files
79
- - Powerful iterators for processing data using common access patterns
80
- - Tight integration with [Fractal's Table Fractal](https://fractal-analytics-platform.github.io/fractal-tasks-core/tables/)
81
- - Validation of OME-Zarr files
82
-
83
- To get started, check out the [Getting Started](https://fractal-analytics-platform.github.io/ngio/getting-started/) guide. Or checkout our [Documentation](https://fractal-analytics-platform.github.io/ngio/)
84
-
85
- ## 🚧 Ngio is Under active Development 🚧
86
-
87
- ### Roadmap
88
-
89
- | Feature | Status | ETA | Description |
90
- |---------|--------|-----|-------------|
91
- | Metadata Handling | | | Read, Write, Validate OME-Zarr Metadata (0.4 supported, 0.5 ready) |
92
- | OME-Zarr Validation | ✅ | | Validate OME-Zarr files for compliance with the OME-Zarr Specification + Compliance between Metadata and Data |
93
- | Base Image Handling | ✅ | | Load data from OME-Zarr files, retrieve basic metadata, and write data |
94
- | ROI Handling | | | Common ROI models |
95
- | Label Handling | ✅ | Mid-September | Based on Image Handling |
96
- | Table Validation | ✅ | Mid-September | Validate Table fractal V1 + Compliance between Metadata and Data |
97
- | Table Handling | ✅ | Mid-September | Read, Write ROI, Features, and Masked Tables |
98
- | Basic Iterators | Ongoing | End-September | Read and Write Iterators for common access patterns |
99
- | Base Documentation | ✅ | End-September | API Documentation and Examples |
100
- | Beta Ready Testing | ✅ | End-September | Beta Testing; Library is ready for testing, but the API is not stable |
101
- | Streaming from Fractal | Ongoing | December | Ngio can stream OME-Zarr from fractal |
102
- | Mask Iterators | Ongoing | Early 2025 | Iterators over Masked Tables |
103
- | Advanced Iterators | Not started | mid-2025 | Iterators for advanced access patterns |
104
- | Parallel Iterators | Not started | mid-2025 | Concurrent Iterators for parallel read and write |
105
- | Full Documentation | Not started | 2025 | Complete Documentation |
106
- | Release 1.0 (Commitment to API) | Not started | 2025 | API is stable; breaking changes will be avoided |
74
+ ngio is a Python library designed to simplify bioimage analysis workflows, offering an intuitive interface for working with OME-Zarr files.
75
+
76
+ ## What is Ngio?
77
+
78
+ Ngio is built for the [OME-Zarr](https://ngff.openmicroscopy.org/) file format, a modern, cloud-optimized format for biological imaging data. OME-Zarr stores large, multi-dimensional microscopy images and metadata in an efficient and scalable way.
79
+
80
+ Ngio's mission is to streamline working with OME-Zarr files by providing a simple, object-based API for opening, exploring, and manipulating OME-Zarr images and high-content screening (HCS) plates. It also offers comprehensive support for labels, tables and regions of interest (ROIs), making it easy to extract and analyze specific regions in your data.
81
+
82
+ ## Key Features
83
+
84
+ ### 📊 Simple Object-Based API
85
+
86
+ - Easily open, explore, and manipulate OME-Zarr images and HCS plates
87
+ - Create and derive new images and labels with minimal boilerplate code
88
+
89
+ ### 🔍 Rich Tables and Regions of Interest (ROI) Support
90
+
91
+ - Extract and analyze specific regions of interest
92
+ - Tight integration with [Tabular Data](https://fractal-analytics-platform.github.io/ngio/stable/table_specs/overview/)
93
+
94
+ ### 🔄 Scalable Data Processing (Coming Soon)
95
+
96
+ - Powerful iterators for processing data at scale
97
+ - Efficient memory management for large datasets
98
+
99
+ ## Installation
100
+
101
+ You can install ngio via pip:
102
+
103
+ ```bash
104
+ pip install ngio
105
+ ```
106
+
107
+ To get started check out the [Quickstart Guide](https://fractal-analytics-platform.github.io/ngio/stable/getting_started/0_quickstart/).
108
+
109
+ ## Supported OME-Zarr versions
110
+
111
+ Currently, ngio only supports OME-Zarr v0.4. Support for version 0.5 and higher is planned for future releases.
112
+
113
+ ## Development Status
114
+
115
+ !!! warning
116
+ Ngio is under active development and is not yet stable. The API is subject to change, and bugs and breaking changes are expected.
117
+ We follow [Semantic Versioning](https://semver.org/). Which means for 0.x releases potentially breaking changes can be introduced in minor releases.
118
+
119
+ ### Available Features
120
+
121
+ - ✅ OME-Zarr metadata handling and validation
122
+ - ✅ Image and label access across pyramid levels
123
+ - ✅ ROI and table support
124
+ - ✅ Streaming from remote sources
125
+ - ✅ Documentation and examples
126
+
127
+ ### Upcoming Features
128
+
129
+ - Advanced image processing iterators
130
+ - Parallel processing capabilities
131
+ - Support for OME-Zarr v0.5 and Zarr v3
132
+
133
+ ## Contributors
134
+
135
+ Ngio is developed at the [BioVisionCenter](https://www.biovisioncenter.uzh.ch/en.html), University of Zurich, by [@lorenzocerrone](https://github.com/lorenzocerrone) and [@jluethi](https://github.com/jluethi).
136
+
137
+ ## License
138
+
139
+ Ngio is released under the BSD-3-Clause License. See [LICENSE](https://github.com/fractal-analytics-platform/ngio/blob/main/LICENSE) for details.
@@ -1,6 +1,6 @@
1
1
  ngio/__init__.py,sha256=zce-RIfRhkiFyfKwO6s7A1-9ZCD3n6RuVuW3GeRj_VA,1309
2
2
  ngio/common/__init__.py,sha256=BttXCAV2ks6_oXVDfapk1Lvlxp4J0ffX7-FXR3LL1BM,1834
3
- ngio/common/_array_pipe.py,sha256=we3gZLhgUsiPQwPQqg_XVkyG_9EpQ2xoe0L_nOALDho,7828
3
+ ngio/common/_array_pipe.py,sha256=mvBsOtNSow9S6bSPMJ0288gCqQFYffGnaTTLyuB2XHw,8641
4
4
  ngio/common/_axes_transforms.py,sha256=kWU0M5erNmgWBXdu5LNv-tLW3jqkT00MMYX7cz-kyHs,2035
5
5
  ngio/common/_common_types.py,sha256=OkAYNSNjZkixL1MI-HPBVuXamheFBr862uJ4PvTxmhk,129
6
6
  ngio/common/_dimensions.py,sha256=UV2XulWaROb3Y2f4fv27ZkTIu-MoS53U26aDkrv-_lk,3900
@@ -8,22 +8,22 @@ ngio/common/_masking_roi.py,sha256=-o6meGP17iTXEbkO9aGh1VX2drkc2laIcRJvCy_pRRM,4
8
8
  ngio/common/_pyramid.py,sha256=SJzPauuduuqcm9B7nFCJhMTzIg6Knjsnp4CY4lN61Is,7411
9
9
  ngio/common/_roi.py,sha256=dq1iVT8-G_zWuxcYWJeHfviBSbPgsyKUcDL3Vg6jx6I,5122
10
10
  ngio/common/_slicer.py,sha256=AKpwXRncOmF9nhjKYma0C_41WqAgSv860beKGx-aw-0,3075
11
- ngio/common/_table_ops.py,sha256=oTjCcecBOG_GJoLgJLgag6yl_nznThOKBKANQJow0h8,15493
11
+ ngio/common/_table_ops.py,sha256=ToNR7F053l1dubVv-gvBD-523T10HnE2UzqeU2BuNy8,15494
12
12
  ngio/common/_zoom.py,sha256=KsURa5VuixmpbAAY5-6obmuQV8vfiHKZqBxZDXvchpM,5473
13
- ngio/hcs/__init__.py,sha256=5oAYT_454WGhms97kxo8gS4_rKHtFf_x-9uu8M_VeVM,356
14
- ngio/hcs/plate.py,sha256=Y_d-ZuV9FmYsSHqwZfcnm_Y024jfdiMd7WlaeNJy73k,43696
15
- ngio/images/__init__.py,sha256=DYbXAdBgPxyjBRdJrWvU0UnBRI0gUMmx9KaJ-Bucvz4,533
16
- ngio/images/abstract_image.py,sha256=8PNQPZjiDz-pcTFXSJAVw7nUr4yL_iRwqDEUTKkAnp0,10266
17
- ngio/images/create.py,sha256=XYn30m_2OSZeHHASYHc3eK9u_gZIYy9wo6mGdRGaq5c,9473
18
- ngio/images/image.py,sha256=mKLIR2DGQUWtQbf3my2fh0bEPkbbsabUoge_XJPhfWE,17824
19
- ngio/images/label.py,sha256=qgbBHFPGYpUR2fHf1OiXZh4sn0FgCeeWwH1F4SrOM1c,10460
20
- ngio/images/masked_image.py,sha256=IBo8x2jHyXBXn7ORo8fSiwBPjV_1JOTb_vatjKNxbJ0,8531
21
- ngio/images/ome_zarr_container.py,sha256=jOodimQzAnaLUSYG1OnBsWqtHeL8_V4wkg_4RSXbwcM,30003
13
+ ngio/hcs/__init__.py,sha256=G8j9vD-liLeB_UeGtKYIgshWvJnUA6ks9GwjvWBLdHs,357
14
+ ngio/hcs/_plate.py,sha256=Z8M3slG5t16MYvPwvAzj-e9O4yAswWZp7_EDBlAxiHc,44225
15
+ ngio/images/__init__.py,sha256=PlYvbHOMvZLDgn_PeGrytOEU3e_-AO8GWpRjEqoX_Gw,536
16
+ ngio/images/_abstract_image.py,sha256=8PNQPZjiDz-pcTFXSJAVw7nUr4yL_iRwqDEUTKkAnp0,10266
17
+ ngio/images/_create.py,sha256=XYn30m_2OSZeHHASYHc3eK9u_gZIYy9wo6mGdRGaq5c,9473
18
+ ngio/images/_image.py,sha256=B9MTk3Cei-FBR4jbhSujTSNcKM_ySape28yXR_JlY0A,17980
19
+ ngio/images/_label.py,sha256=Q1vPrXDcjJ7Gdd0wDz6NCVYQLNe1Ae6YDI4iK0oq31s,10557
20
+ ngio/images/_masked_image.py,sha256=sd6aQetNVwtDkwUvKX-lssQyHzt5m-CYZL8ZFkwDSn8,8533
21
+ ngio/images/_ome_zarr_container.py,sha256=hRx_8CPtFpxQUcprTT4_k5L5pjMUJ6t4wJaYr1tyljw,31181
22
22
  ngio/ome_zarr_meta/__init__.py,sha256=oZ8PEsWM7U0KwzpsnvVfX9k4UfuTz5sZ8B6B9eY5hyY,1193
23
23
  ngio/ome_zarr_meta/_meta_handlers.py,sha256=ctknNDT8jxwyvxQf9on5gW31H1tRRsnneO38GT2UXoE,25880
24
24
  ngio/ome_zarr_meta/ngio_specs/__init__.py,sha256=05NQukZG0nNvjzf8AKWGu7PhjhQcImGSAOK3D3Bg-Js,1786
25
- ngio/ome_zarr_meta/ngio_specs/_axes.py,sha256=Kqe9T7LWa_9o3UWS5uzALyyNluIhXxWhDGxWY4-GIo8,16707
26
- ngio/ome_zarr_meta/ngio_specs/_channels.py,sha256=2L-HM9K1Xu4qRI2MiXPqgCuHdCBRydEW1StThcqEuvY,15120
25
+ ngio/ome_zarr_meta/ngio_specs/_axes.py,sha256=tHtx6NfBgDcCgDk9CosjIjw1KZJ2qi0i_eoLgrdiEWw,16681
26
+ ngio/ome_zarr_meta/ngio_specs/_channels.py,sha256=Jwys1yYC8q6_gIaJ52KcKcTP7hzqVjBE-VlVQvJurCs,15394
27
27
  ngio/ome_zarr_meta/ngio_specs/_dataset.py,sha256=hY8ogPPxvCgVg6k02t3zUr24lasYrvnxBd1iPEigdG4,5892
28
28
  ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py,sha256=uh345KQmEQtslIyMmLK9sB-NbjPYxi0Y9FuYIFhd3Rc,17465
29
29
  ngio/ome_zarr_meta/ngio_specs/_ngio_image.py,sha256=8E38Mgw-l0Ff1nkmCJIzo64G_paAVhM8xktUS_V5egY,17960
@@ -31,9 +31,9 @@ ngio/ome_zarr_meta/ngio_specs/_pixel_size.py,sha256=5TT8250XdCKUnk3OwZeyXIMNFKOg
31
31
  ngio/ome_zarr_meta/v04/__init__.py,sha256=dJRzzxyYc81kf-0Hip_bqvbdManaM8XTdQX2meWyCSs,583
32
32
  ngio/ome_zarr_meta/v04/_custom_models.py,sha256=5GxiDERvLuvq4QvApcA6EiKLS6hLFX1R0R_9rSaa85A,530
33
33
  ngio/ome_zarr_meta/v04/_v04_spec_utils.py,sha256=05tEr2eEP_XVIfBMOAWLT7lzJV4KS5eYrpK8l94tn3w,15876
34
- ngio/tables/__init__.py,sha256=np-XWjUY_HkwMfSy_bIRxh5t5SFZJ9yHEtvtbuaaSgg,824
35
- ngio/tables/abstract_table.py,sha256=naAeDsPTVjDUOnAxj_57UWXApg_nyWCsWdZ0f7bm740,8169
36
- ngio/tables/tables_container.py,sha256=c7YnzLy2aaDc0jCH8ih8FTAKpAX8dIAu743nF7EjNTY,11871
34
+ ngio/tables/__init__.py,sha256=rJGcyQUlHQb_ZbeMM9ICD8_mhTE2X9H5nKp0J-z9tMM,825
35
+ ngio/tables/_abstract_table.py,sha256=naAeDsPTVjDUOnAxj_57UWXApg_nyWCsWdZ0f7bm740,8169
36
+ ngio/tables/_tables_container.py,sha256=a2NNExiP1HqFVJ6HPLn0nEkYHLdf2LONVz5OxoH7OkY,12118
37
37
  ngio/tables/backends/__init__.py,sha256=tx97ZkK5kF_sAGU2kf_ZI9JxbOXn8GVjE0rUUq9h-QM,1525
38
38
  ngio/tables/backends/_abstract_backend.py,sha256=jtai3AqcLNZyxYyK0rernbMtcwxWhWAahCS0fPlMNls,7454
39
39
  ngio/tables/backends/_anndata.py,sha256=8RX2NO15CLxys3p6gw54Nd-_0WATU4WBlNndX06wvzI,2587
@@ -42,20 +42,20 @@ ngio/tables/backends/_csv.py,sha256=Ev61D-AUKo4LIhXRmWPJgYbHI7eQdxiajQR574DevEM,
42
42
  ngio/tables/backends/_json.py,sha256=1ZsEuXDJm1rOZV_KjFm8CB0qhv7L1W7L2EGWPf4q_p0,3137
43
43
  ngio/tables/backends/_non_zarr_backends.py,sha256=SvPPhT6n5TrKUOyV1mNcdHQK49huZ5lwR8EVe9MdydM,7254
44
44
  ngio/tables/backends/_parquet.py,sha256=ic-p86h8lce8q9luBJGRzy6vxlWyJvA0-2l5cUD6OqY,1398
45
- ngio/tables/backends/_table_backends.py,sha256=9bAwiB93gR8E7NdpH9WMMQhjn34Iz6oW9i_H4upYbW4,6567
45
+ ngio/tables/backends/_table_backends.py,sha256=E4b1p_ZqRmEf3JK_Wp05r2J-q-PZQU_B1qFluBrjU9Q,7232
46
46
  ngio/tables/backends/_utils.py,sha256=tJBSWN6OhO_1ybxl4vT2l3ImB028Fb6h0vaitPRcr8A,19668
47
47
  ngio/tables/v1/__init__.py,sha256=Wr1_9RZFpaN8FYMTnxT9Yjkw4AS7y9FMWailmB_uj5g,617
48
- ngio/tables/v1/_condition_table.py,sha256=LwtmygyhsSgAUoI_XuzF4lsHhTO5SIJqytxNAxqRCFU,1780
49
- ngio/tables/v1/_feature_table.py,sha256=6QiaHYTxBGwkIkBndA0pIgTpLSnlkJ6b_Nqs_H5g3GI,3819
50
- ngio/tables/v1/_generic_table.py,sha256=jFpW1vCDurN-TFQtQEyz1Rqnax7sVQoJzdPPBAVopFE,1239
51
- ngio/tables/v1/_roi_table.py,sha256=VQDLJnXGniups4bhZxn9ga9LRQnEI5PJzWDrQNsjmDM,13455
48
+ ngio/tables/v1/_condition_table.py,sha256=IMU3sds8wrKGqU-C20HbpFCVGZX1L_V7Sh8f7CHB_x0,1781
49
+ ngio/tables/v1/_feature_table.py,sha256=n9uMHwoBh-_dlOhUXCFbmAjXFVXncNCR3SjE2qzXI68,3821
50
+ ngio/tables/v1/_generic_table.py,sha256=1ktJHeuv7U1g5Z8PFUuTkCjOzcYMQd8xegKHKUedJB8,1240
51
+ ngio/tables/v1/_roi_table.py,sha256=Q1dBQqPvxqBOqatGzYTAbxmgEnEkBawpSbCL38YBnE0,13456
52
52
  ngio/utils/__init__.py,sha256=r3nuLWgp6-cQlS4ODjYSBrfgdTLkCOVke9jKbn1NpkA,1129
53
53
  ngio/utils/_datasets.py,sha256=EdYJHIifpRou4f43dIuiKsdxe4K6FaeS4f1_e_EYrcI,1727
54
54
  ngio/utils/_errors.py,sha256=pKQ12LUjQLYE1nUawemA5h7HsgznjaSvV1n2PQU33N0,759
55
- ngio/utils/_fractal_fsspec_store.py,sha256=0PMqPRCw7CYdLPxsNtp_vMLXfiQVwqs5EWrn2YVEuvA,1549
55
+ ngio/utils/_fractal_fsspec_store.py,sha256=RdcCFOgHexRKX9zZvJV5RI-5OPc7VOPS6q_IeRxm24I,1548
56
56
  ngio/utils/_logger.py,sha256=HIuqD_2ShfFGDswBddcouStbKfL0Vz_ah8cAIFGhbS8,888
57
57
  ngio/utils/_zarr_utils.py,sha256=qOI-HL2HsfFLCj_yxsTR-aq4oHpSqS9KR13aEIvhGDY,13593
58
- ngio-0.3.0a1.dist-info/METADATA,sha256=7yRX4zM74DQkNKw-w5OijTUM7afR7OSks8zLd-1R1ro,5304
59
- ngio-0.3.0a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
60
- ngio-0.3.0a1.dist-info/licenses/LICENSE,sha256=UgN_a1QCeNh9rZWfz-wORQFxE3elQzLWPQaoK6N6fxQ,1502
61
- ngio-0.3.0a1.dist-info/RECORD,,
58
+ ngio-0.3.1.dist-info/METADATA,sha256=6KnWDNEe6TWTYu4kKvT9uJR6D6uikMu0W6VOgXoNXcw,5868
59
+ ngio-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
60
+ ngio-0.3.1.dist-info/licenses/LICENSE,sha256=UgN_a1QCeNh9rZWfz-wORQFxE3elQzLWPQaoK6N6fxQ,1502
61
+ ngio-0.3.1.dist-info/RECORD,,
File without changes
File without changes
File without changes
File without changes