`render_shapes` with datashader fails with `KeyError: 'global'` on non-"global" coordinate systems with geopandas 1.2
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 72/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- python
- Bereich
- data-visualization
Rechercherichtung
Beginne in spatialdata_plot/pl/render.py beim Datashader-Zweig von _render_shapes, wo transformed_element mit ShapesModel.parse erzeugt wird. Führe den Reproducer aus dem Issue mit 12.000 Shapes auf einem nicht-globalen Koordinatensystem mit geopandas 1.2.0 und 1.1.4 aus. Fertig ist es, wenn er unter beiden Versionen rendert, die kopierten transform-Attribute entfernt sind und die "global"-Identitätstransformation explizit gesetzt ist.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
With geopandas 1.2.0, render_shapes() fails with KeyError: 'global' when the element has more than 10,000 shapes (so the datashader method is used) and the element is not in the "global" coordinate system.
The same code works with geopandas 1.1.4.
Minimal example
import geopandas as gpd
import matplotlib.pyplot as plt
import numpy as np
import shapely
import spatialdata as sd
import spatialdata_plot # noqa: F401
from spatialdata.models import ShapesModel
from spatialdata.transformations import Identity
# More than 10,000 shapes so that render_shapes picks the datashader method
rng = np.random.default_rng(0)
xy = rng.uniform(0, 1000, size=(12_000, 2))
shapes = gpd.GeoDataFrame(geometry=[shapely.box(x, y, x + 2, y + 2) for x, y in xy])
# The element is only in a coordinate system that is not "global"
sdata = sd.SpatialData(
shapes={"squares": ShapesModel.parse(shapes, transformations={"sample": Identity()})}
)
fig, ax = plt.subplots()
sdata.pl.render_shapes("squares").pl.show(ax=ax, coordinate_systems="sample")
With geopandas==1.2.0:
File ".../spatialdata_plot/pl/render.py", line 910, 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", line 830, in _get_extent_and_range_for_datashader_canvas
extent = _fast_extent(spatial_element, coordinate_system)
File ".../spatialdata_plot/pl/utils.py", line 1678, in _fast_extent
return _element_extent_fast(element, coordinate_system) or get_extent(element, coordinate_system=coordinate_system)
File ".../spatialdata_plot/pl/utils.py", line 1585, in _element_extent_fast
matrix = transformations[coordinate_system].to_affine_matrix(("x", "y"), ("x", "y"))
KeyError: 'global'
With geopandas<1.2 (1.1.4) the plot renders correctly.
With method="matplotlib" it also renders correctly.
Cause
In the datashader path of _render_shapes, the geometry is transformed into the target coordinate system and a new element is made:
transformed_element = ShapesModel.parse(
gpd.GeoDataFrame(
data=shapes.drop("geometry", axis=1),
geometry=transformed_geometry,
)
)
The extent is then computed in a hard-coded "global" coordinate system.
This relies on ShapesModel.parse adding the default {"global": Identity()} transformation.
shapes.drop(...) keeps DataFrame.attrs, which hold the original transform.
geopandas 1.1.4 dropped these attrs in the GeoDataFrame constructor, but geopandas 1.2.0 keeps them:
import geopandas as gpd, shapely
g = gpd.GeoDataFrame({"a": [1]}, geometry=[shapely.Point(0, 0)])
g.attrs["transform"] = {"sample": 1}
print(gpd.GeoDataFrame(data=g.drop("geometry", axis=1), geometry=g["geometry"]).attrs)
# geopandas 1.1.4: {}
# geopandas 1.2.0: {'transform': {'sample': 1}}
So with geopandas 1.2.0 ShapesModel.parse keeps the original transformations (here only "sample"), no "global" transformation is added, and the lookup fails.
Possible fix
The geometry is already in the target coordinate system, so the copied transform attrs can be removed before parsing.
Just passing transformations={"global": Identity()} to ShapesModel.parse is not sufficient. With geopandas 1.2.0 it raises ValueError: Transformations are both specified for the element and also passed as an argument to the parser.
This change makes the example above work with both geopandas 1.1.4 and 1.2.0:
- transformed_element = ShapesModel.parse(
- gpd.GeoDataFrame(
- data=shapes.drop("geometry", axis=1),
- geometry=transformed_geometry,
- )
- )
+ transformed_gdf = gpd.GeoDataFrame(
+ data=shapes.drop("geometry", axis=1),
+ geometry=transformed_geometry,
+ )
+ # geometry is already in the target coordinate system; drop any transform
+ # carried over in attrs (geopandas >= 1.2 propagates DataFrame.attrs)
+ transformed_gdf.attrs.pop("transform", None)
+ transformed_element = ShapesModel.parse(transformed_gdf, transformations={"global": Identity()})
Versions
spatialdata-plot 0.4.2
geopandas 1.2.0
spatialdata 0.8.0
pandas 3.0.6
shapely 2.2.0
datashader 0.19.1
numpy 2.5.3
Python 3.13.5
OS macOS-26.7.1-arm64
- Vorherrschende Sprache
- Python
- Sterne
- 86
- Forks
- 22
- Ø Merge
- 4 T. 5 Std.
- Gemergte PRs (30 T.)
- 5
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus scverse/spatialdata-plot
-
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 48/100
scverse/spatialdata-plot#747 ·
-
Schwierigkeit 5/5 Über eine Woche Anfängerfreundlichkeit 45/100
scverse/spatialdata-plot#677 ·
-
enhancement priority: medium utils :wrench:
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 68/100
scverse/spatialdata-plot#632 ·
-
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 45/100
scverse/spatialdata-plot#534 · 1 Kommentar ·
-
Enable auto-completionOffen
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 30/100
scverse/spatialdata-plot#476 ·
Alle Issues in scverse/spatialdata-plot
Ähnliche Issues
-
dependencies feature github_actions good first issue
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 62/100
wemake-services/wemake-django-template#3149 ·
Maintainer antworten meist innerhalb von 1 Tag
-
[request] vsg/1.1.16Offenupstream update
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
conan-io/conan-center-index#31142 ·
Maintainer antworten meist innerhalb von 1 Tag
-
area:core bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag
-
request-theme
Schwierigkeit 2/5 Unter einer Stunde Anfängerfreundlichkeit 70/100
LizardByte/ThemerrDB#8877 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
area/install-update comp/gateway P0 sweeper:risk-compatibility type/bug
Schwierigkeit 2/5 Unter einer Stunde Anfängerfreundlichkeit 72/100
NousResearch/hermes-agent#135997 · 3 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag