ngio 0.5.0__py3-none-any.whl → 0.5.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ngio/__init__.py +2 -5
- ngio/common/__init__.py +6 -11
- ngio/common/_masking_roi.py +54 -34
- ngio/common/_pyramid.py +85 -309
- ngio/common/_roi.py +330 -258
- ngio/experimental/iterators/_feature.py +3 -3
- ngio/experimental/iterators/_rois_utils.py +11 -10
- ngio/hcs/_plate.py +60 -132
- ngio/images/_abstract_image.py +35 -539
- ngio/images/_create.py +287 -0
- ngio/images/_create_synt_container.py +42 -39
- ngio/images/_image.py +250 -516
- ngio/images/_label.py +172 -249
- ngio/images/_masked_image.py +2 -2
- ngio/images/_ome_zarr_container.py +241 -644
- ngio/io_pipes/_io_pipes.py +9 -9
- ngio/io_pipes/_io_pipes_masked.py +7 -7
- ngio/io_pipes/_io_pipes_roi.py +6 -6
- ngio/io_pipes/_io_pipes_types.py +3 -3
- ngio/io_pipes/_match_shape.py +8 -6
- ngio/io_pipes/_ops_slices_utils.py +5 -8
- ngio/ome_zarr_meta/__init__.py +18 -29
- ngio/ome_zarr_meta/_meta_handlers.py +708 -392
- ngio/ome_zarr_meta/ngio_specs/__init__.py +0 -4
- ngio/ome_zarr_meta/ngio_specs/_axes.py +51 -152
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +22 -13
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +91 -129
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +68 -57
- ngio/ome_zarr_meta/v04/__init__.py +1 -5
- ngio/ome_zarr_meta/v04/{_v04_spec.py → _v04_spec_utils.py} +85 -54
- ngio/ome_zarr_meta/v05/__init__.py +1 -5
- ngio/ome_zarr_meta/v05/{_v05_spec.py → _v05_spec_utils.py} +87 -64
- ngio/resources/__init__.py +1 -1
- ngio/resources/resource_model.py +1 -1
- ngio/tables/_tables_container.py +11 -62
- ngio/tables/backends/_anndata.py +8 -58
- ngio/tables/backends/_anndata_utils.py +6 -1
- ngio/tables/backends/_csv.py +19 -3
- ngio/tables/backends/_json.py +13 -10
- ngio/tables/backends/_non_zarr_backends.py +196 -0
- ngio/tables/backends/_parquet.py +31 -3
- ngio/tables/v1/_roi_table.py +24 -41
- ngio/utils/__init__.py +12 -6
- ngio/utils/_datasets.py +0 -6
- ngio/utils/_logger.py +50 -0
- ngio/utils/_zarr_utils.py +58 -167
- {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/METADATA +4 -11
- ngio-0.5.0a2.dist-info/RECORD +89 -0
- {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/WHEEL +1 -1
- ngio/images/_create_utils.py +0 -406
- ngio/tables/backends/_py_arrow_backends.py +0 -222
- ngio-0.5.0.dist-info/RECORD +0 -88
- {ngio-0.5.0.dist-info → ngio-0.5.0a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,7 +15,6 @@ from ngio.ome_zarr_meta.ngio_specs._axes import (
|
|
|
15
15
|
DefaultTimeUnit,
|
|
16
16
|
SpaceUnits,
|
|
17
17
|
TimeUnits,
|
|
18
|
-
build_axes_handler,
|
|
19
18
|
build_canonical_axes_handler,
|
|
20
19
|
canonical_axes_order,
|
|
21
20
|
canonical_label_axes_order,
|
|
@@ -41,7 +40,6 @@ from ngio.ome_zarr_meta.ngio_specs._ngio_image import (
|
|
|
41
40
|
NgioImageLabelMeta,
|
|
42
41
|
NgioImageMeta,
|
|
43
42
|
NgioLabelMeta,
|
|
44
|
-
NgioLabelsGroupMeta,
|
|
45
43
|
)
|
|
46
44
|
from ngio.ome_zarr_meta.ngio_specs._pixel_size import PixelSize
|
|
47
45
|
|
|
@@ -64,13 +62,11 @@ __all__ = [
|
|
|
64
62
|
"NgioImageLabelMeta",
|
|
65
63
|
"NgioImageMeta",
|
|
66
64
|
"NgioLabelMeta",
|
|
67
|
-
"NgioLabelsGroupMeta",
|
|
68
65
|
"NgioPlateMeta",
|
|
69
66
|
"NgioWellMeta",
|
|
70
67
|
"PixelSize",
|
|
71
68
|
"SpaceUnits",
|
|
72
69
|
"TimeUnits",
|
|
73
|
-
"build_axes_handler",
|
|
74
70
|
"build_canonical_axes_handler",
|
|
75
71
|
"canonical_axes_order",
|
|
76
72
|
"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
|
|
8
8
|
|
|
9
9
|
from ngio.utils import NgioValidationError, NgioValueError
|
|
10
10
|
|
|
@@ -153,51 +153,9 @@ 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
|
|
158
156
|
|
|
159
157
|
model_config = ConfigDict(extra="forbid", frozen=True)
|
|
160
158
|
|
|
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
|
-
|
|
201
159
|
def canonical_map(self) -> dict[str, str]:
|
|
202
160
|
"""Get the canonical map of axes."""
|
|
203
161
|
return {
|
|
@@ -239,9 +197,9 @@ def _check_unique_names(axes: Sequence[Axis]):
|
|
|
239
197
|
)
|
|
240
198
|
|
|
241
199
|
|
|
242
|
-
def _check_non_canonical_axes(axes_setup: AxesSetup):
|
|
200
|
+
def _check_non_canonical_axes(axes_setup: AxesSetup, allow_non_canonical_axes: bool):
|
|
243
201
|
"""Check if all axes are known."""
|
|
244
|
-
if not
|
|
202
|
+
if not allow_non_canonical_axes and len(axes_setup.others) > 0:
|
|
245
203
|
raise NgioValidationError(
|
|
246
204
|
f"Unknown axes {axes_setup.others}. Please set "
|
|
247
205
|
"`allow_non_canonical_axes=True` to ignore them"
|
|
@@ -261,9 +219,11 @@ def _check_axes_validity(axes: Sequence[Axis], axes_setup: AxesSetup):
|
|
|
261
219
|
)
|
|
262
220
|
|
|
263
221
|
|
|
264
|
-
def _check_canonical_order(
|
|
222
|
+
def _check_canonical_order(
|
|
223
|
+
axes: Sequence[Axis], axes_setup: AxesSetup, strict_canonical_order: bool
|
|
224
|
+
):
|
|
265
225
|
"""Check if the axes are in the canonical order."""
|
|
266
|
-
if not
|
|
226
|
+
if not strict_canonical_order:
|
|
267
227
|
return
|
|
268
228
|
_names = [ax.name for ax in axes]
|
|
269
229
|
_canonical_order = []
|
|
@@ -282,18 +242,24 @@ def _check_canonical_order(axes: Sequence[Axis], axes_setup: AxesSetup):
|
|
|
282
242
|
def validate_axes(
|
|
283
243
|
axes: Sequence[Axis],
|
|
284
244
|
axes_setup: AxesSetup,
|
|
245
|
+
allow_non_canonical_axes: bool = False,
|
|
246
|
+
strict_canonical_order: bool = False,
|
|
285
247
|
) -> None:
|
|
286
248
|
"""Validate the axes."""
|
|
287
|
-
if
|
|
288
|
-
raise
|
|
249
|
+
if allow_non_canonical_axes and strict_canonical_order:
|
|
250
|
+
raise NgioValidationError(
|
|
289
251
|
"`allow_non_canonical_axes` and"
|
|
290
252
|
"`strict_canonical_order` cannot be true at the same time."
|
|
291
253
|
"If non canonical axes are allowed, the order cannot be checked."
|
|
292
254
|
)
|
|
293
255
|
_check_unique_names(axes=axes)
|
|
294
|
-
_check_non_canonical_axes(
|
|
256
|
+
_check_non_canonical_axes(
|
|
257
|
+
axes_setup=axes_setup, allow_non_canonical_axes=allow_non_canonical_axes
|
|
258
|
+
)
|
|
295
259
|
_check_axes_validity(axes=axes, axes_setup=axes_setup)
|
|
296
|
-
_check_canonical_order(
|
|
260
|
+
_check_canonical_order(
|
|
261
|
+
axes=axes, axes_setup=axes_setup, strict_canonical_order=strict_canonical_order
|
|
262
|
+
)
|
|
297
263
|
|
|
298
264
|
|
|
299
265
|
class AxesHandler:
|
|
@@ -312,22 +278,29 @@ class AxesHandler:
|
|
|
312
278
|
axes: Sequence[Axis],
|
|
313
279
|
# user defined args
|
|
314
280
|
axes_setup: AxesSetup | None = None,
|
|
281
|
+
allow_non_canonical_axes: bool = False,
|
|
282
|
+
strict_canonical_order: bool = False,
|
|
315
283
|
):
|
|
316
284
|
"""Create a new AxesMapper object.
|
|
317
285
|
|
|
318
286
|
Args:
|
|
319
287
|
axes (list[Axis]): The axes on disk.
|
|
320
288
|
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.
|
|
321
292
|
"""
|
|
322
293
|
axes_setup = axes_setup if axes_setup is not None else AxesSetup()
|
|
323
294
|
|
|
324
295
|
validate_axes(
|
|
325
296
|
axes=axes,
|
|
326
297
|
axes_setup=axes_setup,
|
|
298
|
+
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
299
|
+
strict_canonical_order=strict_canonical_order,
|
|
327
300
|
)
|
|
328
301
|
|
|
329
|
-
self._allow_non_canonical_axes =
|
|
330
|
-
self._strict_canonical_order =
|
|
302
|
+
self._allow_non_canonical_axes = allow_non_canonical_axes
|
|
303
|
+
self._strict_canonical_order = strict_canonical_order
|
|
331
304
|
|
|
332
305
|
self._canonical_order = canonical_axes_order()
|
|
333
306
|
|
|
@@ -379,7 +352,6 @@ class AxesHandler:
|
|
|
379
352
|
|
|
380
353
|
@property
|
|
381
354
|
def axes_names(self) -> tuple[str, ...]:
|
|
382
|
-
"""On disk axes names."""
|
|
383
355
|
return tuple(ax.name for ax in self._axes)
|
|
384
356
|
|
|
385
357
|
@property
|
|
@@ -449,48 +421,8 @@ class AxesHandler:
|
|
|
449
421
|
return AxesHandler(
|
|
450
422
|
axes=new_axes,
|
|
451
423
|
axes_setup=self.axes_setup,
|
|
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,
|
|
424
|
+
allow_non_canonical_axes=self.allow_non_canonical_axes,
|
|
425
|
+
strict_canonical_order=self.strict_canonical_order,
|
|
494
426
|
)
|
|
495
427
|
|
|
496
428
|
def get_index(self, name: str) -> int | None:
|
|
@@ -532,33 +464,14 @@ class AxesHandler:
|
|
|
532
464
|
self._axes = new_axes
|
|
533
465
|
|
|
534
466
|
|
|
535
|
-
def _build_axes_list_from_names(
|
|
536
|
-
axes_names: Sequence[str],
|
|
537
|
-
axes_setup: AxesSetup,
|
|
538
|
-
space_units: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
539
|
-
time_units: 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_units))
|
|
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_units))
|
|
552
|
-
case _:
|
|
553
|
-
axes.append(Axis(name=name, axis_type=AxisType.space))
|
|
554
|
-
return axes
|
|
555
|
-
|
|
556
|
-
|
|
557
467
|
def build_canonical_axes_handler(
|
|
558
468
|
axes_names: Sequence[str],
|
|
559
|
-
canonical_channel_order: Sequence[str] | None = None,
|
|
560
469
|
space_units: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
561
470
|
time_units: TimeUnits | str | None = DefaultTimeUnit,
|
|
471
|
+
# user defined args
|
|
472
|
+
axes_setup: AxesSetup | None = None,
|
|
473
|
+
allow_non_canonical_axes: bool = False,
|
|
474
|
+
strict_canonical_order: bool = False,
|
|
562
475
|
) -> AxesHandler:
|
|
563
476
|
"""Create a new canonical axes mapper.
|
|
564
477
|
|
|
@@ -569,47 +482,33 @@ def build_canonical_axes_handler(
|
|
|
569
482
|
- If an integer is provided, the axes are created from the last axis
|
|
570
483
|
to the first
|
|
571
484
|
e.g. 3 -> ["z", "y", "x"]
|
|
572
|
-
canonical_channel_order (Sequence[str], optional): The canonical channel
|
|
573
|
-
order. Defaults to None, which uses the default order.
|
|
574
485
|
space_units (SpaceUnits, optional): The space units. Defaults to None.
|
|
575
486
|
time_units (TimeUnits, optional): The time units. Defaults to None.
|
|
576
|
-
"""
|
|
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_units=space_units,
|
|
586
|
-
time_units=time_units,
|
|
587
|
-
)
|
|
588
|
-
return AxesHandler(
|
|
589
|
-
axes=axes,
|
|
590
|
-
axes_setup=axes_setup,
|
|
591
|
-
)
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
def build_axes_handler(
|
|
595
|
-
axes_names: Sequence[str],
|
|
596
|
-
axes_setup: AxesSetup | None = None,
|
|
597
|
-
) -> AxesHandler:
|
|
598
|
-
"""Create a new axes mapper.
|
|
599
|
-
|
|
600
|
-
Args:
|
|
601
|
-
axes_names (Sequence[str]): The axes names on disk.
|
|
602
487
|
axes_setup (AxesSetup, optional): The axis setup. Defaults to None.
|
|
603
488
|
allow_non_canonical_axes (bool, optional): Allow non canonical axes.
|
|
489
|
+
Defaults to False.
|
|
604
490
|
strict_canonical_order (bool, optional): Check if the axes are in the
|
|
605
491
|
canonical order. Defaults to False.
|
|
492
|
+
|
|
606
493
|
"""
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
494
|
+
axes = []
|
|
495
|
+
for name in axes_names:
|
|
496
|
+
match name:
|
|
497
|
+
case "t":
|
|
498
|
+
axes.append(Axis(name=name, axis_type=AxisType.time, unit=time_units))
|
|
499
|
+
case "c":
|
|
500
|
+
axes.append(Axis(name=name, axis_type=AxisType.channel))
|
|
501
|
+
case "z" | "y" | "x":
|
|
502
|
+
axes.append(Axis(name=name, axis_type=AxisType.space, unit=space_units))
|
|
503
|
+
case _:
|
|
504
|
+
raise NgioValueError(
|
|
505
|
+
f"Invalid axis name '{name}'. "
|
|
506
|
+
"Only 't', 'c', 'z', 'y', 'x' are allowed."
|
|
507
|
+
)
|
|
508
|
+
|
|
612
509
|
return AxesHandler(
|
|
613
510
|
axes=axes,
|
|
614
511
|
axes_setup=axes_setup,
|
|
512
|
+
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
513
|
+
strict_canonical_order=strict_canonical_order,
|
|
615
514
|
)
|
|
@@ -60,20 +60,11 @@ class Dataset:
|
|
|
60
60
|
@property
|
|
61
61
|
def pixel_size(self) -> PixelSize:
|
|
62
62
|
"""Return the pixel size for the dataset."""
|
|
63
|
-
scale = self._scale
|
|
64
|
-
pix_size_dict = {}
|
|
65
|
-
# Mandatory axes: x, y
|
|
66
|
-
for ax in ["x", "y"]:
|
|
67
|
-
index = self.axes_handler.get_index(ax)
|
|
68
|
-
assert index is not None
|
|
69
|
-
pix_size_dict[ax] = scale[index]
|
|
70
|
-
|
|
71
|
-
for ax in ["z", "t"]:
|
|
72
|
-
index = self.axes_handler.get_index(ax)
|
|
73
|
-
pix_size_dict[ax] = scale[index] if index is not None else 1.0
|
|
74
|
-
|
|
75
63
|
return PixelSize(
|
|
76
|
-
|
|
64
|
+
x=self.get_scale("x", default=1.0),
|
|
65
|
+
y=self.get_scale("y", default=1.0),
|
|
66
|
+
z=self.get_scale("z", default=1.0),
|
|
67
|
+
t=self.get_scale("t", default=1.0),
|
|
77
68
|
space_unit=self.axes_handler.space_unit,
|
|
78
69
|
time_unit=self.axes_handler.time_unit,
|
|
79
70
|
)
|
|
@@ -87,3 +78,21 @@ class Dataset:
|
|
|
87
78
|
def translation(self) -> tuple[float, ...]:
|
|
88
79
|
"""Return the translation as a tuple."""
|
|
89
80
|
return tuple(self._translation)
|
|
81
|
+
|
|
82
|
+
def get_scale(self, axis_name: str, default: float | None = None) -> float:
|
|
83
|
+
"""Return the scale for a given axis."""
|
|
84
|
+
idx = self.axes_handler.get_index(axis_name)
|
|
85
|
+
if idx is None:
|
|
86
|
+
if default is not None:
|
|
87
|
+
return default
|
|
88
|
+
raise ValueError(f"Axis {axis_name} not found in axes {self.axes_handler}.")
|
|
89
|
+
return self._scale[idx]
|
|
90
|
+
|
|
91
|
+
def get_translation(self, axis_name: str, default: float | None = None) -> float:
|
|
92
|
+
"""Return the translation for a given axis."""
|
|
93
|
+
idx = self.axes_handler.get_index(axis_name)
|
|
94
|
+
if idx is None:
|
|
95
|
+
if default is not None:
|
|
96
|
+
return default
|
|
97
|
+
raise ValueError(f"Axis {axis_name} not found in axes {self.axes_handler}.")
|
|
98
|
+
return self._translation[idx]
|