From 9f8cdd2490ae8b61f1b08c2b8f5f836d64828410 Mon Sep 17 00:00:00 2001 From: anon Date: Sun, 14 Jun 2026 22:29:23 +0200 Subject: [PATCH] fix(show): render all coordinate systems for type-distributed elements (#694) _resolve_coordinate_systems computed elements_to_be_rendered from the leaked loop variable cs (the last validated CS only). Since _get_elements_to_be_rendered keys on element type, a CS lacking a queued element type was wrongly pruned by _get_valid_cs when elements of that type lived in another CS. Union the elements across all coordinate systems instead. Regression test: an image in one CS and labels in another now render two panels (failed before: only the last CS survived). --- src/spatialdata_plot/pl/basic.py | 5 ++++- tests/pl/test_utils.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/spatialdata_plot/pl/basic.py b/src/spatialdata_plot/pl/basic.py index 9c5584e3..fa9bfd39 100644 --- a/src/spatialdata_plot/pl/basic.py +++ b/src/spatialdata_plot/pl/basic.py @@ -1673,7 +1673,10 @@ def _resolve_coordinate_systems( if cs not in sdata.coordinate_systems: raise ValueError(f"Unknown coordinate system '{cs}', valid choices are: {sdata.coordinate_systems}") - elements_to_be_rendered = _get_elements_to_be_rendered(render_cmds, cs_index, cs) + # Union elements across all coordinate systems, not just the last one validated above. + elements_to_be_rendered = list( + dict.fromkeys(e for cs in coordinate_systems for e in _get_elements_to_be_rendered(render_cmds, cs_index, cs)) + ) # filter out cs without relevant elements cmds = [cmd for cmd, _ in render_cmds] diff --git a/tests/pl/test_utils.py b/tests/pl/test_utils.py index 74a929f4..33c07739 100644 --- a/tests/pl/test_utils.py +++ b/tests/pl/test_utils.py @@ -791,3 +791,26 @@ def test_missing_instances_become_nan(self): new = _extract_color_column(sdata["table"], "g0", origin="var", element=sdata["shapes"], element_name="shapes") assert len(new) == 30 assert int(new.isna().sum()) == 5 + + +def test_show_renders_all_coordinate_systems_for_distributed_elements(): + """Regression for #694: element types split across coordinate systems must all render. + + Before the fix, ``_resolve_coordinate_systems`` computed the rendered element set from a + leaked loop variable (the last validated CS only), so ``_get_valid_cs`` could drop a CS whose + elements lived elsewhere. ``_get_elements_to_be_rendered`` keys on element *type*, so the bug + only surfaces when the leftover CS lacks a queued element type: here the image lives in ``cs_a`` + and the labels in ``cs_b``, so the leaked ``cs_b`` (no image) used to drop ``cs_a``. + """ + from spatialdata.models import Image2DModel + from spatialdata.transformations import Identity + + rng = np.random.default_rng(0) + img = Image2DModel.parse(rng.random((3, 16, 16)), transformations={"cs_a": Identity()}) + lab = Labels2DModel.parse(rng.integers(0, 5, (16, 16)), transformations={"cs_b": Identity()}) + sdata = SpatialData(images={"img": img}, labels={"lab": lab}) + + axes = sdata.pl.render_images("img").pl.render_labels("lab").pl.show(return_ax=True) + axes = axes if isinstance(axes, list) else [axes] + assert {ax.get_title() for ax in axes} == {"cs_a", "cs_b"} + plt.close("all")