Skip to content
This repository was archived by the owner on Dec 1, 2025. It is now read-only.

Commit e144273

Browse files
authored
bugfix/convert-dimension-spec-lists-to-slices-when-possible (#429)
* try to convert list to slice when possible * add some tests * allow tuples in utility function * update typing for test function
1 parent d94ccb4 commit e144273

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

aicsimageio/tests/test_transforms.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
from aicsimageio import AICSImage, types
1414
from aicsimageio.exceptions import ConflictingArgumentsError, UnexpectedShapeError
1515
from aicsimageio.readers import ArrayLikeReader
16-
from aicsimageio.transforms import generate_stack, reshape_data, transpose_to_dims
16+
from aicsimageio.transforms import (
17+
generate_stack,
18+
reduce_to_slice,
19+
reshape_data,
20+
transpose_to_dims,
21+
)
1722

1823

1924
@pytest.mark.parametrize("array_maker", [np.zeros, da.zeros])
@@ -523,3 +528,26 @@ def test_generate_stack_mismatch_and_drop(
523528
xr.testing.assert_allclose(stack, reference)
524529
else:
525530
np.testing.assert_allclose(stack, reference)
531+
532+
533+
@pytest.mark.parametrize(
534+
"list_to_test, expected",
535+
[
536+
([0], 0),
537+
([0, 1], slice(0, 2, 1)),
538+
([1, 0], [1, 0]),
539+
([3, 5], slice(3, 6, 2)),
540+
([8, 9, 11], [8, 9, 11]),
541+
([15, 20, 25], slice(15, 26, 5)),
542+
((0,), 0),
543+
((0, 1), slice(0, 2, 1)),
544+
((1, 0), (1, 0)),
545+
((3, 5), slice(3, 6, 2)),
546+
((8, 9, 11), (8, 9, 11)),
547+
((15, 20, 25), slice(15, 26, 5)),
548+
],
549+
)
550+
def test_convert_list_to_slice(
551+
list_to_test: Union[List, Tuple], expected: Union[int, List, slice, Tuple]
552+
) -> None:
553+
assert reduce_to_slice(list_to_test) == expected

aicsimageio/transforms.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from collections import Counter
6-
from typing import Any, Literal, Optional, Union
6+
from typing import Any, List, Literal, Optional, Tuple, Union
77

88
import dask.array as da
99
import numpy as np
@@ -16,6 +16,22 @@
1616
###############################################################################
1717

1818

19+
def reduce_to_slice(L: Union[List, Tuple]) -> Union[int, List, slice, Tuple]:
20+
# if the list only has one element, then just use it
21+
if len(L) == 1:
22+
return L[0]
23+
# if the list has at least 2 elements we can check for sliceable
24+
# it is convertable to a slice if the step size between each
25+
# consecutive pair of elements is equal and positive
26+
# 1. get all the deltas in a list:
27+
steps = [(L[i + 1] - L[i]) for i in range(len(L) - 1)]
28+
# 2. check if all the deltas are equal and positive
29+
if steps[0] > 0 and steps.count(steps[0]) == len(steps):
30+
return slice(min(L), max(L) + 1, steps[0])
31+
# if we can't convert to a slice, then just return the list unmodified
32+
return L
33+
34+
1935
def transpose_to_dims(
2036
data: types.ArrayLike,
2137
given_dims: str,
@@ -208,6 +224,8 @@ def reshape_data(
208224
# Get the largest absolute value index in the list using min and max
209225
if isinstance(dim_spec, list):
210226
check_selection_max = max([abs(min(dim_spec)), max(dim_spec)])
227+
# try to convert to slice if possible
228+
dim_spec = reduce_to_slice(dim_spec)
211229

212230
# Get the largest absolute value index from start and stop of slice
213231
if isinstance(dim_spec, slice):

0 commit comments

Comments
 (0)