diff --git a/doc/user_guide/Geographic_Data.ipynb b/doc/user_guide/Geographic_Data.ipynb index 55df431a2..3b6ed7fe7 100644 --- a/doc/user_guide/Geographic_Data.ipynb +++ b/doc/user_guide/Geographic_Data.ipynb @@ -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:" ] @@ -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)." ] diff --git a/hvplot/converter.py b/hvplot/converter.py index 8d5f3f035..9aadbc358 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -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]) @@ -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): diff --git a/hvplot/tests/testgeowithoutgv.py b/hvplot/tests/testgeowithoutgv.py index 7ad0bf3ee..07517bced 100644 --- a/hvplot/tests/testgeowithoutgv.py +++ b/hvplot/tests/testgeowithoutgv.py @@ -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'] @@ -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`