Skip to content

render_shapes(method="datashader") fails with KeyError: 'global' when the element has no "global" coordinate system #782

Closed

Description

@LucaMarconato

AI-generated--manually reviewed

Description

render_shapes(..., method="datashader") raises KeyError: 'global' when the shapes element has no "global" coordinate system. This breaks the Visium HD example notebooks (technology_visium_hd, technology_visium_hd_mouse_4.0.1): data from spatialdata-io has no global CS, and datashader is used either explicitly or automatically (more than 10k shapes).

MRE (PEP 723, run with uv run mre.py)

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "spatialdata @ git+https://github.com/scverse/spatialdata.git@main",
#     "spatialdata-plot @ git+https://github.com/scverse/spatialdata-plot.git@main",
# ]
# ///
import matplotlib

matplotlib.use("Agg")

import spatialdata as sd
import spatialdata_plot  # noqa: F401
from spatialdata.transformations import get_transformation, set_transformation

sdata = sd.datasets.cells()

# Move every element from "global" to a custom CS, as spatialdata-io does for Visium HD.
cs = "my_sample"
for _, name, element in sdata.gen_spatial_elements():
    set_transformation(element, {cs: get_transformation(element, "global")}, set_all=True)
assert "global" not in sdata.coordinate_systems

sdata.pl.render_shapes("cell_boundaries", method="matplotlib").pl.show(coordinate_systems=cs)  # OK
sdata.pl.render_shapes("cell_boundaries", method="datashader").pl.show(coordinate_systems=cs)  # KeyError: 'global'

(spatialdata is installed from main because datasets.cells() is not in a release yet.)

Traceback (abridged)

File .../spatialdata_plot/pl/render.py, in _render_shapes
    plot_width, plot_height, x_ext, y_ext, factor = _get_extent_and_range_for_datashader_canvas(
        transformed_element, "global", fig_params
    )
File .../spatialdata_plot/pl/_datashader.py, in _get_extent_and_range_for_datashader_canvas
    extent = _fast_extent(spatial_element, coordinate_system)
File .../spatialdata_plot/pl/utils.py, in _fast_extent
    return _element_extent_fast(element, coordinate_system) or get_extent(element, coordinate_system=coordinate_system)
File .../spatialdata_plot/pl/utils.py, in _element_extent_fast
    matrix = transformations[coordinate_system].to_affine_matrix(("x", "y"), ("x", "y"))
KeyError: 'global'

Root cause

In the datashader branch of _render_shapes, the already-transformed geometry is wrapped with ShapesModel.parse(gpd.GeoDataFrame(data=shapes.drop("geometry", axis=1), ...)), and the canvas extent is then computed in a hardcoded "global" CS. Because shapes.drop(...) keeps .attrs, the new element inherits the original transformations (here only my_sample) and never gets a "global" entry, so the lookup in _element_extent_fast fails.

The lookup came in with #703 (fast axis-aligned extent), so that's the likely regression point; not confirmed by bisecting.

Possible fix

The geometry is already in the target CS, so pass transformations={"global": Identity()} to that ShapesModel.parse call (or clear attrs before parsing). A regression test rendering shapes with datashader in a non-global CS would cover this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions