From a1baf256c31bb6d7a35958747358911a49de68f4 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Mon, 25 Nov 2024 14:46:16 +0100 Subject: [PATCH 1/7] fixed line on checking data.crs --- hvplot/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index 8d5f3f035..b987fee2f 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -2171,7 +2171,7 @@ def _process_tiles_without_geo(self, data, x, y): return data, x, y if is_geodataframe(data): - if data.crs is not None: + if hasattr(data, 'crs') and data.crs is not None: data = data.to_crs(epsg=3857) return data, x, y elif not is_lazy_data(data): From e3f481506baf7ce64f28948d96eb87df480da95f Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Mon, 25 Nov 2024 16:23:51 +0100 Subject: [PATCH 2/7] added tests --- hvplot/tests/testgeowithoutgv.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hvplot/tests/testgeowithoutgv.py b/hvplot/tests/testgeowithoutgv.py index 7ad0bf3ee..21fd7a8df 100644 --- a/hvplot/tests/testgeowithoutgv.py +++ b/hvplot/tests/testgeowithoutgv.py @@ -7,6 +7,9 @@ import numpy as np import pandas as pd import pytest +import spatialpandas as spd + +from hvplot.util import is_geodataframe try: import dask.dataframe as dd @@ -83,3 +86,20 @@ 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) + + if hasattr(sdf, 'crs'): + del sdf.crs + + assert len(plot) == 2 + assert is_geodataframe(sdf) + assert not hasattr(plot, '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' From 2bbf2eb70a8b39254fb73b3254d6264891791e65 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Mon, 25 Nov 2024 17:56:05 +0100 Subject: [PATCH 3/7] post review --- hvplot/tests/testgeowithoutgv.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hvplot/tests/testgeowithoutgv.py b/hvplot/tests/testgeowithoutgv.py index 21fd7a8df..516133d22 100644 --- a/hvplot/tests/testgeowithoutgv.py +++ b/hvplot/tests/testgeowithoutgv.py @@ -93,13 +93,10 @@ def test_plot_without_crs(self): sdf = spd.GeoDataFrame({'geometry': spd.GeoSeries([square, square]), 'name': ['A', 'B']}) plot = sdf.hvplot.polygons(tiles=True) - if hasattr(sdf, 'crs'): - del sdf.crs - assert len(plot) == 2 assert is_geodataframe(sdf) - assert not hasattr(plot, 'crs') + 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' + assert bk_plot.projection == 'mercator' # projection enabled due to `tiles=True` From 511c63f34ebab6cafff56093a0f1182cbeab0ecf Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 27 Nov 2024 11:03:13 +0100 Subject: [PATCH 4/7] updated docs --- doc/user_guide/Geographic_Data.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)." ] From 8aa71f805869f402d218da076ef685b910f4eeaf Mon Sep 17 00:00:00 2001 From: maximlt Date: Wed, 27 Nov 2024 15:55:20 +0100 Subject: [PATCH 5/7] optional import --- hvplot/tests/testgeowithoutgv.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hvplot/tests/testgeowithoutgv.py b/hvplot/tests/testgeowithoutgv.py index 516133d22..07517bced 100644 --- a/hvplot/tests/testgeowithoutgv.py +++ b/hvplot/tests/testgeowithoutgv.py @@ -7,7 +7,6 @@ import numpy as np import pandas as pd import pytest -import spatialpandas as spd from hvplot.util import is_geodataframe @@ -17,6 +16,11 @@ except ImportError: dd = None +try: + import spatialpandas as spd +except ModuleNotFoundError: + spd = None + bk_renderer = hv.Store.renderers['bokeh'] From 1e155916e6660d061631bc919fa57d8e073c1706 Mon Sep 17 00:00:00 2001 From: maximlt Date: Wed, 27 Nov 2024 15:55:49 +0100 Subject: [PATCH 6/7] minor refactor --- hvplot/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index b987fee2f..0b0b3e552 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -2171,7 +2171,7 @@ def _process_tiles_without_geo(self, data, x, y): return data, x, y if is_geodataframe(data): - if hasattr(data, 'crs') and data.crs is not None: + if getattr(data, 'crs', None) is not None: data = data.to_crs(epsg=3857) return data, x, y elif not is_lazy_data(data): From 599aa481d59b1f9f33aae40181f799af0881045c Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Fri, 29 Nov 2024 15:48:49 +0100 Subject: [PATCH 7/7] changed control flow logic --- hvplot/converter.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index 0b0b3e552..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 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) - return data, x, y - elif not is_lazy_data(data): - # To prevent eager evaluation: https://github.com/holoviz/hvplot/pull/1432 + 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):