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,4 +1,4 @@
1
- import warnings
1
+ import logging
2
2
  from collections.abc import Sequence
3
3
  from enum import Enum
4
4
 
@@ -7,6 +7,8 @@ import numpy as np
7
7
 
8
8
  from ngio.utils import NgioValueError
9
9
 
10
+ logger = logging.getLogger(f"ngio:{__name__}")
11
+
10
12
 
11
13
  class Action(str, Enum):
12
14
  NONE = "none"
@@ -29,10 +31,9 @@ def _compute_pad_widths(
29
31
  pad_def.append((before, after))
30
32
  else:
31
33
  pad_def.append((0, 0))
32
- warnings.warn(
34
+ logger.warning(
33
35
  f"Images have a different shape ({array_shape} vs {target_shape}). "
34
- f"Resolving by padding: {pad_def}",
35
- stacklevel=2,
36
+ f"Resolving by padding: {pad_def}"
36
37
  )
37
38
  return tuple(pad_def)
38
39
 
@@ -76,10 +77,9 @@ def _compute_trim_slices(
76
77
  else:
77
78
  slices.append(slice(0, s))
78
79
 
79
- warnings.warn(
80
+ logger.warning(
80
81
  f"Images have a different shape ({array_shape} vs {target_shape}). "
81
- f"Resolving by trimming: {slices}",
82
- stacklevel=2,
82
+ f"Resolving by trimming: {slices}"
83
83
  )
84
84
  return tuple(slices)
85
85
 
@@ -118,10 +118,9 @@ def _compute_rescaling_shape(
118
118
  rescaling_shape.append(s)
119
119
  factor.append(1.0)
120
120
 
121
- warnings.warn(
121
+ logger.warning(
122
122
  f"Images have a different shape ({array_shape} vs {target_shape}). "
123
- f"Resolving by scaling with factors {factor}.",
124
- stacklevel=2,
123
+ f"Resolving by scaling with factors {factor}."
125
124
  )
126
125
  return tuple(rescaling_shape)
127
126
 
@@ -266,14 +265,11 @@ def numpy_match_shape(
266
265
  reference_axes (Sequence[str]): The axes names of the reference shape.
267
266
  tolerance (int): The maximum number of pixels by which dimensions
268
267
  can differ when matching shapes.
269
- allow_broadcast (bool): If True, allow broadcasting new dimensions to
270
- match the reference shape. If False, single-dimension axes will
271
- be left as is.
272
268
  pad_mode (str): The mode to use for padding. See numpy.pad for options.
273
269
  pad_values (int | float): The constant value to use for padding if
274
270
  pad_mode is 'constant'.
275
271
  allow_rescaling (bool): If True, when the array differs more than the
276
- tolerance, it will be rescalingd to the reference shape. If False,
272
+ tolerance, it will be rescaled to the reference shape. If False,
277
273
  an error will be raised.
278
274
  """
279
275
  _check_axes(
@@ -1,7 +1,7 @@
1
+ import logging
1
2
  import math
2
3
  from collections.abc import Mapping, Sequence
3
4
  from typing import TypeAlias, assert_never
4
- from warnings import warn
5
5
 
6
6
  import dask.array as da
7
7
  import numpy as np
@@ -13,6 +13,9 @@ from ngio.io_pipes._ops_slices_utils import compute_slice_chunks
13
13
  from ngio.ome_zarr_meta.ngio_specs import Axis
14
14
  from ngio.utils import NgioValueError
15
15
 
16
+ logger = logging.getLogger(f"ngio:{__name__}")
17
+
18
+
16
19
  SlicingInputType: TypeAlias = slice | Sequence[int] | int | None
17
20
  SlicingType: TypeAlias = slice | list[int] | int
18
21
 
@@ -141,12 +144,11 @@ def _check_list_in_slicing_tuple(
141
144
  # Complex case, we have exactly one tuple in the slicing tuple
142
145
  ax, first_tuple = list_in_slice[0]
143
146
  if len(first_tuple) > 100:
144
- warn(
147
+ logger.warning(
145
148
  "Performance warning: "
146
149
  "Non-contiguous slicing with a tuple/list with more than 100 elements is "
147
150
  "not natively supported by zarr. This is implemented by Ngio by performing "
148
- "multiple reads and stacking the result.",
149
- stacklevel=2,
151
+ "multiple reads and stacking the result."
150
152
  )
151
153
  return ax, first_tuple
152
154
 
@@ -1,10 +1,13 @@
1
- import warnings
1
+ import logging
2
2
  from collections.abc import Iterable, Iterator
3
3
  from itertools import product
4
4
  from typing import TypeAlias, TypeVar
5
5
 
6
6
  from ngio.utils import NgioValueError
7
7
 
8
+ logger = logging.getLogger(f"ngio:{__name__}")
9
+
10
+
8
11
  T = TypeVar("T")
9
12
 
10
13
  ##############################################################
@@ -86,10 +89,9 @@ def check_if_regions_overlap(slices: Iterable[tuple[SlicingType, ...]]) -> bool:
86
89
  return True
87
90
 
88
91
  if it == 10_000:
89
- warnings.warn(
92
+ logger.warning(
90
93
  "Performance Warning check_for_overlaps is O(n^2) and may be slow for "
91
- "large numbers of regions.",
92
- stacklevel=2,
94
+ "large numbers of regions."
93
95
  )
94
96
  return False
95
97
 
@@ -191,9 +193,8 @@ def check_if_chunks_overlap(
191
193
  if si & sj:
192
194
  return True
193
195
  if it == 10_000:
194
- warnings.warn(
196
+ logger.warning(
195
197
  "Performance Warning check_for_chunks_overlaps is O(n^2) and may be "
196
- "slow for large numbers of regions.",
197
- stacklevel=2,
198
+ "slow for large numbers of regions."
198
199
  )
199
200
  return False
@@ -176,8 +176,6 @@ def get_ngio_image_meta(
176
176
  group_handler: ZarrGroupHandler,
177
177
  version: str | None = None,
178
178
  axes_setup: AxesSetup | None = None,
179
- allow_non_canonical_axes: bool = False,
180
- strict_canonical_order: bool = True,
181
179
  ) -> NgioImageMeta:
182
180
  """Retrieve the NGIO image metadata from the Zarr group.
183
181
 
@@ -185,19 +183,16 @@ def get_ngio_image_meta(
185
183
  group_handler (ZarrGroupHandler): The Zarr group handler.
186
184
  version (str | None): Optional NGFF version to use for decoding.
187
185
  axes_setup (AxesSetup | None): Optional axes setup for validation.
188
- allow_non_canonical_axes (bool): Whether to allow non-canonical axes.
189
- strict_canonical_order (bool): Whether to enforce strict canonical order.
190
186
 
191
187
  Returns:
192
188
  NgioImageMeta: The NGIO image metadata.
193
189
  """
190
+ # axes_setup = axes_setup or AxesSetup(x="XX")
194
191
  return get_ngio_meta(
195
192
  group_handler=group_handler,
196
193
  meta_type=NgioImageMeta,
197
194
  version=version,
198
195
  axes_setup=axes_setup,
199
- allow_non_canonical_axes=allow_non_canonical_axes,
200
- strict_canonical_order=strict_canonical_order,
201
196
  )
202
197
 
203
198
 
@@ -224,15 +219,10 @@ class ImageMetaHandler:
224
219
  group_handler: ZarrGroupHandler,
225
220
  version: str | None = None,
226
221
  axes_setup: AxesSetup | None = None,
227
- allow_non_canonical_axes: bool = False,
228
- strict_canonical_order: bool = True,
229
222
  ):
230
223
  self._group_handler = group_handler
231
224
  self._version = version
232
225
  self._axes_setup = axes_setup
233
- self._allow_non_canonical_axes = allow_non_canonical_axes
234
- self._strict_canonical_order = strict_canonical_order
235
-
236
226
  # Validate metadata
237
227
  meta = self.get_meta()
238
228
  # Store the resolved version
@@ -244,8 +234,6 @@ class ImageMetaHandler:
244
234
  group_handler=self._group_handler,
245
235
  version=self._version,
246
236
  axes_setup=self._axes_setup,
247
- allow_non_canonical_axes=self._allow_non_canonical_axes,
248
- strict_canonical_order=self._strict_canonical_order,
249
237
  )
250
238
 
251
239
  def update_meta(self, ngio_meta: NgioImageMeta) -> None:
@@ -260,8 +248,6 @@ def get_ngio_label_meta(
260
248
  group_handler: ZarrGroupHandler,
261
249
  version: str | None = None,
262
250
  axes_setup: AxesSetup | None = None,
263
- allow_non_canonical_axes: bool = False,
264
- strict_canonical_order: bool = True,
265
251
  ) -> NgioLabelMeta:
266
252
  """Retrieve the NGIO label metadata from the Zarr group.
267
253
 
@@ -269,8 +255,6 @@ def get_ngio_label_meta(
269
255
  group_handler (ZarrGroupHandler): The Zarr group handler.
270
256
  version (str | None): Optional NGFF version to use for decoding.
271
257
  axes_setup (AxesSetup | None): Optional axes setup for validation.
272
- allow_non_canonical_axes (bool): Whether to allow non-canonical axes.
273
- strict_canonical_order (bool): Whether to enforce strict canonical order.
274
258
 
275
259
  Returns:
276
260
  NgioLabelMeta: The NGIO label metadata.
@@ -280,8 +264,6 @@ def get_ngio_label_meta(
280
264
  meta_type=NgioLabelMeta,
281
265
  version=version,
282
266
  axes_setup=axes_setup,
283
- allow_non_canonical_axes=allow_non_canonical_axes,
284
- strict_canonical_order=strict_canonical_order,
285
267
  )
286
268
 
287
269
 
@@ -306,16 +288,12 @@ class LabelMetaHandler:
306
288
  def __init__(
307
289
  self,
308
290
  group_handler: ZarrGroupHandler,
309
- version: str | None = None,
310
291
  axes_setup: AxesSetup | None = None,
311
- allow_non_canonical_axes: bool = False,
312
- strict_canonical_order: bool = True,
292
+ version: str | None = None,
313
293
  ):
314
294
  self._group_handler = group_handler
315
295
  self._version = version
316
296
  self._axes_setup = axes_setup
317
- self._allow_non_canonical_axes = allow_non_canonical_axes
318
- self._strict_canonical_order = strict_canonical_order
319
297
 
320
298
  # Validate metadata
321
299
  meta = self.get_meta()
@@ -328,8 +306,6 @@ class LabelMetaHandler:
328
306
  group_handler=self._group_handler,
329
307
  version=self._version,
330
308
  axes_setup=self._axes_setup,
331
- allow_non_canonical_axes=self._allow_non_canonical_axes,
332
- strict_canonical_order=self._strict_canonical_order,
333
309
  )
334
310
 
335
311
  def update_meta(self, ngio_meta: NgioLabelMeta) -> None:
@@ -15,6 +15,7 @@ from ngio.ome_zarr_meta.ngio_specs._axes import (
15
15
  DefaultTimeUnit,
16
16
  SpaceUnits,
17
17
  TimeUnits,
18
+ build_axes_handler,
18
19
  build_canonical_axes_handler,
19
20
  canonical_axes_order,
20
21
  canonical_label_axes_order,
@@ -69,6 +70,7 @@ __all__ = [
69
70
  "PixelSize",
70
71
  "SpaceUnits",
71
72
  "TimeUnits",
73
+ "build_axes_handler",
72
74
  "build_canonical_axes_handler",
73
75
  "canonical_axes_order",
74
76
  "canonical_label_axes_order",
@@ -4,7 +4,7 @@ from collections.abc import Sequence
4
4
  from enum import Enum
5
5
  from typing import Literal, TypeAlias, TypeVar
6
6
 
7
- from pydantic import BaseModel, ConfigDict, Field
7
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
8
8
 
9
9
  from ngio.utils import NgioValidationError, NgioValueError
10
10
 
@@ -153,9 +153,51 @@ class AxesSetup(BaseModel):
153
153
  c: str = "c"
154
154
  t: str = "t"
155
155
  others: list[str] = Field(default_factory=list)
156
+ allow_non_canonical_axes: bool = False
157
+ strict_canonical_order: bool = False
156
158
 
157
159
  model_config = ConfigDict(extra="forbid", frozen=True)
158
160
 
161
+ @model_validator(mode="after")
162
+ def _validate_axes_values(self) -> "AxesSetup":
163
+ """Validate the axes values."""
164
+ canonical = {"x", "y", "z", "c", "t"}
165
+ axes = {"x": self.x, "y": self.y, "z": self.z, "c": self.c, "t": self.t}
166
+
167
+ for axis_name, axis_value in axes.items():
168
+ reserved = canonical - {axis_name}
169
+ if axis_value in reserved:
170
+ raise NgioValueError(
171
+ f"The {axis_name} axis cannot be called: '{axis_value}'. "
172
+ f"{axis_value} is reserved. If you want to set a non canonical "
173
+ "axis order, please set the 'strict_canonical_order'to False."
174
+ )
175
+ return self
176
+
177
+ @classmethod
178
+ def from_ordered_list(
179
+ cls, axes_names: Sequence[str], canonical_order: Sequence[str]
180
+ ):
181
+ """Create an AxesSetup from an ordered list of axes names."""
182
+ # Make sure to only keep as many default axes as provided in axes_names
183
+ if len(axes_names) > len(canonical_order):
184
+ raise NgioValueError(
185
+ f"Cannot create AxesSetup from axes names {axes_names} "
186
+ f"and canonical order {canonical_order}. "
187
+ "The number of axes names cannot be greater than the "
188
+ "number of canonical axes."
189
+ )
190
+ canonical_order = list(canonical_order)
191
+ chanonical_axes = canonical_axes_order()
192
+ axes_mapping = {}
193
+ for ax in reversed(axes_names):
194
+ c_ax = canonical_order.pop()
195
+ if ax in chanonical_axes:
196
+ axes_mapping[ax] = ax
197
+ else:
198
+ axes_mapping[c_ax] = ax
199
+ return cls(**axes_mapping)
200
+
159
201
  def canonical_map(self) -> dict[str, str]:
160
202
  """Get the canonical map of axes."""
161
203
  return {
@@ -197,9 +239,9 @@ def _check_unique_names(axes: Sequence[Axis]):
197
239
  )
198
240
 
199
241
 
200
- def _check_non_canonical_axes(axes_setup: AxesSetup, allow_non_canonical_axes: bool):
242
+ def _check_non_canonical_axes(axes_setup: AxesSetup):
201
243
  """Check if all axes are known."""
202
- if not allow_non_canonical_axes and len(axes_setup.others) > 0:
244
+ if not axes_setup.allow_non_canonical_axes and len(axes_setup.others) > 0:
203
245
  raise NgioValidationError(
204
246
  f"Unknown axes {axes_setup.others}. Please set "
205
247
  "`allow_non_canonical_axes=True` to ignore them"
@@ -219,11 +261,9 @@ def _check_axes_validity(axes: Sequence[Axis], axes_setup: AxesSetup):
219
261
  )
220
262
 
221
263
 
222
- def _check_canonical_order(
223
- axes: Sequence[Axis], axes_setup: AxesSetup, strict_canonical_order: bool
224
- ):
264
+ def _check_canonical_order(axes: Sequence[Axis], axes_setup: AxesSetup):
225
265
  """Check if the axes are in the canonical order."""
226
- if not strict_canonical_order:
266
+ if not axes_setup.strict_canonical_order:
227
267
  return
228
268
  _names = [ax.name for ax in axes]
229
269
  _canonical_order = []
@@ -242,24 +282,18 @@ def _check_canonical_order(
242
282
  def validate_axes(
243
283
  axes: Sequence[Axis],
244
284
  axes_setup: AxesSetup,
245
- allow_non_canonical_axes: bool = False,
246
- strict_canonical_order: bool = False,
247
285
  ) -> None:
248
286
  """Validate the axes."""
249
- if allow_non_canonical_axes and strict_canonical_order:
250
- raise NgioValidationError(
287
+ if axes_setup.allow_non_canonical_axes and axes_setup.strict_canonical_order:
288
+ raise NgioValueError(
251
289
  "`allow_non_canonical_axes` and"
252
290
  "`strict_canonical_order` cannot be true at the same time."
253
291
  "If non canonical axes are allowed, the order cannot be checked."
254
292
  )
255
293
  _check_unique_names(axes=axes)
256
- _check_non_canonical_axes(
257
- axes_setup=axes_setup, allow_non_canonical_axes=allow_non_canonical_axes
258
- )
294
+ _check_non_canonical_axes(axes_setup=axes_setup)
259
295
  _check_axes_validity(axes=axes, axes_setup=axes_setup)
260
- _check_canonical_order(
261
- axes=axes, axes_setup=axes_setup, strict_canonical_order=strict_canonical_order
262
- )
296
+ _check_canonical_order(axes=axes, axes_setup=axes_setup)
263
297
 
264
298
 
265
299
  class AxesHandler:
@@ -278,29 +312,22 @@ class AxesHandler:
278
312
  axes: Sequence[Axis],
279
313
  # user defined args
280
314
  axes_setup: AxesSetup | None = None,
281
- allow_non_canonical_axes: bool = False,
282
- strict_canonical_order: bool = False,
283
315
  ):
284
316
  """Create a new AxesMapper object.
285
317
 
286
318
  Args:
287
319
  axes (list[Axis]): The axes on disk.
288
320
  axes_setup (AxesSetup, optional): The axis setup. Defaults to None.
289
- allow_non_canonical_axes (bool, optional): Allow non canonical axes.
290
- strict_canonical_order (bool, optional): Check if the axes are in the
291
- canonical order. Defaults to False.
292
321
  """
293
322
  axes_setup = axes_setup if axes_setup is not None else AxesSetup()
294
323
 
295
324
  validate_axes(
296
325
  axes=axes,
297
326
  axes_setup=axes_setup,
298
- allow_non_canonical_axes=allow_non_canonical_axes,
299
- strict_canonical_order=strict_canonical_order,
300
327
  )
301
328
 
302
- self._allow_non_canonical_axes = allow_non_canonical_axes
303
- self._strict_canonical_order = strict_canonical_order
329
+ self._allow_non_canonical_axes = axes_setup.allow_non_canonical_axes
330
+ self._strict_canonical_order = axes_setup.strict_canonical_order
304
331
 
305
332
  self._canonical_order = canonical_axes_order()
306
333
 
@@ -422,8 +449,48 @@ class AxesHandler:
422
449
  return AxesHandler(
423
450
  axes=new_axes,
424
451
  axes_setup=self.axes_setup,
425
- allow_non_canonical_axes=self.allow_non_canonical_axes,
426
- strict_canonical_order=self.strict_canonical_order,
452
+ )
453
+
454
+ def rename_axes(self, axes_names: Sequence[str]) -> "AxesHandler":
455
+ """Rename the axes.
456
+
457
+ Args:
458
+ axes_names (Sequence[str]): The new axes names.
459
+ """
460
+ if len(axes_names) != len(self.axes):
461
+ raise NgioValueError(
462
+ f"Cannot rename axes. "
463
+ f"Expected {len(self.axes)} axes, but got {len(axes_names)}."
464
+ )
465
+ new_axes = []
466
+ axes_setup = self.axes_setup
467
+ for ax, new_name in zip(self.axes, axes_names, strict=True):
468
+ if ax.name == new_name:
469
+ new_axes.append(ax)
470
+ continue
471
+ new_ax = Axis(name=new_name, axis_type=ax.axis_type, unit=ax.unit)
472
+ match ax.name:
473
+ case axes_setup.x:
474
+ axes_setup = axes_setup.model_copy(update={"x": new_name})
475
+ case axes_setup.y:
476
+ axes_setup = axes_setup.model_copy(update={"y": new_name})
477
+ case axes_setup.z:
478
+ axes_setup = axes_setup.model_copy(update={"z": new_name})
479
+ case axes_setup.c:
480
+ axes_setup = axes_setup.model_copy(update={"c": new_name})
481
+ case axes_setup.t:
482
+ axes_setup = axes_setup.model_copy(update={"t": new_name})
483
+ case _:
484
+ if ax.name in axes_setup.others:
485
+ others = axes_setup.others.copy()
486
+ others.remove(ax.name)
487
+ others.append(new_name)
488
+ axes_setup = axes_setup.model_copy(update={"others": others})
489
+ new_axes.append(new_ax)
490
+ # Update the axes setup
491
+ return AxesHandler(
492
+ axes=new_axes,
493
+ axes_setup=axes_setup,
427
494
  )
428
495
 
429
496
  def get_index(self, name: str) -> int | None:
@@ -465,14 +532,33 @@ class AxesHandler:
465
532
  self._axes = new_axes
466
533
 
467
534
 
535
+ def _build_axes_list_from_names(
536
+ axes_names: Sequence[str],
537
+ axes_setup: AxesSetup,
538
+ space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
539
+ time_unit: TimeUnits | str | None = DefaultTimeUnit,
540
+ ) -> list[Axis]:
541
+ """Build a list of Axis objects from a list of axis names."""
542
+ axes = []
543
+ for name in axes_names:
544
+ c_name = axes_setup.get_canonical_name(name)
545
+ match c_name:
546
+ case "t":
547
+ axes.append(Axis(name=name, axis_type=AxisType.time, unit=time_unit))
548
+ case "c":
549
+ axes.append(Axis(name=name, axis_type=AxisType.channel))
550
+ case "z" | "y" | "x":
551
+ axes.append(Axis(name=name, axis_type=AxisType.space, unit=space_unit))
552
+ case _:
553
+ axes.append(Axis(name=name, axis_type=AxisType.space))
554
+ return axes
555
+
556
+
468
557
  def build_canonical_axes_handler(
469
558
  axes_names: Sequence[str],
470
- space_units: SpaceUnits | str | None = DefaultSpaceUnit,
471
- time_units: TimeUnits | str | None = DefaultTimeUnit,
472
- # user defined args
473
- axes_setup: AxesSetup | None = None,
474
- allow_non_canonical_axes: bool = False,
475
- strict_canonical_order: bool = False,
559
+ canonical_channel_order: Sequence[str] | None = None,
560
+ space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
561
+ time_unit: TimeUnits | str | None = DefaultTimeUnit,
476
562
  ) -> AxesHandler:
477
563
  """Create a new canonical axes mapper.
478
564
 
@@ -483,33 +569,50 @@ def build_canonical_axes_handler(
483
569
  - If an integer is provided, the axes are created from the last axis
484
570
  to the first
485
571
  e.g. 3 -> ["z", "y", "x"]
486
- space_units (SpaceUnits, optional): The space units. Defaults to None.
487
- time_units (TimeUnits, optional): The time units. Defaults to None.
488
- axes_setup (AxesSetup, optional): The axis setup. Defaults to None.
489
- allow_non_canonical_axes (bool, optional): Allow non canonical axes.
490
- Defaults to False.
491
- strict_canonical_order (bool, optional): Check if the axes are in the
492
- canonical order. Defaults to False.
493
-
572
+ canonical_channel_order (Sequence[str], optional): The canonical channel
573
+ order. Defaults to None, which uses the default order.
574
+ space_unit (SpaceUnits, optional): The space units. Defaults to None.
575
+ time_unit (TimeUnits, optional): The time units. Defaults to None.
494
576
  """
495
- axes = []
496
- for name in axes_names:
497
- match name:
498
- case "t":
499
- axes.append(Axis(name=name, axis_type=AxisType.time, unit=time_units))
500
- case "c":
501
- axes.append(Axis(name=name, axis_type=AxisType.channel))
502
- case "z" | "y" | "x":
503
- axes.append(Axis(name=name, axis_type=AxisType.space, unit=space_units))
504
- case _:
505
- raise NgioValueError(
506
- f"Invalid axis name '{name}'. "
507
- "Only 't', 'c', 'z', 'y', 'x' are allowed."
508
- )
577
+ if canonical_channel_order is None:
578
+ canonical_channel_order = canonical_axes_order()
579
+ axes_setup = AxesSetup.from_ordered_list(
580
+ axes_names=axes_names, canonical_order=canonical_channel_order
581
+ )
582
+ axes = _build_axes_list_from_names(
583
+ axes_names=axes_names,
584
+ axes_setup=axes_setup,
585
+ space_unit=space_unit,
586
+ time_unit=time_unit,
587
+ )
588
+ return AxesHandler(
589
+ axes=axes,
590
+ axes_setup=axes_setup,
591
+ )
592
+
509
593
 
594
+ def build_axes_handler(
595
+ axes_names: Sequence[str],
596
+ axes_setup: AxesSetup | None = None,
597
+ space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
598
+ time_unit: TimeUnits | str | None = DefaultTimeUnit,
599
+ ) -> AxesHandler:
600
+ """Create a new axes mapper.
601
+
602
+ Args:
603
+ axes_names (Sequence[str]): The axes names on disk.
604
+ axes_setup (AxesSetup, optional): The axis setup. Defaults to None.
605
+ space_unit (SpaceUnits, optional): The space units. Defaults to None.
606
+ time_unit (TimeUnits, optional): The time units. Defaults to None.
607
+ """
608
+ axes_setup = axes_setup if axes_setup is not None else AxesSetup()
609
+ axes = _build_axes_list_from_names(
610
+ axes_names=axes_names,
611
+ axes_setup=axes_setup,
612
+ space_unit=space_unit,
613
+ time_unit=time_unit,
614
+ )
510
615
  return AxesHandler(
511
616
  axes=axes,
512
617
  axes_setup=axes_setup,
513
- allow_non_canonical_axes=allow_non_canonical_axes,
514
- strict_canonical_order=strict_canonical_order,
515
618
  )