File: C:/Users/fred/anaconda3/Lib/site-packages/hvplot/tests/testgeo.py
"""
These tests depends on GeoViews.
"""
import pathlib
import sys
from unittest import TestCase, SkipTest
import holoviews as hv
import numpy as np
import pandas as pd
import pytest
from hvplot.util import proj_to_cartopy
from packaging.version import Version
pytestmark = pytest.mark.geo
bk_renderer = hv.Store.renderers['bokeh']
@pytest.fixture
def simple_df():
return pd.DataFrame(np.random.rand(10, 2), columns=['x', 'y'])
class TestGeo(TestCase):
def setUp(self):
if sys.platform == 'win32':
raise SkipTest('Skip geo tests on windows for now')
try:
import xarray as xr # noqa
import rasterio # noqa
import geoviews # noqa
import cartopy.crs as ccrs # noqa
import pyproj # noqa
import rioxarray as rxr
except ImportError:
raise SkipTest(
'xarray, rasterio, geoviews, cartopy, pyproj or rioxarray not available'
)
import hvplot.xarray # noqa
import hvplot.pandas # noqa
self.da = rxr.open_rasterio(
pathlib.Path(__file__).parent / 'data' / 'RGB-red.byte.tif'
).isel(band=0)
self.crs = proj_to_cartopy(self.da.spatial_ref.attrs['crs_wkt'])
def assertCRS(self, plot, proj='utm'):
import cartopy
if Version(cartopy.__version__) < Version('0.20'):
assert plot.crs.proj4_params['proj'] == proj
else:
assert plot.crs.to_dict()['proj'] == proj
def assert_projection(self, plot, proj):
opts = hv.Store.lookup_options('bokeh', plot, 'plot')
assert opts.kwargs['projection'].proj4_params['proj'] == proj
class TestCRSInference(TestGeo):
def setUp(self):
if sys.platform == 'win32':
raise SkipTest('Skip CRS inference on Windows')
super().setUp()
def test_plot_with_crs_as_proj_string(self):
da = self.da.copy()
da.rio._crs = False # To not treat it as a rioxarray
plot = self.da.hvplot.image('x', 'y', crs='epsg:32618')
self.assertCRS(plot)
def test_plot_with_geo_as_true_crs_undefined(self):
plot = self.da.hvplot.image('x', 'y', geo=True)
self.assertCRS(plot)
class TestProjections(TestGeo):
def test_plot_with_crs_as_object(self):
plot = self.da.hvplot.image('x', 'y', crs=self.crs)
self.assertCRS(plot)
def test_plot_with_crs_as_attr_str(self):
da = self.da.copy()
da.rio._crs = False # To not treat it as a rioxarray
da.attrs = {'bar': self.crs}
plot = da.hvplot.image('x', 'y', crs='bar')
self.assertCRS(plot)
def test_plot_with_crs_as_pyproj_Proj(self):
import pyproj
da = self.da.copy()
da.rio._crs = False # To not treat it as a rioxarray
plot = da.hvplot.image('x', 'y', crs=pyproj.Proj(self.crs))
self.assertCRS(plot)
def test_plot_with_crs_as_nonexistent_attr_str(self):
da = self.da.copy()
da.rio._crs = False # To not treat it as a rioxarray
# Used to test crs='foo' but this is parsed under-the-hood
# by PROJ (projinfo) which matches a geographic projection named
# 'Amersfoort'
with self.assertRaisesRegex(ValueError, "'name_of_some_invalid_projection' must be"):
da.hvplot.image('x', 'y', crs='name_of_some_invalid_projection')
def test_plot_with_geo_as_true_crs_no_crs_on_data_returns_default(self):
da = self.da.copy()
da.rio._crs = False # To not treat it as a rioxarray
da.attrs = {'bar': self.crs}
plot = da.hvplot.image('x', 'y', geo=True)
self.assertCRS(plot, 'eqc')
def test_plot_with_projection_as_string(self):
da = self.da.copy()
plot = da.hvplot.image('x', 'y', crs=self.crs, projection='Robinson')
self.assert_projection(plot, 'robin')
def test_plot_with_projection_as_string_google_mercator(self):
da = self.da.copy()
plot = da.hvplot.image('x', 'y', crs=self.crs, projection='GOOGLE_MERCATOR')
self.assert_projection(plot, 'merc')
def test_plot_with_projection_as_invalid_string(self):
with self.assertRaisesRegex(ValueError, 'Projection must be defined'):
self.da.hvplot.image('x', 'y', projection='foo')
def test_plot_with_projection_raises_an_error_when_tiles_set(self):
da = self.da.copy()
with self.assertRaisesRegex(ValueError, 'Tiles can only be used with output projection'):
da.hvplot.image('x', 'y', crs=self.crs, projection='Robinson', tiles=True)
def test_overlay_with_projection(self):
# Regression test for https://github.com/holoviz/hvplot/issues/1090
df = pd.DataFrame({'lon': [0, 10], 'lat': [40, 50], 'v': [0, 1]})
plot1 = df.hvplot.points(x='lon', y='lat', s=200, c='y', geo=True, tiles='CartoLight')
plot2 = df.hvplot.points(x='lon', y='lat', c='v', geo=True)
# This should work without erroring
plot = plot1 * plot2
hv.renderer('bokeh').get_plot(plot)
def test_geo_with_rasterize(self):
import xarray as xr
import cartopy.crs as ccrs
import geoviews as gv
try:
from holoviews.operation.datashader import rasterize
except ImportError:
raise SkipTest('datashader not available')
ds = xr.tutorial.open_dataset('air_temperature')
hvplot_output = ds.isel(time=0).hvplot.points(
'lon',
'lat',
crs=ccrs.PlateCarree(),
projection=ccrs.LambertConformal(),
rasterize=True,
dynamic=False,
aggregator='max',
project=True,
)
p1 = gv.Points(ds.isel(time=0), kdims=['lon', 'lat'], crs=ccrs.PlateCarree())
p2 = gv.project(p1, projection=ccrs.LambertConformal())
expected = rasterize(p2, dynamic=False, aggregator='max')
xr.testing.assert_allclose(hvplot_output.data, expected.data)
class TestGeoAnnotation(TestCase):
def setUp(self):
try:
import geoviews # noqa
import cartopy.crs as ccrs # noqa
except ImportError:
raise SkipTest('geoviews or cartopy not available')
import hvplot.pandas # noqa
self.crs = ccrs.PlateCarree()
self.df = pd.DataFrame(np.random.rand(10, 2), columns=['x', 'y'])
def test_plot_with_coastline(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', geo=True, coastline=True)
self.assertEqual(len(plot), 2)
coastline = plot.get(1)
self.assertIsInstance(coastline, gv.Feature)
def test_plot_with_coastline_sets_geo_by_default(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', coastline=True)
self.assertEqual(len(plot), 2)
coastline = plot.get(1)
self.assertIsInstance(coastline, gv.Feature)
def test_plot_with_coastline_scale(self):
plot = self.df.hvplot.points('x', 'y', geo=True, coastline='10m')
opts = plot.get(1).opts.get('plot')
assert opts.kwargs['scale'] == '10m'
def test_plot_with_tiles(self):
plot = self.df.hvplot.points('x', 'y', geo=False, tiles=True)
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), hv.Tiles)
self.assertIn('openstreetmap', plot.get(0).data)
def test_plot_with_tiles_with_tiles_opts(self):
plot = self.df.hvplot.points('x', 'y', geo=False, tiles=True, tiles_opts=dict(alpha=0.5))
assert len(plot) == 2
tiles = plot.get(0)
assert isinstance(tiles, hv.Tiles)
assert 'openstreetmap' in tiles.data
assert tiles.opts['alpha'] == 0.5
def test_plot_with_tiles_with_geo(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', geo=True, tiles=True)
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), gv.element.WMTS)
self.assertIn('openstreetmap', plot.get(0).data)
def test_plot_with_tiles_with_tiles_opts_with_geo(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', geo=True, tiles=True, tiles_opts=dict(alpha=0.5))
assert len(plot) == 2
tiles = plot.get(0)
assert isinstance(tiles, gv.element.WMTS)
assert 'openstreetmap' in tiles.data
assert tiles.opts['alpha'] == 0.5
def test_plot_with_specific_tiles(self):
plot = self.df.hvplot.points('x', 'y', geo=False, tiles='ESRI')
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), hv.Tiles)
self.assertIn('ArcGIS', plot.get(0).data)
def test_plot_with_specific_tiles_geo(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', geo=True, tiles='ESRI')
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), gv.element.WMTS)
self.assertIn('ArcGIS', plot.get(0).data)
def test_plot_with_specific_tile_class(self):
plot = self.df.hvplot.points('x', 'y', geo=False, tiles=hv.element.tiles.EsriImagery)
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), hv.Tiles)
self.assertIn('ArcGIS', plot.get(0).data)
def test_plot_with_specific_tile_class_with_geo(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', geo=True, tiles=gv.tile_sources.EsriImagery)
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), gv.element.WMTS)
self.assertIn('ArcGIS', plot.get(0).data)
def test_plot_with_specific_tile_obj(self):
plot = self.df.hvplot.points('x', 'y', geo=False, tiles=hv.element.tiles.EsriImagery())
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), hv.Tiles)
self.assertIn('ArcGIS', plot.get(0).data)
def test_plot_with_specific_tile_obj_with_geo(self):
plot = self.df.hvplot.points('x', 'y', geo=True, tiles=hv.element.tiles.EsriImagery())
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), hv.Tiles)
self.assertIn('ArcGIS', plot.get(0).data)
def test_plot_with_specific_gv_tile_obj(self):
import geoviews as gv
plot = self.df.hvplot.points('x', 'y', geo=True, tiles=gv.tile_sources.CartoDark)
self.assertEqual(len(plot), 2)
self.assertIsInstance(plot.get(0), gv.element.WMTS)
def test_plot_with_xyzservices_tiles(self):
xyzservices = pytest.importorskip('xyzservices')
import geoviews as gv
plot = self.df.hvplot.points(
'x', 'y', geo=True, tiles=xyzservices.providers.Esri.WorldImagery
)
assert len(plot) == 2
assert isinstance(plot.get(0), gv.element.WMTS)
assert isinstance(plot.get(0).data, xyzservices.TileProvider)
def test_plot_with_features_properly_overlaid_underlaid(self):
# land should be under, borders should be over
plot = self.df.hvplot.points('x', 'y', features=['land', 'borders'])
assert plot.get(0).group == 'Land'
assert plot.get(2).group == 'Borders'
class TestGeoElements(TestCase):
def setUp(self):
try:
import geoviews # noqa
import cartopy.crs as ccrs # noqa
except ImportError:
raise SkipTest('geoviews or cartopy not available')
import hvplot.pandas # noqa
self.crs = ccrs.PlateCarree()
self.df = pd.DataFrame(np.random.rand(10, 2), columns=['x', 'y'])
def test_geo_hexbin(self):
hextiles = self.df.hvplot.hexbin('x', 'y', geo=True)
self.assertEqual(hextiles.crs, self.crs)
def test_geo_points(self):
points = self.df.hvplot.points('x', 'y', geo=True)
self.assertEqual(points.crs, self.crs)
def test_geo_points_color_internally_set_to_dim(self):
altered_df = self.df.copy().assign(red=np.random.choice(['a', 'b'], len(self.df)))
plot = altered_df.hvplot.points('x', 'y', c='red', geo=True)
opts = hv.Store.lookup_options('bokeh', plot, 'style')
self.assertIsInstance(opts.kwargs['color'], hv.dim)
self.assertEqual(opts.kwargs['color'].dimension.name, 'red')
def test_geo_opts(self):
points = self.df.hvplot.points('x', 'y', geo=True)
opts = hv.Store.lookup_options('bokeh', points, 'plot').kwargs
self.assertEqual(opts.get('data_aspect'), 1)
self.assertEqual(opts.get('width'), None)
def test_geo_opts_with_width(self):
points = self.df.hvplot.points('x', 'y', geo=True, width=200)
opts = hv.Store.lookup_options('bokeh', points, 'plot').kwargs
self.assertEqual(opts.get('data_aspect'), 1)
self.assertEqual(opts.get('width'), 200)
self.assertEqual(opts.get('height'), None)
class TestGeoPandas(TestCase):
def setUp(self):
try:
import geopandas as gpd # noqa
import geoviews # noqa
import cartopy.crs as ccrs # noqa
import shapely # noqa
except ImportError:
raise SkipTest('geopandas, geoviews, shapely or cartopy not available')
import hvplot.pandas # noqa
from shapely.geometry import Polygon
p_geometry = gpd.points_from_xy(
x=[12.45339, 12.44177, 9.51667, 6.13000, 158.14997],
y=[41.90328, 43.93610, 47.13372, 49.61166, 6.91664],
crs='EPSG:4326',
)
p_names = ['Vatican City', 'San Marino', 'Vaduz', 'Luxembourg', 'Palikir']
self.cities = gpd.GeoDataFrame(dict(name=p_names), geometry=p_geometry)
pg_geometry = [
Polygon(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))),
Polygon(((2, 2), (2, 3), (3, 3), (3, 2), (2, 2))),
]
pg_names = ['A', 'B']
self.polygons = gpd.GeoDataFrame(dict(name=pg_names), geometry=pg_geometry)
def test_points_hover_cols_is_empty_by_default(self):
points = self.cities.hvplot()
assert points.kdims == ['x', 'y']
assert points.vdims == []
def test_points_hover_cols_does_not_include_geometry_when_all(self):
points = self.cities.hvplot(x='x', y='y', hover_cols='all')
assert points.kdims == ['x', 'y']
assert points.vdims == ['index', 'name']
def test_points_hover_cols_when_all_and_use_columns_is_false(self):
points = self.cities.hvplot(x='x', hover_cols='all', use_index=False)
assert points.kdims == ['x', 'y']
assert points.vdims == ['name']
def test_points_hover_cols_index_in_list(self):
points = self.cities.hvplot(y='y', hover_cols=['index'])
assert points.kdims == ['x', 'y']
assert points.vdims == ['index']
def test_points_hover_cols_positional_arg_sets_color(self):
points = self.cities.hvplot('name')
assert points.kdims == ['x', 'y']
assert points.vdims == ['name']
opts = hv.Store.lookup_options('bokeh', points, 'style').kwargs
assert opts['color'] == 'name'
def test_points_hover_cols_with_c_set_to_name(self):
points = self.cities.hvplot(c='name')
assert points.kdims == ['x', 'y']
assert points.vdims == ['name']
opts = hv.Store.lookup_options('bokeh', points, 'style').kwargs
assert opts['color'] == 'name'
def test_points_hover_cols_with_by_set_to_name(self):
points = self.cities.hvplot(by='name')
assert isinstance(points, hv.core.overlay.NdOverlay)
assert points.kdims == ['name']
assert points.vdims == []
for element in points.values():
assert element.kdims == ['x', 'y']
assert element.vdims == []
def test_points_project_xlim_and_ylim(self):
points = self.cities.hvplot(geo=False, xlim=(-10, 10), ylim=(-20, -10))
opts = hv.Store.lookup_options('bokeh', points, 'plot').options
np.testing.assert_equal(opts['xlim'], (-10, 10))
np.testing.assert_equal(opts['ylim'], (-20, -10))
def test_points_project_xlim_and_ylim_with_geo(self):
points = self.cities.hvplot(geo=True, xlim=(-10, 10), ylim=(-20, -10))
opts = hv.Store.lookup_options('bokeh', points, 'plot').options
np.testing.assert_allclose(opts['xlim'], (-10, 10))
np.testing.assert_allclose(opts['ylim'], (-20, -10))
def test_polygons_by_subplots(self):
polygons = self.polygons.hvplot(geo=True, by='name', subplots=True)
assert isinstance(polygons, hv.core.layout.NdLayout)
def test_polygons_turns_off_hover_when_there_are_no_fields_to_include(self):
polygons = self.polygons.hvplot(geo=True)
opts = hv.Store.lookup_options('bokeh', polygons, 'plot').kwargs
assert 'hover' not in opts.get('tools')
def test_geometry_none(self):
polygons = self.polygons.copy()
polygons.geometry[1] = None
assert polygons.hvplot(geo=True)
def test_tiles_without_gv(self):
polygons = self.polygons.copy()
polygons_plot = polygons.hvplot(tiles=True)
polygons_plot.get(1).data.crs is None
polygons.crs = 'EPSG:4326'
polygons_plot = self.polygons.hvplot(tiles=True)
polygons_plot.get(1).data.crs == 'EPSG:3857'
class TestGeoUtil(TestCase):
def setUp(self):
if sys.platform == 'win32':
raise SkipTest('Skip geo tests on windows for now')
try:
import cartopy.crs as ccrs
except ImportError:
raise SkipTest('cartopy not available')
self.ccrs = ccrs
def test_proj_to_cartopy(self):
from ..util import proj_to_cartopy
crs = proj_to_cartopy('+init=epsg:26911')
assert isinstance(crs, self.ccrs.CRS)
def test_proj_to_cartopy_wkt_string(self):
from ..util import proj_to_cartopy
crs = proj_to_cartopy(
'GEOGCRS["unnamed",BASEGEOGCRS["unknown",DATUM["unknown",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],DERIVINGCONVERSION["unknown",METHOD["PROJ ob_tran o_proj=latlon"],PARAMETER["o_lon_p",0,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["o_lat_p",37.5,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["lon_0",357.5,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]]],CS[ellipsoidal,2],AXIS["longitude",east,ORDER[1],ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],AXIS["latitude",north,ORDER[2],ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]]]'
) # noqa: E501
assert isinstance(crs, self.ccrs.RotatedPole)
assert crs.proj4_params['lon_0'] == 357.5
assert crs.proj4_params['o_lat_p'] == 37.5