ngio 0.5.0b6__py3-none-any.whl → 0.5.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,6 +1,6 @@
1
1
  """Utility functions for working with OME-Zarr images."""
2
2
 
3
- import warnings
3
+ import logging
4
4
  from collections.abc import Mapping, Sequence
5
5
  from typing import Any, Literal, TypeVar
6
6
 
@@ -22,6 +22,7 @@ from ngio.ome_zarr_meta.ngio_specs import (
22
22
  NgffVersions,
23
23
  SpaceUnits,
24
24
  TimeUnits,
25
+ build_axes_handler,
25
26
  build_canonical_axes_handler,
26
27
  canonical_axes_order,
27
28
  canonical_label_axes_order,
@@ -29,37 +30,9 @@ from ngio.ome_zarr_meta.ngio_specs import (
29
30
  from ngio.ome_zarr_meta.ngio_specs._axes import AxesSetup
30
31
  from ngio.utils import NgioValueError, StoreOrGroup, ZarrGroupHandler
31
32
 
32
- _image_or_label_meta = TypeVar("_image_or_label_meta", NgioImageMeta, NgioLabelMeta)
33
-
33
+ logger = logging.getLogger(f"ngio:{__name__}")
34
34
 
35
- def _build_axes_handler(
36
- *,
37
- shape: tuple[int, ...],
38
- axes_names: Sequence[str] | None,
39
- default_channel_order: tuple[str, ...],
40
- space_units: SpaceUnits | str | None = DefaultSpaceUnit,
41
- time_units: TimeUnits | str | None = DefaultTimeUnit,
42
- axes_setup: AxesSetup | None = None,
43
- allow_non_canonical_axes: bool = False,
44
- strict_canonical_order: bool = False,
45
- ) -> AxesHandler:
46
- """Compute axes names for given shape."""
47
- if axes_names is None:
48
- axes_names = default_channel_order[-len(shape) :]
49
- # Validate length
50
- if len(axes_names) != len(shape):
51
- raise NgioValueError(
52
- f"Number of axes names {axes_names} does not match the number of "
53
- f"dimensions {shape}."
54
- )
55
- return build_canonical_axes_handler(
56
- axes_names=axes_names,
57
- space_units=space_units,
58
- time_units=time_units,
59
- axes_setup=axes_setup,
60
- allow_non_canonical_axes=allow_non_canonical_axes,
61
- strict_canonical_order=strict_canonical_order,
62
- )
35
+ _image_or_label_meta = TypeVar("_image_or_label_meta", NgioImageMeta, NgioLabelMeta)
63
36
 
64
37
 
65
38
  def _align_to_axes(
@@ -85,9 +58,9 @@ def _check_deprecated_scaling_factors(
85
58
  shape: tuple[int, ...],
86
59
  ) -> Sequence[float] | Literal["auto"]:
87
60
  if yx_scaling_factor is not None or z_scaling_factor is not None:
88
- warnings.warn(
61
+ logger.warning(
89
62
  "The 'yx_scaling_factor' and 'z_scaling_factor' arguments are deprecated "
90
- "and will be removed in future versions. Please use the 'scaling_factors' "
63
+ "and will be removed in ngio=0.6. Please use the 'scaling_factors' "
91
64
  "argument instead.",
92
65
  DeprecationWarning,
93
66
  stacklevel=2,
@@ -149,7 +122,7 @@ def _compute_scaling_factors(
149
122
  return tuple(scaling_factors)
150
123
 
151
124
 
152
- def _compute_base_scale(
125
+ def compute_base_scale(
153
126
  *,
154
127
  pixelsize: float | tuple[float, float],
155
128
  z_spacing: float,
@@ -231,6 +204,38 @@ def _add_channels_meta(
231
204
  return meta
232
205
 
233
206
 
207
+ def _build_axes_handler(
208
+ *,
209
+ shape: tuple[int, ...],
210
+ meta_type: type[_image_or_label_meta],
211
+ axes_names: Sequence[str] | None = None,
212
+ axes_setup: AxesSetup | None = None,
213
+ space_unit: SpaceUnits | str | None = None,
214
+ time_unit: TimeUnits | str | None = None,
215
+ ) -> AxesHandler:
216
+ """Build axes handler for given shape and axes names."""
217
+ if meta_type is NgioImageMeta:
218
+ canonical_axes_order_ = canonical_axes_order()
219
+ else:
220
+ canonical_axes_order_ = canonical_label_axes_order()
221
+ if axes_names is None:
222
+ axes_names = canonical_axes_order_[-len(shape) :]
223
+
224
+ if axes_setup is None:
225
+ return build_canonical_axes_handler(
226
+ axes_names=axes_names,
227
+ canonical_channel_order=canonical_axes_order_,
228
+ space_unit=space_unit,
229
+ time_unit=time_unit,
230
+ )
231
+ return build_axes_handler(
232
+ axes_names=axes_names,
233
+ axes_setup=axes_setup,
234
+ space_unit=space_unit,
235
+ time_unit=time_unit,
236
+ )
237
+
238
+
234
239
  def init_image_like(
235
240
  *,
236
241
  # Where to create the image
@@ -243,6 +248,7 @@ def init_image_like(
243
248
  time_spacing: float = 1.0,
244
249
  scaling_factors: Sequence[float] | Literal["auto"] = "auto",
245
250
  levels: int | list[str] = 5,
251
+ translation: Sequence[float] | None = None,
246
252
  space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
247
253
  time_unit: TimeUnits | str | None = DefaultTimeUnit,
248
254
  axes_names: Sequence[str] | None = None,
@@ -258,32 +264,28 @@ def init_image_like(
258
264
  extra_array_kwargs: Mapping[str, Any] | None = None,
259
265
  # internal axes configuration for advanced use cases
260
266
  axes_setup: AxesSetup | None = None,
261
- allow_non_canonical_axes: bool = False,
262
- strict_canonical_order: bool = False,
263
267
  # Whether to overwrite existing image
264
268
  overwrite: bool = False,
265
269
  # Deprecated arguments
266
270
  yx_scaling_factor: float | tuple[float, float] | None = None,
267
271
  z_scaling_factor: float | None = None,
268
- ) -> ZarrGroupHandler:
272
+ ) -> tuple[ZarrGroupHandler, AxesSetup]:
269
273
  """Create an empty OME-Zarr image with the given shape and metadata."""
270
274
  shape = tuple(shape)
271
- if meta_type is NgioImageMeta:
272
- default_axes_order = canonical_axes_order()
273
- else:
274
- default_axes_order = canonical_label_axes_order()
275
-
276
275
  axes_handler = _build_axes_handler(
277
276
  shape=shape,
277
+ meta_type=meta_type,
278
278
  axes_names=axes_names,
279
- default_channel_order=default_axes_order,
280
- space_units=space_unit,
281
- time_units=time_unit,
282
279
  axes_setup=axes_setup,
283
- allow_non_canonical_axes=allow_non_canonical_axes,
284
- strict_canonical_order=strict_canonical_order,
280
+ space_unit=space_unit,
281
+ time_unit=time_unit,
285
282
  )
286
- base_scale = _compute_base_scale(
283
+ if len(shape) != len(axes_handler.axes_names):
284
+ raise NgioValueError(
285
+ f"Mismatch between shape {shape} "
286
+ f"and number of axes {len(axes_handler.axes_names)}."
287
+ )
288
+ base_scale = compute_base_scale(
287
289
  pixelsize=pixelsize,
288
290
  z_spacing=z_spacing,
289
291
  time_spacing=time_spacing,
@@ -306,6 +308,7 @@ def init_image_like(
306
308
  scaling_factors=scaling_factors,
307
309
  base_shape=shape,
308
310
  base_scale=base_scale,
311
+ base_translation=translation,
309
312
  axes=axes_handler.axes_names,
310
313
  chunks=chunks,
311
314
  data_type=dtype,
@@ -319,18 +322,19 @@ def init_image_like(
319
322
  levels=[p.path for p in pyramid_builder.levels],
320
323
  axes_handler=axes_handler,
321
324
  scales=[p.scale for p in pyramid_builder.levels],
322
- translations=[None for _ in pyramid_builder.levels],
325
+ translations=[p.translation for p in pyramid_builder.levels],
323
326
  name=name,
324
327
  version=ngff_version,
325
328
  )
326
329
  meta = _add_channels_meta(meta=meta, channels_meta=channels_meta)
327
330
  # Keep this creation at the end to avoid partial creations on errors
328
- return _create_image_like_group(
331
+ image_handler = _create_image_like_group(
329
332
  store=store,
330
333
  pyramid_builder=pyramid_builder,
331
334
  meta=meta,
332
335
  overwrite=overwrite,
333
336
  )
337
+ return image_handler, axes_handler.axes_setup
334
338
 
335
339
 
336
340
  def init_image_like_from_shapes(
@@ -340,10 +344,9 @@ def init_image_like_from_shapes(
340
344
  # Ngff image parameters
341
345
  meta_type: type[_image_or_label_meta],
342
346
  shapes: Sequence[tuple[int, ...]],
343
- pixelsize: float | tuple[float, float],
344
- z_spacing: float = 1.0,
345
- time_spacing: float = 1.0,
347
+ base_scale: tuple[float, ...] | list[tuple[float, ...]],
346
348
  levels: list[str] | None = None,
349
+ translation: Sequence[float] | None = None,
347
350
  space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
348
351
  time_unit: TimeUnits | str | None = DefaultTimeUnit,
349
352
  axes_names: Sequence[str] | None = None,
@@ -359,34 +362,24 @@ def init_image_like_from_shapes(
359
362
  extra_array_kwargs: Mapping[str, Any] | None = None,
360
363
  # internal axes configuration for advanced use cases
361
364
  axes_setup: AxesSetup | None = None,
362
- allow_non_canonical_axes: bool = False,
363
- strict_canonical_order: bool = False,
364
365
  # Whether to overwrite existing image
365
366
  overwrite: bool = False,
366
- ) -> ZarrGroupHandler:
367
+ ) -> tuple[ZarrGroupHandler, AxesSetup]:
367
368
  """Create an empty OME-Zarr image with the given shape and metadata."""
368
369
  base_shape = shapes[0]
369
- if meta_type is NgioImageMeta:
370
- default_axes_order = canonical_axes_order()
371
- else:
372
- default_axes_order = canonical_label_axes_order()
373
-
374
370
  axes_handler = _build_axes_handler(
375
371
  shape=base_shape,
372
+ meta_type=meta_type,
376
373
  axes_names=axes_names,
377
- default_channel_order=default_axes_order,
378
- space_units=space_unit,
379
- time_units=time_unit,
380
374
  axes_setup=axes_setup,
381
- allow_non_canonical_axes=allow_non_canonical_axes,
382
- strict_canonical_order=strict_canonical_order,
383
- )
384
- base_scale = _compute_base_scale(
385
- pixelsize=pixelsize,
386
- z_spacing=z_spacing,
387
- time_spacing=time_spacing,
388
- axes_handler=axes_handler,
375
+ space_unit=space_unit,
376
+ time_unit=time_unit,
389
377
  )
378
+ if len(base_shape) != len(axes_handler.axes_names):
379
+ raise NgioValueError(
380
+ f"Mismatch between shape {base_shape} "
381
+ f"and number of axes {len(axes_handler.axes_names)}."
382
+ )
390
383
  if levels is None:
391
384
  levels_paths = tuple(str(i) for i in range(len(shapes)))
392
385
  else:
@@ -395,6 +388,7 @@ def init_image_like_from_shapes(
395
388
  pyramid_builder = ImagePyramidBuilder.from_shapes(
396
389
  shapes=shapes,
397
390
  base_scale=base_scale,
391
+ base_translation=translation,
398
392
  levels_paths=levels_paths,
399
393
  axes=axes_handler.axes_names,
400
394
  chunks=chunks,
@@ -409,15 +403,16 @@ def init_image_like_from_shapes(
409
403
  levels=[p.path for p in pyramid_builder.levels],
410
404
  axes_handler=axes_handler,
411
405
  scales=[p.scale for p in pyramid_builder.levels],
412
- translations=[None for _ in pyramid_builder.levels],
406
+ translations=[p.translation for p in pyramid_builder.levels],
413
407
  name=name,
414
408
  version=ngff_version,
415
409
  )
416
410
  meta = _add_channels_meta(meta=meta, channels_meta=channels_meta)
417
411
  # Keep this creation at the end to avoid partial creations on errors
418
- return _create_image_like_group(
412
+ image_handler = _create_image_like_group(
419
413
  store=store,
420
414
  pyramid_builder=pyramid_builder,
421
415
  meta=meta,
422
416
  overwrite=overwrite,
423
417
  )
418
+ return image_handler, axes_handler.axes_setup