ngio 0.2.0b3__py3-none-any.whl → 0.2.2__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.
@@ -5,7 +5,7 @@ from typing import Literal, overload
5
5
 
6
6
  import numpy as np
7
7
 
8
- from ngio.images.create import _create_empty_image
8
+ from ngio.images.create import create_empty_image_container
9
9
  from ngio.images.image import Image, ImagesContainer
10
10
  from ngio.images.label import Label, LabelsContainer
11
11
  from ngio.images.masked_image import MaskedImage, MaskedLabel
@@ -14,13 +14,17 @@ from ngio.ome_zarr_meta import (
14
14
  PixelSize,
15
15
  )
16
16
  from ngio.ome_zarr_meta.ngio_specs import (
17
+ DefaultNgffVersion,
18
+ DefaultSpaceUnit,
19
+ DefaultTimeUnit,
20
+ NgffVersions,
17
21
  SpaceUnits,
18
22
  TimeUnits,
19
23
  )
20
24
  from ngio.tables import (
21
25
  FeatureTable,
22
26
  GenericRoiTable,
23
- MaskingROITable,
27
+ MaskingRoiTable,
24
28
  RoiTable,
25
29
  Table,
26
30
  TablesContainer,
@@ -155,7 +159,17 @@ class OmeZarrContainer:
155
159
  """Return True if the image is multichannel."""
156
160
  return self.get_image().is_multi_channels
157
161
 
158
- def initialize_channel_meta(
162
+ @property
163
+ def space_unit(self) -> str | None:
164
+ """Return the space unit of the image."""
165
+ return self.image_meta.space_unit
166
+
167
+ @property
168
+ def time_unit(self) -> str | None:
169
+ """Return the time unit of the image."""
170
+ return self.image_meta.time_unit
171
+
172
+ def set_channel_meta(
159
173
  self,
160
174
  labels: Collection[str] | int | None = None,
161
175
  wavelength_id: Collection[str] | None = None,
@@ -165,7 +179,7 @@ class OmeZarrContainer:
165
179
  **omero_kwargs: dict,
166
180
  ) -> None:
167
181
  """Create a ChannelsMeta object with the default unit."""
168
- self._images_container.initialize_channel_meta(
182
+ self._images_container.set_channel_meta(
169
183
  labels=labels,
170
184
  wavelength_id=wavelength_id,
171
185
  percentiles=percentiles,
@@ -174,16 +188,36 @@ class OmeZarrContainer:
174
188
  **omero_kwargs,
175
189
  )
176
190
 
177
- def update_percentiles(
191
+ def set_channel_percentiles(
178
192
  self,
179
193
  start_percentile: float = 0.1,
180
194
  end_percentile: float = 99.9,
181
195
  ) -> None:
182
196
  """Update the percentiles of the image."""
183
- self._images_container.update_percentiles(
197
+ self._images_container.set_channel_percentiles(
184
198
  start_percentile=start_percentile, end_percentile=end_percentile
185
199
  )
186
200
 
201
+ def set_axes_units(
202
+ self,
203
+ space_unit: SpaceUnits = DefaultSpaceUnit,
204
+ time_unit: TimeUnits = DefaultTimeUnit,
205
+ set_labels: bool = True,
206
+ ) -> None:
207
+ """Set the units of the image.
208
+
209
+ Args:
210
+ space_unit (SpaceUnits): The unit of space.
211
+ time_unit (TimeUnits): The unit of time.
212
+ set_labels (bool): Whether to set the units for the labels as well.
213
+ """
214
+ self._images_container.set_axes_unit(space_unit=space_unit, time_unit=time_unit)
215
+ if not set_labels:
216
+ return
217
+ for label_name in self.list_labels():
218
+ label = self.get_label(label_name)
219
+ label.set_axes_unit(space_unit=space_unit, time_unit=time_unit)
220
+
187
221
  def get_image(
188
222
  self,
189
223
  path: str | None = None,
@@ -193,7 +227,7 @@ class OmeZarrContainer:
193
227
  """Get an image at a specific level.
194
228
 
195
229
  Args:
196
- path (str | None): The path to the image in the omezarr file.
230
+ path (str | None): The path to the image in the ome_zarr file.
197
231
  pixel_size (PixelSize | None): The pixel size of the image.
198
232
  strict (bool): Only used if the pixel size is provided. If True, the
199
233
  pixel size must match the image pixel size exactly. If False, the
@@ -217,7 +251,7 @@ class OmeZarrContainer:
217
251
  Args:
218
252
  masking_label_name (str): The name of the label.
219
253
  masking_table_name (str | None): The name of the masking table.
220
- path (str | None): The path to the image in the omezarr file.
254
+ path (str | None): The path to the image in the ome_zarr file.
221
255
  pixel_size (PixelSize | None): The pixel size of the image.
222
256
  strict (bool): Only used if the pixel size is provided. If True, the
223
257
  pixel size must match the image pixel size exactly. If False, the
@@ -250,6 +284,7 @@ class OmeZarrContainer:
250
284
  labels: Collection[str] | None = None,
251
285
  pixel_size: PixelSize | None = None,
252
286
  axes_names: Collection[str] | None = None,
287
+ name: str | None = None,
253
288
  chunks: Collection[int] | None = None,
254
289
  dtype: str | None = None,
255
290
  copy_labels: bool = False,
@@ -268,6 +303,7 @@ class OmeZarrContainer:
268
303
  axes_names (Collection[str] | None): The axes names of the new image.
269
304
  chunks (Collection[int] | None): The chunk shape of the new image.
270
305
  dtype (str | None): The data type of the new image.
306
+ name (str | None): The name of the new image.
271
307
  copy_labels (bool): Whether to copy the labels from the reference image.
272
308
  copy_tables (bool): Whether to copy the tables from the reference image.
273
309
  overwrite (bool): Whether to overwrite an existing image.
@@ -283,6 +319,7 @@ class OmeZarrContainer:
283
319
  labels=labels,
284
320
  pixel_size=pixel_size,
285
321
  axes_names=axes_names,
322
+ name=name,
286
323
  chunks=chunks,
287
324
  dtype=dtype,
288
325
  overwrite=overwrite,
@@ -292,21 +329,21 @@ class OmeZarrContainer:
292
329
  store, cache=self._group_handler.use_cache, mode=self._group_handler.mode
293
330
  )
294
331
 
295
- new_omezarr = OmeZarrContainer(
332
+ new_ome_zarr = OmeZarrContainer(
296
333
  group_handler=handler,
297
334
  validate_arrays=False,
298
335
  )
299
336
 
300
337
  if copy_labels:
301
338
  self.labels_container._group_handler.copy_handler(
302
- new_omezarr.labels_container._group_handler
339
+ new_ome_zarr.labels_container._group_handler
303
340
  )
304
341
 
305
342
  if copy_tables:
306
343
  self.tables_container._group_handler.copy_handler(
307
- new_omezarr.tables_container._group_handler
344
+ new_ome_zarr.tables_container._group_handler
308
345
  )
309
- return new_omezarr
346
+ return new_ome_zarr
310
347
 
311
348
  def list_tables(self) -> list[str]:
312
349
  """List all tables in the image."""
@@ -325,7 +362,7 @@ class OmeZarrContainer:
325
362
  @overload
326
363
  def get_table(
327
364
  self, name: str, check_type: Literal["masking_roi_table"]
328
- ) -> MaskingROITable: ...
365
+ ) -> MaskingRoiTable: ...
329
366
 
330
367
  @overload
331
368
  def get_table(
@@ -348,7 +385,7 @@ class OmeZarrContainer:
348
385
  )
349
386
  return table
350
387
  case "masking_roi_table":
351
- if not isinstance(table, MaskingROITable):
388
+ if not isinstance(table, MaskingRoiTable):
352
389
  raise NgioValueError(
353
390
  f"Table '{name}' is not a masking ROI table. "
354
391
  f"Found type: {table.type()}"
@@ -379,7 +416,7 @@ class OmeZarrContainer:
379
416
  """Compute the ROI table for an image."""
380
417
  return self.get_image().build_image_roi_table(name=name)
381
418
 
382
- def build_masking_roi_table(self, label: str) -> MaskingROITable:
419
+ def build_masking_roi_table(self, label: str) -> MaskingRoiTable:
383
420
  """Compute the masking ROI table for a label."""
384
421
  return self.get_label(label).build_masking_roi_table()
385
422
 
@@ -410,7 +447,7 @@ class OmeZarrContainer:
410
447
 
411
448
  Args:
412
449
  name (str): The name of the label.
413
- path (str | None): The path to the image in the omezarr file.
450
+ path (str | None): The path to the image in the ome_zarr file.
414
451
  pixel_size (PixelSize | None): The pixel size of the image.
415
452
  strict (bool): Only used if the pixel size is provided. If True, the
416
453
  pixel size must match the image pixel size exactly. If False, the
@@ -435,7 +472,7 @@ class OmeZarrContainer:
435
472
  label_name (str): The name of the label.
436
473
  masking_label_name (str): The name of the masking label.
437
474
  masking_table_name (str | None): The name of the masking table.
438
- path (str | None): The path to the image in the omezarr file.
475
+ path (str | None): The path to the image in the ome_zarr file.
439
476
  pixel_size (PixelSize | None): The pixel size of the image.
440
477
  strict (bool): Only used if the pixel size is provided. If True, the
441
478
  pixel size must match the image pixel size exactly. If False, the
@@ -507,7 +544,7 @@ class OmeZarrContainer:
507
544
  )
508
545
 
509
546
 
510
- def open_omezarr_container(
547
+ def open_ome_zarr_container(
511
548
  store: StoreOrGroup,
512
549
  cache: bool = False,
513
550
  mode: AccessModeLiteral = "r+",
@@ -533,7 +570,7 @@ def open_image(
533
570
 
534
571
  Args:
535
572
  store (StoreOrGroup): The Zarr store or group to create the image in.
536
- path (str | None): The path to the image in the omezarr file.
573
+ path (str | None): The path to the image in the ome_zarr file.
537
574
  pixel_size (PixelSize | None): The pixel size of the image.
538
575
  strict (bool): Only used if the pixel size is provided. If True, the
539
576
  pixel size must match the image pixel size exactly. If False, the
@@ -551,7 +588,7 @@ def open_image(
551
588
  )
552
589
 
553
590
 
554
- def create_empty_omezarr(
591
+ def create_empty_ome_zarr(
555
592
  store: StoreOrGroup,
556
593
  shape: Collection[int],
557
594
  xy_pixelsize: float,
@@ -560,8 +597,8 @@ def create_empty_omezarr(
560
597
  levels: int | list[str] = 5,
561
598
  xy_scaling_factor: float = 2,
562
599
  z_scaling_factor: float = 1.0,
563
- space_unit: SpaceUnits | str | None = None,
564
- time_unit: TimeUnits | str | None = None,
600
+ space_unit: SpaceUnits = DefaultSpaceUnit,
601
+ time_unit: TimeUnits = DefaultTimeUnit,
565
602
  axes_names: Collection[str] | None = None,
566
603
  name: str | None = None,
567
604
  chunks: Collection[int] | None = None,
@@ -572,7 +609,7 @@ def create_empty_omezarr(
572
609
  channel_colors: Collection[str] | None = None,
573
610
  channel_active: Collection[bool] | None = None,
574
611
  overwrite: bool = False,
575
- version: str = "0.4",
612
+ version: NgffVersions = DefaultNgffVersion,
576
613
  ) -> OmeZarrContainer:
577
614
  """Create an empty OME-Zarr image with the given shape and metadata.
578
615
 
@@ -589,10 +626,10 @@ def create_empty_omezarr(
589
626
  dimensions. Defaults to 2.0.
590
627
  z_scaling_factor (float, optional): The down-scaling factor in z dimension.
591
628
  Defaults to 1.0.
592
- space_unit (SpaceUnits | str | None, optional): The unit of space. Defaults to
593
- None.
594
- time_unit (TimeUnits | str | None, optional): The unit of time. Defaults to
595
- None.
629
+ space_unit (SpaceUnits, optional): The unit of space. Defaults to
630
+ DefaultSpaceUnit.
631
+ time_unit (TimeUnits, optional): The unit of time. Defaults to
632
+ DefaultTimeUnit.
596
633
  axes_names (Collection[str] | None, optional): The names of the axes.
597
634
  If None the canonical names are used. Defaults to None.
598
635
  name (str | None, optional): The name of the image. Defaults to None.
@@ -611,10 +648,10 @@ def create_empty_omezarr(
611
648
  active. Defaults to None.
612
649
  overwrite (bool, optional): Whether to overwrite an existing image.
613
650
  Defaults to True.
614
- version (str, optional): The version of the OME-Zarr specification.
615
- Defaults to "0.4".
651
+ version (NgffVersion, optional): The version of the OME-Zarr specification.
652
+ Defaults to DefaultNgffVersion.
616
653
  """
617
- handler = _create_empty_image(
654
+ handler = create_empty_image_container(
618
655
  store=store,
619
656
  shape=shape,
620
657
  pixelsize=xy_pixelsize,
@@ -633,18 +670,18 @@ def create_empty_omezarr(
633
670
  version=version,
634
671
  )
635
672
 
636
- omezarr = OmeZarrContainer(group_handler=handler)
637
- omezarr.initialize_channel_meta(
673
+ ome_zarr = OmeZarrContainer(group_handler=handler)
674
+ ome_zarr.set_channel_meta(
638
675
  labels=channel_labels,
639
676
  wavelength_id=channel_wavelengths,
640
677
  percentiles=percentiles,
641
678
  colors=channel_colors,
642
679
  active=channel_active,
643
680
  )
644
- return omezarr
681
+ return ome_zarr
645
682
 
646
683
 
647
- def create_omezarr_from_array(
684
+ def create_ome_zarr_from_array(
648
685
  store: StoreOrGroup,
649
686
  array: np.ndarray,
650
687
  xy_pixelsize: float,
@@ -653,8 +690,8 @@ def create_omezarr_from_array(
653
690
  levels: int | list[str] = 5,
654
691
  xy_scaling_factor: float = 2.0,
655
692
  z_scaling_factor: float = 1.0,
656
- space_unit: SpaceUnits | str | None = None,
657
- time_unit: TimeUnits | str | None = None,
693
+ space_unit: SpaceUnits = DefaultSpaceUnit,
694
+ time_unit: TimeUnits = DefaultTimeUnit,
658
695
  axes_names: Collection[str] | None = None,
659
696
  channel_labels: list[str] | None = None,
660
697
  channel_wavelengths: list[str] | None = None,
@@ -664,7 +701,7 @@ def create_omezarr_from_array(
664
701
  name: str | None = None,
665
702
  chunks: Collection[int] | None = None,
666
703
  overwrite: bool = False,
667
- version: str = "0.4",
704
+ version: NgffVersions = DefaultNgffVersion,
668
705
  ) -> OmeZarrContainer:
669
706
  """Create an OME-Zarr image from a numpy array.
670
707
 
@@ -681,10 +718,10 @@ def create_omezarr_from_array(
681
718
  dimensions. Defaults to 2.0.
682
719
  z_scaling_factor (float, optional): The down-scaling factor in z dimension.
683
720
  Defaults to 1.0.
684
- space_unit (SpaceUnits | str | None, optional): The unit of space. Defaults to
685
- None.
686
- time_unit (TimeUnits | str | None, optional): The unit of time. Defaults to
687
- None.
721
+ space_unit (SpaceUnits, optional): The unit of space. Defaults to
722
+ DefaultSpaceUnit.
723
+ time_unit (TimeUnits, optional): The unit of time. Defaults to
724
+ DefaultTimeUnit.
688
725
  axes_names (Collection[str] | None, optional): The names of the axes.
689
726
  If None the canonical names are used. Defaults to None.
690
727
  name (str | None, optional): The name of the image. Defaults to None.
@@ -703,9 +740,9 @@ def create_omezarr_from_array(
703
740
  overwrite (bool, optional): Whether to overwrite an existing image.
704
741
  Defaults to True.
705
742
  version (str, optional): The version of the OME-Zarr specification.
706
- Defaults to "0.4".
743
+ Defaults to DefaultNgffVersion.
707
744
  """
708
- handler = _create_empty_image(
745
+ handler = create_empty_image_container(
709
746
  store=store,
710
747
  shape=array.shape,
711
748
  pixelsize=xy_pixelsize,
@@ -724,15 +761,15 @@ def create_omezarr_from_array(
724
761
  version=version,
725
762
  )
726
763
 
727
- omezarr = OmeZarrContainer(group_handler=handler)
728
- image = omezarr.get_image()
764
+ ome_zarr = OmeZarrContainer(group_handler=handler)
765
+ image = ome_zarr.get_image()
729
766
  image.set_array(array)
730
767
  image.consolidate()
731
- omezarr.initialize_channel_meta(
768
+ ome_zarr.set_channel_meta(
732
769
  labels=channel_labels,
733
770
  wavelength_id=channel_wavelengths,
734
771
  percentiles=percentiles,
735
772
  colors=channel_colors,
736
773
  active=channel_active,
737
774
  )
738
- return omezarr
775
+ return ome_zarr
@@ -16,11 +16,13 @@ from ngio.ome_zarr_meta.ngio_specs import (
16
16
  AxesMapper,
17
17
  Dataset,
18
18
  ImageInWellPath,
19
+ NgffVersions,
19
20
  NgioImageMeta,
20
21
  NgioLabelMeta,
21
22
  NgioPlateMeta,
22
23
  NgioWellMeta,
23
24
  PixelSize,
25
+ path_in_well_validation,
24
26
  )
25
27
 
26
28
  __all__ = [
@@ -31,6 +33,8 @@ __all__ = [
31
33
  "ImageMetaHandler",
32
34
  "LabelMetaHandler",
33
35
  "LabelMetaHandler",
36
+ "NgffVersions",
37
+ "NgffVersions",
34
38
  "NgioImageMeta",
35
39
  "NgioLabelMeta",
36
40
  "NgioPlateMeta",
@@ -44,4 +48,5 @@ __all__ = [
44
48
  "get_label_meta_handler",
45
49
  "get_plate_meta_handler",
46
50
  "get_well_meta_handler",
51
+ "path_in_well_validation",
47
52
  ]
@@ -15,6 +15,8 @@ from ngio.ome_zarr_meta.ngio_specs._axes import (
15
15
  AxesTranspose,
16
16
  Axis,
17
17
  AxisType,
18
+ DefaultSpaceUnit,
19
+ DefaultTimeUnit,
18
20
  SpaceUnits,
19
21
  TimeUnits,
20
22
  canonical_axes_order,
@@ -32,9 +34,12 @@ from ngio.ome_zarr_meta.ngio_specs._ngio_hcs import (
32
34
  ImageInWellPath,
33
35
  NgioPlateMeta,
34
36
  NgioWellMeta,
37
+ path_in_well_validation,
35
38
  )
36
39
  from ngio.ome_zarr_meta.ngio_specs._ngio_image import (
40
+ DefaultNgffVersion,
37
41
  ImageLabelSource,
42
+ NgffVersions,
38
43
  NgioImageLabelMeta,
39
44
  NgioImageMeta,
40
45
  NgioLabelMeta,
@@ -54,8 +59,12 @@ __all__ = [
54
59
  "ChannelVisualisation",
55
60
  "ChannelsMeta",
56
61
  "Dataset",
62
+ "DefaultNgffVersion",
63
+ "DefaultSpaceUnit",
64
+ "DefaultTimeUnit",
57
65
  "ImageInWellPath",
58
66
  "ImageLabelSource",
67
+ "NgffVersions",
59
68
  "NgioColors",
60
69
  "NgioImageLabelMeta",
61
70
  "NgioImageMeta",
@@ -68,4 +77,5 @@ __all__ = [
68
77
  "canonical_axes_order",
69
78
  "canonical_label_axes_order",
70
79
  "default_channel_name",
80
+ "path_in_well_validation",
71
81
  ]
@@ -3,7 +3,7 @@
3
3
  from collections.abc import Collection
4
4
  from enum import Enum
5
5
  from logging import Logger
6
- from typing import TypeVar
6
+ from typing import Literal, TypeVar
7
7
 
8
8
  import numpy as np
9
9
  from pydantic import BaseModel, ConfigDict, Field
@@ -32,98 +32,108 @@ class AxisType(str, Enum):
32
32
  space = "space"
33
33
 
34
34
 
35
- class SpaceUnits(str, Enum):
36
- """Allowed space units."""
37
-
38
- nanometer = "nanometer"
39
- nm = "nm"
40
- micrometer = "micrometer"
41
- um = "um"
42
- millimeter = "millimeter"
43
- mm = "mm"
44
- centimeter = "centimeter"
45
- cm = "cm"
46
-
47
- @classmethod
48
- def default(cls) -> "SpaceUnits":
49
- return SpaceUnits.um
50
-
51
-
52
- class TimeUnits(str, Enum):
53
- """Allowed time units."""
54
-
55
- seconds = "seconds"
56
- s = "s"
57
-
58
- @classmethod
59
- def default(cls) -> "TimeUnits":
60
- return TimeUnits.s
35
+ SpaceUnits = Literal[
36
+ "micrometer",
37
+ "nanometer",
38
+ "angstrom",
39
+ "picometer",
40
+ "millimeter",
41
+ "centimeter",
42
+ "decimeter",
43
+ "meter",
44
+ "inch",
45
+ "foot",
46
+ "yard",
47
+ "mile",
48
+ "kilometer",
49
+ "hectometer",
50
+ "megameter",
51
+ "gigameter",
52
+ "terameter",
53
+ "petameter",
54
+ "exameter",
55
+ "parsec",
56
+ "femtometer",
57
+ "attometer",
58
+ "zeptometer",
59
+ "yoctometer",
60
+ "zettameter",
61
+ "yottameter",
62
+ ]
63
+ DefaultSpaceUnit = "micrometer"
64
+
65
+ TimeUnits = Literal[
66
+ "attosecond",
67
+ "centisecond",
68
+ "day",
69
+ "decisecond",
70
+ "exasecond",
71
+ "femtosecond",
72
+ "gigasecond",
73
+ "hectosecond",
74
+ "hour",
75
+ "kilosecond",
76
+ "megasecond",
77
+ "microsecond",
78
+ "millisecond",
79
+ "minute",
80
+ "nanosecond",
81
+ "petasecond",
82
+ "picosecond",
83
+ "second",
84
+ "terasecond",
85
+ "yoctosecond",
86
+ "yottasecond",
87
+ "zeptosecond",
88
+ "zettasecond",
89
+ ]
90
+ DefaultTimeUnit = "second"
61
91
 
62
92
 
63
93
  class Axis(BaseModel):
64
94
  """Axis infos model."""
65
95
 
66
96
  on_disk_name: str
67
- unit: SpaceUnits | TimeUnits | None = None
97
+ unit: str | None = None
68
98
  axis_type: AxisType | None = None
69
99
 
70
100
  model_config = ConfigDict(extra="forbid", frozen=True)
71
101
 
72
102
  def implicit_type_cast(self, cast_type: AxisType) -> "Axis":
103
+ unit = self.unit
73
104
  if self.axis_type != cast_type:
74
105
  logger.warning(
75
106
  f"Axis {self.on_disk_name} has type {self.axis_type}. "
76
107
  f"Casting to {cast_type}."
77
108
  )
78
- new_axis = Axis(
79
- on_disk_name=self.on_disk_name, axis_type=cast_type, unit=self.unit
80
- )
81
- if cast_type == AxisType.time and not isinstance(self.unit, TimeUnits):
109
+
110
+ if cast_type == AxisType.time and unit is None:
82
111
  logger.warning(
83
112
  f"Time axis {self.on_disk_name} has unit {self.unit}. "
84
- f"Casting to {TimeUnits.default()}."
85
- )
86
- new_axis = Axis(
87
- on_disk_name=self.on_disk_name,
88
- axis_type=AxisType.time,
89
- unit=TimeUnits.default(),
90
- )
91
- elif cast_type == AxisType.space and not isinstance(self.unit, SpaceUnits):
92
- logger.warning(
93
- f"Space axis {self.on_disk_name} has unit {self.unit}. "
94
- f"Casting to {SpaceUnits.default()}."
113
+ f"Casting to {DefaultSpaceUnit}."
95
114
  )
96
- new_axis = Axis(
97
- on_disk_name=self.on_disk_name,
98
- axis_type=AxisType.space,
99
- unit=SpaceUnits.default(),
100
- )
101
- elif cast_type == AxisType.channel and self.unit is not None:
115
+ unit = DefaultTimeUnit
116
+
117
+ if cast_type == AxisType.space and unit is None:
102
118
  logger.warning(
103
- f"Channel axis {self.on_disk_name} has unit {self.unit}. Removing unit."
104
- )
105
- new_axis = Axis(
106
- on_disk_name=self.on_disk_name,
107
- axis_type=AxisType.channel,
108
- unit=None,
119
+ f"Space axis {self.on_disk_name} has unit {unit}. "
120
+ f"Casting to {DefaultSpaceUnit}."
109
121
  )
110
- return new_axis
122
+ unit = DefaultSpaceUnit
123
+
124
+ return Axis(on_disk_name=self.on_disk_name, axis_type=cast_type, unit=unit)
111
125
 
112
126
  def canonical_axis_cast(self, canonical_name: str) -> "Axis":
113
127
  """Cast the implicit axis to the correct type."""
114
128
  match canonical_name:
115
129
  case "t":
116
- if self.axis_type != AxisType.time or not isinstance(
117
- self.unit, TimeUnits
118
- ):
130
+ if self.axis_type != AxisType.time or self.unit is None:
119
131
  return self.implicit_type_cast(AxisType.time)
120
132
  case "c":
121
- if self.axis_type != AxisType.channel or self.unit is not None:
133
+ if self.axis_type != AxisType.channel:
122
134
  return self.implicit_type_cast(AxisType.channel)
123
135
  case "z" | "y" | "x":
124
- if self.axis_type != AxisType.space or not isinstance(
125
- self.unit, SpaceUnits
126
- ):
136
+ if self.axis_type != AxisType.space or self.unit is None:
127
137
  return self.implicit_type_cast(AxisType.space)
128
138
  return self
129
139
 
@@ -345,6 +355,11 @@ class AxesMapper:
345
355
  _index_mapping[canonical_key] = None
346
356
  return _index_mapping
347
357
 
358
+ @property
359
+ def axes_setup(self) -> AxesSetup:
360
+ """Return the axes setup."""
361
+ return self._axes_setup
362
+
348
363
  @property
349
364
  def on_disk_axes(self) -> list[Axis]:
350
365
  return list(self._on_disk_axes)
@@ -353,6 +368,16 @@ class AxesMapper:
353
368
  def on_disk_axes_names(self) -> list[str]:
354
369
  return [ax.on_disk_name for ax in self._on_disk_axes]
355
370
 
371
+ @property
372
+ def allow_non_canonical_axes(self) -> bool:
373
+ """Return if non canonical axes are allowed."""
374
+ return self._allow_non_canonical_axes
375
+
376
+ @property
377
+ def strict_canonical_order(self) -> bool:
378
+ """Return if strict canonical order is enforced."""
379
+ return self._strict_canonical_order
380
+
356
381
  def get_index(self, name: str) -> int | None:
357
382
  """Get the index of the axis by name."""
358
383
  if name not in self._index_mapping.keys():
@@ -443,8 +468,8 @@ class AxesMapper:
443
468
 
444
469
  def canonical_axes(
445
470
  axes_names: Collection[str],
446
- space_units: SpaceUnits | None = None,
447
- time_units: TimeUnits | None = None,
471
+ space_units: SpaceUnits | None = DefaultSpaceUnit,
472
+ time_units: TimeUnits | None = DefaultTimeUnit,
448
473
  ) -> list[Axis]:
449
474
  """Create a new canonical axes mapper.
450
475