Skip to content

Commit

Permalink
checks geodataframe for crs before conversion (#1459)
Browse files Browse the repository at this point in the history
Co-authored-by: maximlt <[email protected]>
  • Loading branch information
Azaya89 and maximlt authored Dec 2, 2024
1 parent 62c691f commit 19206c5
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
4 changes: 2 additions & 2 deletions doc/user_guide/Geographic_Data.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"source": [
"## Tiled web map\n",
"\n",
"A [tiled web map](https://en.wikipedia.org/wiki/Tiled_web_map), or tile map, is an interactive map displayed on a web browser that is divided into small, pre-rendered image tiles, allowing for efficient loading and seamless navigation across various zoom levels and geographic areas. hvPlot allows to add a tile map as a basemap to a plot with the `tiles` parameter. Importantly, `tiles` is a parameter that can be used **without installing GeoViews**.\n",
"A [tiled web map](https://en.wikipedia.org/wiki/Tiled_web_map), or tile map, is an interactive map displayed on a web browser that is divided into small, pre-rendered image tiles, allowing for efficient loading and seamless navigation across various zoom levels and geographic areas. hvPlot allows us to add a tile map as a basemap to a plot with the `tiles` parameter. Importantly, `tiles` is a parameter that can be used **without installing GeoViews**.\n",
"\n",
"We'll display this dataframe of all US airports (including military bases overseas), the points are expressed in latitude/longitude coordinates:"
]
Expand All @@ -80,7 +80,7 @@
"source": [
"We'll first start by displaying the airports **without GeoViews** with tiles by setting `tiles=True`. \n",
"\n",
"Under the hood, hvPlot projects lat/lon to easting/northing ([EPSG:4326](https://epsg.io/4326) to [EPSG:3857](https://epsg.io/3857)) coordinates without additional package dependencies if it detects that the values falls within expected lat/lon ranges, **unless the data is lazily loaded (dask / ibis).**\n",
"Under the hood, hvPlot projects lat/lon to easting/northing ([EPSG:4326](https://epsg.io/4326) to [EPSG:3857](https://epsg.io/3857)) coordinates without additional package dependencies if it detects that the values falls within expected lat/lon ranges, **unless the data is lazily loaded (dask / ibis), or the data is a spatialpandas object.**\n",
"\n",
"Note, **this feature is only available after `hvplot>=0.11.0`**; older versions, `hvplot<0.11.0`, require manual projection (see below)."
]
Expand Down
14 changes: 8 additions & 6 deletions hvplot/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2170,12 +2170,13 @@ def _process_tiles_without_geo(self, data, x, y):
elif not is_geodataframe(data) and (x is None or y is None):
return data, x, y

if is_geodataframe(data):
if data.crs is not None:
data = data.to_crs(epsg=3857)
return data, x, y
elif not is_lazy_data(data):
if is_lazy_data(data):
# To prevent eager evaluation: https://github.com/holoviz/hvplot/pull/1432
pass
elif is_geodataframe(data):
if getattr(data, 'crs', None) is not None:
data = data.to_crs(epsg=3857)
else:
min_x = np.min(data[x])
max_x = np.max(data[x])
min_y = np.min(data[y])
Expand All @@ -2193,7 +2194,8 @@ def _process_tiles_without_geo(self, data, x, y):
data[new_y] = northing
if is_xarray(data):
data = data.swap_dims({x: new_x, y: new_y})
return data, new_x, new_y
x = new_x
y = new_y
return data, x, y

def chart(self, element, x, y, data=None):
Expand Down
21 changes: 21 additions & 0 deletions hvplot/tests/testgeowithoutgv.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@
import pandas as pd
import pytest

from hvplot.util import is_geodataframe

try:
import dask.dataframe as dd
import hvplot.dask # noqa
except ImportError:
dd = None

try:
import spatialpandas as spd
except ModuleNotFoundError:
spd = None


bk_renderer = hv.Store.renderers['bokeh']

Expand Down Expand Up @@ -83,3 +90,17 @@ def test_plot_with_dask(self, simple_df):
assert isinstance(plot.get(0), hv.Tiles)
bk_plot = bk_renderer.get_plot(plot)
assert bk_plot.projection == 'mercator'

@pytest.mark.skipif(spd is None, reason='spatialpandas not installed')
def test_plot_without_crs(self):
square = spd.geometry.Polygon([(0.0, 0), (0, 1), (1, 1), (1, 0)])
sdf = spd.GeoDataFrame({'geometry': spd.GeoSeries([square, square]), 'name': ['A', 'B']})
plot = sdf.hvplot.polygons(tiles=True)

assert len(plot) == 2
assert is_geodataframe(sdf)
assert not hasattr(sdf, 'crs')
assert isinstance(plot.get(0), hv.Tiles)
assert isinstance(plot.get(1), hv.Polygons)
bk_plot = bk_renderer.get_plot(plot)
assert bk_plot.projection == 'mercator' # projection enabled due to `tiles=True`

0 comments on commit 19206c5

Please sign in to comment.