Skip to content

Commit bfda1fe

Browse files
authored
fix(datashader): render_shapes in a non-global coordinate system (#782) (#783)
1 parent 2bad5a1 commit bfda1fe

2 files changed

Lines changed: 14 additions & 15 deletions

File tree

‎src/spatialdata_plot/pl/render.py‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -895,11 +895,17 @@ def _draw_centroids(xy: np.ndarray, radius: float | None = None) -> None:
895895
transformed_geometry = shapes["geometry"].transform(
896896
lambda x: (np.hstack([x, np.ones((x.shape[0], 1))]) @ tm.T)[:, :2]
897897
)
898+
transformed_geodataframe = gpd.GeoDataFrame(
899+
data=shapes.drop("geometry", axis=1),
900+
geometry=transformed_geometry,
901+
)
902+
# Geometry is already in the target CS, so tag the wrapped element with an identity transform
903+
# there. Depending on the pandas/geopandas version the constructor above may carry over the
904+
# source element's transform attrs; drop them first so parse does not see conflicting ones.
905+
transformed_geodataframe.attrs.pop("transform", None)
898906
transformed_element = ShapesModel.parse(
899-
gpd.GeoDataFrame(
900-
data=shapes.drop("geometry", axis=1),
901-
geometry=transformed_geometry,
902-
)
907+
transformed_geodataframe,
908+
transformations={coordinate_system: Identity()},
903909
)
904910

905911
if len(transformed_element) == 0:
@@ -908,7 +914,7 @@ def _draw_centroids(xy: np.ndarray, radius: float | None = None) -> None:
908914
return
909915

910916
plot_width, plot_height, x_ext, y_ext, factor = _get_extent_and_range_for_datashader_canvas(
911-
transformed_element, "global", fig_params
917+
transformed_element, coordinate_system, fig_params
912918
)
913919

914920
cvs = ds.Canvas(plot_width=plot_width, plot_height=plot_height, x_range=x_ext, y_range=y_ext)

‎tests/pl/test_render_shapes.py‎

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,10 +1331,10 @@ def test_plot_can_handle_non_numeric_radius_values(sdata_blobs: SpatialData):
13311331
def test_groups_filtering_preserves_transformation(sdata_blobs: SpatialData):
13321332
"""Regression test for #420: groups filtering must not strip coordinate-system metadata.
13331333
1334-
Simulates the exact sequence that ``_render_shapes`` performs —
1334+
Simulates the sequence that ``_render_shapes`` performs —
13351335
filter_by_coordinate_system -> groups boolean-index -> reset_index ->
1336-
re-assign to sdata_filt -> GeoDataFrame re-wrap — then asserts that
1337-
``_prepare_transformation`` can still retrieve the correct transformation.
1336+
re-assign to sdata_filt — then asserts that ``_prepare_transformation``
1337+
can still retrieve the correct transformation.
13381338
"""
13391339
from spatialdata_plot.pl._datashader import _prepare_transformation
13401340

@@ -1354,20 +1354,13 @@ def test_groups_filtering_preserves_transformation(sdata_blobs: SpatialData):
13541354
keep = shapes["cluster"] == "c1"
13551355
shapes = shapes[keep].reset_index(drop=True)
13561356
sdata_filt["blobs_polygons"] = shapes
1357-
# GeoDataFrame re-wrap strips .attrs (this is what _render_shapes does next)
1358-
shapes = gpd.GeoDataFrame(shapes, geometry="geometry")
13591357

13601358
# sdata_filt's element must still carry the correct transformation
13611359
trans, _ = _prepare_transformation(sdata_filt.shapes["blobs_polygons"], cs)
13621360
matrix = trans.get_matrix()
13631361
np.testing.assert_allclose(matrix[0, 0], scale_factor, err_msg="x-scale lost after groups filtering")
13641362
np.testing.assert_allclose(matrix[1, 1], scale_factor, err_msg="y-scale lost after groups filtering")
13651363

1366-
# The GeoDataFrame re-wrap strips attrs — reading the transform from
1367-
# the re-wrapped object must fail, proving why early capture matters.
1368-
with pytest.raises(AssertionError):
1369-
_prepare_transformation(shapes, cs)
1370-
13711364

13721365
def test_plot_can_handle_mixed_numeric_and_color_data(sdata_blobs: SpatialData):
13731366
"""Test that mixed numeric and color-like data raises a clear error."""

0 commit comments

Comments
 (0)