Skip to content

Commit b4ea1a9

Browse files
m-albertLucaMarconatoCopilot
authored
When transforming DataTree elements, discard scales resulting in zero shape (#948)
* Add test showing that DataTree transform fails when transformed scales have zero shape * Handle resulting scales of shape zero in DataTree transform and make associated test pass * Make test name more specific * Update tests/core/operations/test_transform.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/spatialdata/_core/operations/transform.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * tiny improvements --------- Co-authored-by: Luca Marconato <m.lucalmer@gmail.com> Co-authored-by: LucaMarconato <2664412+LucaMarconato@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 2794fb0 commit b4ea1a9

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

src/spatialdata/_core/operations/transform.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,18 @@ def _(
381381
transformed_dask, raster_translation_single_scale = _transform_raster(
382382
data=xdata.data, axes=xdata.dims, transformation=composed, **kwargs
383383
)
384+
385+
# if a scale in the transformed data has zero shape, we skip it
386+
if 0 in transformed_dask.shape:
387+
if k == "scale0":
388+
raise ValueError(
389+
"The transformation leads to zero shaped data even at the highest resolution level. "
390+
"Check the scaling component of the transformation."
391+
)
392+
# no risk of skipping a scale (e.g. scale1) but not the next ones (e.g. scale2), because once a scale
393+
# is skipped, all the lower scales are also skipped
394+
continue
395+
384396
if raster_translation is None:
385397
raster_translation = raster_translation_single_scale
386398
# we set a dummy empty dict for the transformation that will be replaced with the correct transformation for

tests/core/operations/test_transform.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from spatialdata._core.data_extent import are_extents_equal, get_extent
1212
from spatialdata._core.spatialdata import SpatialData
1313
from spatialdata._utils import unpad_raster
14-
from spatialdata.models import PointsModel, ShapesModel, get_axes_names
14+
from spatialdata.models import Image2DModel, PointsModel, ShapesModel, get_axes_names
1515
from spatialdata.transformations.operations import (
1616
align_elements_using_landmarks,
1717
get_transformation,
@@ -229,6 +229,37 @@ def test_transform_shapes(shapes: SpatialData):
229229
assert geom_almost_equals(p0["geometry"], p1["geometry"])
230230

231231

232+
def test_transform_datatree_scale_handling():
233+
"""
234+
Test the cases in which the lowest and highest scale of the result of a
235+
transformed multi-scale image would be zero shape.
236+
"""
237+
238+
test_image = Image2DModel.parse(
239+
np.ones((1, 10, 10)),
240+
dims=("c", "y", "x"),
241+
scale_factors=[2, 4],
242+
transformations={
243+
"cs1": Scale([0.5] * 2, axes=["y", "x"]),
244+
"cs2": Scale([0.01] * 2, axes=["y", "x"]),
245+
},
246+
)
247+
248+
# check that the transform doesn't raise an error and that it
249+
# discards the lowest resolution level
250+
test_image_t = transform(test_image, to_coordinate_system="cs1")
251+
assert list(test_image.keys()) == ["scale0", "scale1", "scale2"]
252+
assert list(test_image_t.keys()) == ["scale0", "scale1"]
253+
254+
# check that a ValueError is raised when no resolution level
255+
# is left after the transformation
256+
with pytest.raises(
257+
ValueError,
258+
match="The transformation leads to zero shaped data even at the highest resolution level",
259+
):
260+
transform(test_image, to_coordinate_system="cs2")
261+
262+
232263
def test_map_coordinate_systems_single_path(full_sdata: SpatialData):
233264
scale = Scale([2], axes=("x",))
234265
translation = Translation([100], axes=("x",))

0 commit comments

Comments
 (0)