From 0cfe84f53163f66313e6b6f99484d3dd97cece46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Weber?= Date: Thu, 3 Jul 2025 13:25:04 +0200 Subject: [PATCH 1/2] modifying Axis.find_index to allow slicing by quantity and tests --- src/pymodaq_data/data.py | 10 ++++++---- tests/data_test.py | 14 ++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/pymodaq_data/data.py b/src/pymodaq_data/data.py index 51e6e3cd..d1bcb812 100644 --- a/src/pymodaq_data/data.py +++ b/src/pymodaq_data/data.py @@ -166,7 +166,7 @@ class DataDistribution(BaseEnum): def _compute_slices_from_axis(axis: Axis, _slice, *ignored, is_index=True, **ignored_also): if not is_index: - if isinstance(_slice, numbers.Number): + if isinstance(_slice, numbers.Number) or isinstance(_slice, Q_): if not is_index: _slice = axis.find_index(_slice) elif _slice is Ellipsis: @@ -599,8 +599,10 @@ def max(self): else: return self.offset + (self.size * self.scaling if self.scaling > 0 else 0) - def find_index(self, threshold: float) -> int: + def find_index(self, threshold: Union[float, Q_]) -> int: """find the index of the threshold value within the axis""" + if isinstance(threshold, Q_): + threshold = threshold.m_as(self.units) if threshold < self.min(): return 0 elif threshold > self.max(): @@ -610,7 +612,7 @@ def find_index(self, threshold: float) -> int: else: return int((threshold - self.offset) / self.scaling) - def find_indexes(self, thresholds: IterableType[float]) -> IterableType[int]: + def find_indexes(self, thresholds: IterableType[Union[float, Q_]]) -> IterableType[int]: if isinstance(thresholds, numbers.Number): thresholds = [thresholds] return [self.find_index(threshold) for threshold in thresholds] @@ -2625,7 +2627,7 @@ def _slicer(self, slices, is_navigation=True, is_index=True): is_navigation: bool if True apply the slices to the navigation dimension else to the signal ones is_index: bool - if True the slices are indexes otherwise the slices are axes values to be indexed first + if True the slices are indexes otherwise the slices are axes values (float or quantities) to be indexed first Returns ------- diff --git a/tests/data_test.py b/tests/data_test.py index 9f0b83a8..7305b446 100644 --- a/tests/data_test.py +++ b/tests/data_test.py @@ -16,16 +16,16 @@ from pymodaq_utils import math_utils as mutils from pymodaq_utils.units import nm2eV, eV2nm from pymodaq_data import data as data_mod -from pymodaq_data.data import DataDim +from pymodaq_data.data import DataDim, Q_ from pymodaq_data.post_treatment.process_to_scalar import DataProcessorFactory data_processors = DataProcessorFactory() LABEL = 'A Label' -UNITS = 'units' +UNITS = 'mm' OFFSET = -20.4 -SCALING = 0.22 -SIZE = 20 +SCALING = 1.33 +SIZE = 1024 DATA = OFFSET + SCALING * np.linspace(0, SIZE-1, SIZE) DATA0D = np.array([2.7]) @@ -263,10 +263,15 @@ def test_slice_getter(self, init_axis_fixt): sliced_axis_value = ax.vaxis[ax.get_data()[ind_start]:ax.get_data()[ind_end]] assert sliced_axis == sliced_axis_value + assert ax.vaxis[0.3:1000.] == ax.vaxis[Q_(300, 'um'):Q_(1, 'm')] + ind_int = 3 int_axis = ax.iaxis[ind_int] int_axis_value = ax.vaxis[ax.get_data()[ind_int]] + threshold = Q_(0.5, 'm') + assert ax.vaxis[threshold] == ax.vaxis[threshold.m_as(ax.units)] + assert isinstance(int_axis, data_mod.Axis) assert len(int_axis) == 1 assert int_axis.get_data()[0] == ax.get_data()[ind_int] @@ -277,6 +282,7 @@ def test_slice_getter(self, init_axis_fixt): assert sliced_axis is not None assert len(sliced_axis) == len(ax) - neg_index - ind_start + def test_slice_setter(self, init_axis_fixt): ax = init_axis_fixt length = len(ax) From e87b5e207214c1940aa94478cc04e8311c48ac0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Weber?= Date: Thu, 3 Jul 2025 17:38:32 +0200 Subject: [PATCH 2/2] allowing value slicing of DataWithAxes objects --- src/pymodaq_data/data.py | 4 ++-- tests/data_test.py | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/pymodaq_data/data.py b/src/pymodaq_data/data.py index d1bcb812..ec231960 100644 --- a/src/pymodaq_data/data.py +++ b/src/pymodaq_data/data.py @@ -2573,7 +2573,7 @@ def _compute_slices(self, slices, is_navigation=True, is_index=True): list(slice): a version as index of the input argument """ _slices_as_index = [] - if isinstance(slices, numbers.Number) or isinstance(slices, slice): + if isinstance(slices, numbers.Number) or isinstance(slices, Q_) or isinstance(slices, slice): slices = [slices] if is_navigation: indexes = self._am.nav_indexes @@ -2607,7 +2607,7 @@ def _compute_slices(self, slices, is_navigation=True, is_index=True): total_slices = tuple(total_slices) return total_slices, _slices_as_index - def check_squeeze(self, total_slices: List[slice], is_navigation: bool): + def check_squeeze(self, total_slices: IterableType[slice], is_navigation: bool): do_squeeze = True if 1 in self.data[0][total_slices].shape: diff --git a/tests/data_test.py b/tests/data_test.py index 7305b446..64828b99 100644 --- a/tests/data_test.py +++ b/tests/data_test.py @@ -1042,10 +1042,24 @@ def test_slice_signal(self, init_data_uniform): assert len(data_1.axes) == 2 assert data_1.nav_indexes == (0, 1) - data_2: data_mod.DataWithAxes = data_raw.isig[0:3, 2:4] - assert data_2.shape == (Nn0, Nn1, 3, 2) - assert data_2.get_axis_from_index(2)[0].size == 3 - assert data_2.get_axis_from_index(3)[0].size == 2 + + isig2_min = 0 + isig3_min = 2 + isig2_max = 3 + isig3_max = 4 + + data_2: data_mod.DataWithAxes = data_raw.isig[isig2_min:isig2_max, isig3_min:isig3_max] + + axis_2_values = data_raw.get_axis_from_index(data_raw.sig_indexes[0])[0].get_data()[isig2_min:isig2_max+1] + axis_3_values = data_raw.get_axis_from_index(data_raw.sig_indexes[1])[0].get_data()[isig3_min:isig3_max+1] + + data_2_vsliced = data_raw.vsig[min(axis_2_values):max(axis_2_values), + min(axis_3_values):max(axis_3_values)] + assert data_2 == data_2_vsliced + + assert data_2.shape == (Nn0, Nn1, isig2_max-isig2_min, isig3_max-isig3_min) + assert data_2.get_axis_from_index(2)[0].size == isig2_max-isig2_min + assert data_2.get_axis_from_index(3)[0].size == isig3_max-isig3_min data_3: data_mod.DataWithAxes = data_raw.isig[0:3, :-1] assert data_3.shape == (Nn0, Nn1, 3, Ndata1-1)