Skip to content

Commit

Permalink
Fix Labels.data_setitem setting of view by taking dims order into a…
Browse files Browse the repository at this point in the history
…ccount (#6616)

# References and relevant issues

closes #6615

# Description

In #6607, we started painting into both the data and the slice view.
(And this was already happening and broken when painting into lazy
arrays such as zarr and dask, #6112.) However, when setting the view we
need to take into account the axis ordering used when slicing (some axes
may be transposed). This manifested as an index error in #6615.

In this PR, we add an `indices_order` argument to `index_in_slice`
function and the function returns indices in the requested order, which
we can then use to set the view.
  • Loading branch information
Czaki committed Jan 24, 2024
1 parent 6ea5950 commit 0be7f18
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 7 deletions.
11 changes: 10 additions & 1 deletion napari/layers/labels/_tests/test_labels.py
Expand Up @@ -705,6 +705,15 @@ def test_data_setitem_multi_dim():
)


def test_data_setitiem_transposed_axes():
data = np.zeros((10, 100), dtype=np.uint32)
labels = Labels(data)
dims = Dims(ndim=2, ndisplay=2, order=(1, 0))
labels.data_setitem((np.array([9]), np.array([99])), 1)
labels._slice_dims(dims)
labels.data_setitem((np.array([9]), np.array([99])), 2)


def test_selecting_label():
"""Test selecting label."""
np.random.seed(0)
Expand Down Expand Up @@ -831,7 +840,7 @@ def test_paint_2d():


def test_paint_2d_xarray():
"""Test the memory usage of painting an xarray indirectly via timeout."""
"""Test the memory usage of painting a xarray indirectly via timeout."""
now = time.monotonic()
data = xr.DataArray(np.zeros((3, 3, 1024, 1024), dtype=np.uint32))

Expand Down
4 changes: 3 additions & 1 deletion napari/layers/labels/labels.py
Expand Up @@ -1593,7 +1593,9 @@ def data_setitem(self, indices, value, refresh=True):
self.data[indices] = value

pt_not_disp = self._get_pt_not_disp()
displayed_indices = index_in_slice(indices, pt_not_disp)
displayed_indices = index_in_slice(
indices, pt_not_disp, self._slice.slice_input.order
)
if isinstance(value, np.ndarray):
visible_values = value[elements_in_slice(indices, pt_not_disp)]
else:
Expand Down
14 changes: 9 additions & 5 deletions napari/utils/_indexing.py
Expand Up @@ -35,7 +35,9 @@ def elements_in_slice(


def index_in_slice(
index: Tuple[npt.NDArray[np.int_], ...], position_in_axes: Dict[int, int]
index: Tuple[npt.NDArray[np.int_], ...],
position_in_axes: Dict[int, int],
indices_order: Tuple[int, ...],
) -> Tuple[npt.NDArray[np.int_], ...]:
"""Convert a NumPy fancy indexing expression from data to sliced space.
Expand All @@ -45,6 +47,8 @@ def index_in_slice(
A NumPy fancy indexing expression [1]_.
position_in_axes : dict[int, int]
A dictionary mapping sliced (non-displayed) axes to a slice position.
indices_order : tuple of int
The order of the indices in data view.
Returns
-------
Expand All @@ -55,9 +59,9 @@ def index_in_slice(
Examples
--------
>>> index = (np.arange(5), np.full(5, 1), np.arange(4, 9))
>>> index_in_slice(index, {0: 3})
>>> index_in_slice(index, {0: 3}, (0, 1, 2))
(array([1]), array([7]))
>>> index_in_slice(index, {1: 1, 2: 8})
>>> index_in_slice(index, {1: 1, 2: 8}, (0, 1, 2))
(array([4]),)
References
Expand All @@ -66,7 +70,7 @@ def index_in_slice(
"""
index_in_slice = elements_in_slice(index, position_in_axes)
return tuple(
ix[index_in_slice]
for i, ix in enumerate(index)
index[i][index_in_slice]
for i in indices_order
if i not in position_in_axes
)

0 comments on commit 0be7f18

Please sign in to comment.