From 802af90ad81b5a5a4803da85aa1452f7fe9d21f7 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Wed, 13 Sep 2023 21:47:31 -0700 Subject: [PATCH 01/10] Add alpha dimension --- geoviews/util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/geoviews/util.py b/geoviews/util.py index 91ba8a8a..a12dfd0d 100644 --- a/geoviews/util.py +++ b/geoviews/util.py @@ -747,6 +747,8 @@ def from_xarray(da, crs=None, apply_transform=False, nan_nodata=False, **kwargs) from .element.geo import RGB, HvRGB el = RGB if 'crs' in kwargs else HvRGB vdims = el.vdims[:bands] + if bands == 4: + vdims.append("A") el = el(data, [x, y], vdims, **kwargs) if hasattr(el.data, 'attrs'): el.data.attrs = da.attrs From 9ab00b291c93c1287f572ff64ae153730565d201 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Wed, 3 Jan 2024 16:03:40 -0800 Subject: [PATCH 02/10] ImageStack for bokeh backend --- geoviews/__init__.py | 2 +- geoviews/element/__init__.py | 5 +++- geoviews/element/comparison.py | 3 ++- geoviews/element/geo.py | 39 ++++++++++++++++++++++++++--- geoviews/plotting/bokeh/__init__.py | 10 ++++++-- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/geoviews/__init__.py b/geoviews/__init__.py index c8a46be5..01d11226 100644 --- a/geoviews/__init__.py +++ b/geoviews/__init__.py @@ -9,7 +9,7 @@ from .annotators import annotate # noqa (API import) from .element import ( # noqa (API import) _Element, Feature, Tiles, WMTS, LineContours, FilledContours, - Text, Image, Points, Path, Polygons, Shape, Dataset, RGB, + Text, Image, ImageStack, Points, Path, Polygons, Shape, Dataset, RGB, Contours, Graph, TriMesh, Nodes, EdgePaths, QuadMesh, VectorField, HexTiles, Labels, Rectangles, Segments, WindBarbs ) diff --git a/geoviews/element/__init__.py b/geoviews/element/__init__.py index 6114b8a6..ad8e47a8 100644 --- a/geoviews/element/__init__.py +++ b/geoviews/element/__init__.py @@ -4,7 +4,7 @@ ) from .geo import (_Element, Feature, Tiles, is_geographic, # noqa (API import) - WMTS, Points, Image, Text, LineContours, RGB, + WMTS, Points, Image, ImageStack, Text, LineContours, RGB, FilledContours, Path, Polygons, Shape, Dataset, Contours, TriMesh, Graph, Nodes, EdgePaths, QuadMesh, VectorField, Labels, HexTiles, Rectangles, Segments, WindBarbs) @@ -51,6 +51,9 @@ def filledcontours(self, kdims=None, vdims=None, mdims=None, **kwargs): def image(self, kdims=None, vdims=None, mdims=None, **kwargs): return self(Image, kdims, vdims, mdims, **kwargs) + def image_stack(self, kdims=None, vdims=None, mdims=None, **kwargs): + return self(ImageStack, kdims, vdims, mdims, **kwargs) + def points(self, kdims=None, vdims=None, mdims=None, **kwargs): if kdims is None: kdims = self._element.kdims el_type = Points if is_geographic(self._element, kdims) else HvPoints diff --git a/geoviews/element/comparison.py b/geoviews/element/comparison.py index 8b6d148c..a245b830 100644 --- a/geoviews/element/comparison.py +++ b/geoviews/element/comparison.py @@ -2,7 +2,7 @@ from holoviews.element.comparison import Comparison as HvComparison -from .geo import Image, Points, LineContours, FilledContours, WindBarbs +from .geo import Image, ImageStack, Points, LineContours, FilledContours, WindBarbs class Comparison(HvComparison): @@ -10,6 +10,7 @@ class Comparison(HvComparison): def register(cls): super().register() cls.equality_type_funcs[Image] = cls.compare_dataset + cls.equality_type_funcs[ImageStack] = cls.compare_dataset cls.equality_type_funcs[Points] = cls.compare_dataset cls.equality_type_funcs[LineContours] = cls.compare_dataset cls.equality_type_funcs[FilledContours] = cls.compare_dataset diff --git a/geoviews/element/geo.py b/geoviews/element/geo.py index 12b46a43..985c4000 100644 --- a/geoviews/element/geo.py +++ b/geoviews/element/geo.py @@ -10,9 +10,9 @@ from holoviews.core import util from holoviews.element import ( Contours as HvContours, Graph as HvGraph, Image as HvImage, - Nodes as HvNodes, Path as HvPath, Polygons as HvPolygons, - RGB as HvRGB, Text as HvText, TriMesh as HvTriMesh, - QuadMesh as HvQuadMesh, Points as HvPoints, + ImageStack as HvImageStack, Nodes as HvNodes, Path as HvPath, + Polygons as HvPolygons, RGB as HvRGB, Text as HvText, + TriMesh as HvTriMesh, QuadMesh as HvQuadMesh, Points as HvPoints, VectorField as HvVectorField, HexTiles as HvHexTiles, Labels as HvLabels, Rectangles as HvRectangles, Segments as HvSegments, Geometry as HvGeometry, @@ -401,6 +401,39 @@ def from_xarray(cls, da, crs=None, apply_transform=False, return from_xarray(da, crs, apply_transform, **kwargs) +class ImageStack(_Element, HvImageStack): + """ + ImageStack expands the capabilities of Image to by supporting + multiple layers of images. + + As there is many ways to represent multiple layers of images, + the following options are supported: + + 1) A 3D Numpy array with the shape (y, x, level) + 2) A list of 2D Numpy arrays with identical shape (y, x) + 3) A dictionary where the keys will be set as the vdims and the + values are 2D Numpy arrays with identical shapes (y, x). + If the dictionary's keys matches the kdims of the element, + they need to be 1D arrays. + 4) A tuple containing (x, y, level_0, level_1, ...), + where the level is a 2D Numpy array in the shape of (y, x). + 5) An xarray DataArray or Dataset where its `coords` contain the kdims. + + If no kdims are supplied, x and y are used. + + If no vdims are supplied, and the naming can be inferred like with a dictionary + the levels will be named level_0, level_1, etc. + """ + + vdims = param.List(doc=""" + The dimension description of the data held in the matrix.""") + + group = param.String(default='ImageStack', constant=True) + + _ndim = 3 + + _vdim_reductions = {1: Image} + class QuadMesh(_Element, HvQuadMesh): """ diff --git a/geoviews/plotting/bokeh/__init__.py b/geoviews/plotting/bokeh/__init__.py index 1af833bf..46db98a6 100644 --- a/geoviews/plotting/bokeh/__init__.py +++ b/geoviews/plotting/bokeh/__init__.py @@ -14,10 +14,10 @@ from holoviews.plotting.bokeh.graphs import TriMeshPlot, GraphPlot from holoviews.plotting.bokeh.hex_tiles import hex_binning, HexTilesPlot from holoviews.plotting.bokeh.path import PolygonPlot, PathPlot, ContourPlot -from holoviews.plotting.bokeh.raster import RasterPlot, RGBPlot, QuadMeshPlot +from holoviews.plotting.bokeh.raster import RasterPlot, RGBPlot, QuadMeshPlot, ImageStackPlot from ...element import ( - WMTS, Points, Polygons, Path, Contours, Shape, Image, Feature, + WMTS, Points, Polygons, Path, Contours, Shape, Image, ImageStack, Feature, Text, RGB, Nodes, EdgePaths, Graph, TriMesh, QuadMesh, VectorField, Labels, HexTiles, LineContours, FilledContours, Rectangles, Segments ) @@ -140,6 +140,11 @@ class GeoRGBPlot(GeoPlot, RGBPlot): _project_operation = project_image.instance(fast=False) +class GeoImageStackPlot(GeoPlot, ImageStackPlot): + + _project_operation = project_image.instance(fast=False) + + class GeoPolygonPlot(GeoPlot, PolygonPlot): _project_operation = project_path @@ -293,6 +298,7 @@ def _process(self, element, key=None): Path: GeoPathPlot, Shape: GeoShapePlot, Image: GeoRasterPlot, + ImageStack: GeoImageStackPlot, RGB: GeoRGBPlot, LineContours: LineContourPlot, FilledContours: FilledContourPlot, From 87aa8117131f215caa97e4dfe392729b97c1641f Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Wed, 3 Jan 2024 16:42:24 -0800 Subject: [PATCH 03/10] Add MPL but still doesn't work --- geoviews/plotting/mpl/__init__.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/geoviews/plotting/mpl/__init__.py b/geoviews/plotting/mpl/__init__.py index 70aeb3be..55d977b0 100644 --- a/geoviews/plotting/mpl/__init__.py +++ b/geoviews/plotting/mpl/__init__.py @@ -27,7 +27,7 @@ from ...element import ( - Image, Points, Feature, WMTS, Tiles, Text, LineContours, + Image, ImageStack, Points, Feature, WMTS, Tiles, Text, LineContours, FilledContours, is_geographic, Path, Polygons, Shape, RGB, Contours, Nodes, EdgePaths, Graph, TriMesh, QuadMesh, VectorField, HexTiles, Labels, Rectangles, Segments, WindBarbs @@ -246,7 +246,6 @@ def update_handles(self, *args): return GeoPlot.update_handles(self, *args) - class GeoQuadMeshPlot(GeoPlot, QuadMeshPlot): _project_operation = project_quadmesh @@ -288,6 +287,24 @@ def update_handles(self, *args): return GeoPlot.update_handles(self, *args) +class GeoImageStackPlot(GeoImagePlot): + + style_opts = ['alpha', 'cmap', 'visible', 'filterrad', 'clims', 'norm'] + + def __init__(self, element, **params): + super().__init__(element, **params) + + def get_data(self, element, ranges, style): + self._norm_kwargs(element, ranges, style, element.vdims[0]) + style.pop('interpolation', None) + xs, ys, zs = geo_mesh(element) + xs = GridInterface._infer_interval_breaks(xs) + ys = GridInterface._infer_interval_breaks(ys) + if self.geographic: + style['transform'] = element.crs + return (xs, ys, zs), style, {} + + class GeoPointPlot(GeoPlot, PointPlot): """ Draws a scatter plot from the data in a Points Element. @@ -587,6 +604,7 @@ def draw_annotation(self, axis, data, crs, opts): Path: GeoPathPlot, Contours: GeoContourPlot, RGB: GeoRGBPlot, + ImageStack: GeoImageStackPlot, Shape: GeoShapePlot, Graph: GeoGraphPlot, TriMesh: GeoTriMeshPlot, From 04ba601c701ab468f1ba71e163d031af18be508c Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Wed, 3 Jan 2024 16:48:07 -0800 Subject: [PATCH 04/10] Sprinkle raises --- geoviews/plotting/mpl/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/geoviews/plotting/mpl/__init__.py b/geoviews/plotting/mpl/__init__.py index 55d977b0..e9cc1c38 100644 --- a/geoviews/plotting/mpl/__init__.py +++ b/geoviews/plotting/mpl/__init__.py @@ -287,11 +287,13 @@ def update_handles(self, *args): return GeoPlot.update_handles(self, *args) -class GeoImageStackPlot(GeoImagePlot): +class GeoImageStackPlot(GeoPlot): style_opts = ['alpha', 'cmap', 'visible', 'filterrad', 'clims', 'norm'] def __init__(self, element, **params): + print(element, **params) + raise super().__init__(element, **params) def get_data(self, element, ranges, style): @@ -302,9 +304,24 @@ def get_data(self, element, ranges, style): ys = GridInterface._infer_interval_breaks(ys) if self.geographic: style['transform'] = element.crs + raise return (xs, ys, zs), style, {} + def init_artists(self, ax, plot_args, plot_kwargs): + artist = ax.imshow(*plot_args, **plot_kwargs) + raise + return {'artist': artist} + + + def update_handles(self, *args): + """ + Update the elements of the plot. + """ + raise + return GeoPlot.update_handles(self, *args) + + class GeoPointPlot(GeoPlot, PointPlot): """ Draws a scatter plot from the data in a Points Element. From e62e91e929b27dbf1bc206f6db6e92576282bde1 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Tue, 9 Jan 2024 10:52:52 -0800 Subject: [PATCH 05/10] Remove [::-1] --- geoviews/plotting/mpl/__init__.py | 41 +++---------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/geoviews/plotting/mpl/__init__.py b/geoviews/plotting/mpl/__init__.py index e9cc1c38..15e8199e 100644 --- a/geoviews/plotting/mpl/__init__.py +++ b/geoviews/plotting/mpl/__init__.py @@ -267,9 +267,10 @@ class GeoRGBPlot(GeoImagePlot): def get_data(self, element, ranges, style): self._norm_kwargs(element, ranges, style, element.vdims[0]) style.pop('interpolation', None) - zs = get_raster_array(element)[::-1] + zs = get_raster_array(element) l, b, r, t = element.bounds.lbrt() style['extent'] = [l, r, b, t] + style['origin'] = 'upper' if self.geographic: style['transform'] = element.crs return (zs,), style, {} @@ -287,41 +288,6 @@ def update_handles(self, *args): return GeoPlot.update_handles(self, *args) -class GeoImageStackPlot(GeoPlot): - - style_opts = ['alpha', 'cmap', 'visible', 'filterrad', 'clims', 'norm'] - - def __init__(self, element, **params): - print(element, **params) - raise - super().__init__(element, **params) - - def get_data(self, element, ranges, style): - self._norm_kwargs(element, ranges, style, element.vdims[0]) - style.pop('interpolation', None) - xs, ys, zs = geo_mesh(element) - xs = GridInterface._infer_interval_breaks(xs) - ys = GridInterface._infer_interval_breaks(ys) - if self.geographic: - style['transform'] = element.crs - raise - return (xs, ys, zs), style, {} - - - def init_artists(self, ax, plot_args, plot_kwargs): - artist = ax.imshow(*plot_args, **plot_kwargs) - raise - return {'artist': artist} - - - def update_handles(self, *args): - """ - Update the elements of the plot. - """ - raise - return GeoPlot.update_handles(self, *args) - - class GeoPointPlot(GeoPlot, PointPlot): """ Draws a scatter plot from the data in a Points Element. @@ -621,7 +587,7 @@ def draw_annotation(self, axis, data, crs, opts): Path: GeoPathPlot, Contours: GeoContourPlot, RGB: GeoRGBPlot, - ImageStack: GeoImageStackPlot, + ImageStack: GeoRGBPlot, Shape: GeoShapePlot, Graph: GeoGraphPlot, TriMesh: GeoTriMeshPlot, @@ -630,7 +596,6 @@ def draw_annotation(self, axis, data, crs, opts): HexTiles: GeoHexTilesPlot, QuadMesh: GeoQuadMeshPlot}, 'matplotlib') - # Define plot and style options options = Store.options(backend='matplotlib') From 0316add840d40664e2d54cca6e04558faa7cdc0c Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Tue, 16 Jan 2024 13:19:07 -0800 Subject: [PATCH 06/10] Check for 1.18 --- geoviews/element/geo.py | 19 +++++++++++++++---- geoviews/plotting/bokeh/__init__.py | 9 +++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/geoviews/element/geo.py b/geoviews/element/geo.py index 985c4000..48eba244 100644 --- a/geoviews/element/geo.py +++ b/geoviews/element/geo.py @@ -10,16 +10,22 @@ from holoviews.core import util from holoviews.element import ( Contours as HvContours, Graph as HvGraph, Image as HvImage, - ImageStack as HvImageStack, Nodes as HvNodes, Path as HvPath, - Polygons as HvPolygons, RGB as HvRGB, Text as HvText, - TriMesh as HvTriMesh, QuadMesh as HvQuadMesh, Points as HvPoints, + Nodes as HvNodes, Path as HvPath, Polygons as HvPolygons, + RGB as HvRGB, Text as HvText, TriMesh as HvTriMesh, + QuadMesh as HvQuadMesh, Points as HvPoints, VectorField as HvVectorField, HexTiles as HvHexTiles, Labels as HvLabels, Rectangles as HvRectangles, Segments as HvSegments, Geometry as HvGeometry, ) +from holoviews import __version__ as _hv_version +try: + from holoviews import ImageStack as HvImageStack +except ImportError: + class HvImageStack: + # will check version below + pass from holoviews.element.selection import Selection2DExpr - from shapely.geometry.base import BaseGeometry from shapely.geometry import ( box, GeometryCollection, MultiPolygon, LineString, MultiLineString, @@ -425,6 +431,11 @@ class ImageStack(_Element, HvImageStack): the levels will be named level_0, level_1, etc. """ + def __init__(self, data, kdims=None, vdims=None, **params): + if _hv_version < '1.18': + raise ImportError('ImageStack requires HoloViews 1.18 or greater.') + super().__init__(data, kdims=kdims, vdims=vdims, **params) + vdims = param.List(doc=""" The dimension description of the data held in the matrix.""") diff --git a/geoviews/plotting/bokeh/__init__.py b/geoviews/plotting/bokeh/__init__.py index 46db98a6..718e07e7 100644 --- a/geoviews/plotting/bokeh/__init__.py +++ b/geoviews/plotting/bokeh/__init__.py @@ -14,8 +14,7 @@ from holoviews.plotting.bokeh.graphs import TriMeshPlot, GraphPlot from holoviews.plotting.bokeh.hex_tiles import hex_binning, HexTilesPlot from holoviews.plotting.bokeh.path import PolygonPlot, PathPlot, ContourPlot -from holoviews.plotting.bokeh.raster import RasterPlot, RGBPlot, QuadMeshPlot, ImageStackPlot - +from holoviews.plotting.bokeh.raster import RasterPlot, RGBPlot, QuadMeshPlot from ...element import ( WMTS, Points, Polygons, Path, Contours, Shape, Image, ImageStack, Feature, Text, RGB, Nodes, EdgePaths, Graph, TriMesh, QuadMesh, VectorField, @@ -29,7 +28,13 @@ from ...util import poly_types, line_types from .plot import GeoPlot, GeoOverlayPlot from . import callbacks # noqa +try: + from holoviews.plotting.bokeh.raster import ImageStackPlot +except ImportError: + class ImageStackPlot: + def __init__(self, *args, **kwargs): + raise ImportError('ImageStackPlot requires HoloViews>=1.18.0') class TilePlot(GeoPlot): From 4e977583a7320affa1fedb72eb4d348192d9d024 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Tue, 16 Jan 2024 13:31:16 -0800 Subject: [PATCH 07/10] Add test --- geoviews/tests/plotting/bokeh/test_chart.py | 24 +++++++++++++++++++++ geoviews/tests/plotting/mpl/test_chart.py | 23 ++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 geoviews/tests/plotting/bokeh/test_chart.py diff --git a/geoviews/tests/plotting/bokeh/test_chart.py b/geoviews/tests/plotting/bokeh/test_chart.py new file mode 100644 index 00000000..0181673f --- /dev/null +++ b/geoviews/tests/plotting/bokeh/test_chart.py @@ -0,0 +1,24 @@ + +import numpy as np +import geoviews as gv + +class TestImageStackPlot: + + def test_image_stack_crs(self): + x = np.arange(-120, -115) + y = np.arange(40, 43) + a = np.random.rand(len(y), len(x)) + b = np.random.rand(len(y), len(x)) + + img_stack = gv.ImageStack( + (x, y, a, b), kdims=["x", "y"], vdims=["a", "b"], + ) + data = img_stack.data + np.testing.assert_almost_equal(data["x"], x) + np.testing.assert_almost_equal(data["y"], y) + np.testing.assert_almost_equal(data["a"], a) + np.testing.assert_almost_equal(data["b"], b) + + fig = gv.render(img_stack, backend="bokeh") + assert fig.x_range + assert fig.y_range diff --git a/geoviews/tests/plotting/mpl/test_chart.py b/geoviews/tests/plotting/mpl/test_chart.py index 0af2cb17..f1cbdbca 100644 --- a/geoviews/tests/plotting/mpl/test_chart.py +++ b/geoviews/tests/plotting/mpl/test_chart.py @@ -195,3 +195,26 @@ def test_windbarbs_color_warning(self): "'flagcolor' and 'barbcolor'; ignoring 'flagcolor' and 'barbcolor'.\n" ) self.assertEqual(log_msg, warning) + + +class TestImageStackPlot(TestMPLPlot): + + def test_image_stack_crs(self): + x = np.arange(-120, -115) + y = np.arange(40, 43) + a = np.random.rand(len(y), len(x)) + b = np.random.rand(len(y), len(x)) + + img_stack = gv.ImageStack( + (x, y, a, b), kdims=["x", "y"], vdims=["a", "b"], + ) + data = img_stack.data + np.testing.assert_almost_equal(data["x"], x) + np.testing.assert_almost_equal(data["y"], y) + np.testing.assert_almost_equal(data["a"], a) + np.testing.assert_almost_equal(data["b"], b) + + fig = gv.render(img_stack) + mpl_img = fig.axes[0].get_children()[0] + np.testing.assert_almost_equal(mpl_img.get_extent(), (-120.5, -115.5, 39.5, 42.5)) + assert np.sum(mpl_img.get_array()) > 0 From 819a230a71f41b1555a238d3dd45ce8752b10c56 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Tue, 16 Jan 2024 13:34:42 -0800 Subject: [PATCH 08/10] FIx weird error --- .../tests/plotting/bokeh/{test_chart.py => test_bokeh_chart.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename geoviews/tests/plotting/bokeh/{test_chart.py => test_bokeh_chart.py} (100%) diff --git a/geoviews/tests/plotting/bokeh/test_chart.py b/geoviews/tests/plotting/bokeh/test_bokeh_chart.py similarity index 100% rename from geoviews/tests/plotting/bokeh/test_chart.py rename to geoviews/tests/plotting/bokeh/test_bokeh_chart.py From bf9b5f0a141ccb2d4c12fa1decaca4a6119a930c Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Mon, 22 Jan 2024 10:32:24 -0800 Subject: [PATCH 09/10] Address comments --- geoviews/element/geo.py | 18 ++++++++---------- geoviews/plotting/bokeh/__init__.py | 4 +--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/geoviews/element/geo.py b/geoviews/element/geo.py index 48eba244..eb00ff71 100644 --- a/geoviews/element/geo.py +++ b/geoviews/element/geo.py @@ -17,13 +17,6 @@ Labels as HvLabels, Rectangles as HvRectangles, Segments as HvSegments, Geometry as HvGeometry, ) -from holoviews import __version__ as _hv_version -try: - from holoviews import ImageStack as HvImageStack -except ImportError: - class HvImageStack: - # will check version below - pass from holoviews.element.selection import Selection2DExpr from shapely.geometry.base import BaseGeometry @@ -41,13 +34,18 @@ class HvImageStack: # when installing the package. Cube = None - - try: from owslib.wmts import WebMapTileService except ImportError: WebMapTileService = None +try: + from holoviews import ImageStack as HvImageStack + _IMAGESTACK_AVAILABLE = True +except ImportError: + class HvImageStack: ... + _IMAGESTACK_AVAILABLE = False + from ..util import ( path_to_geom_dicts, polygons_to_geom_dicts, load_tiff, from_xarray, poly_types, expand_geoms, transform_shapely @@ -432,7 +430,7 @@ class ImageStack(_Element, HvImageStack): """ def __init__(self, data, kdims=None, vdims=None, **params): - if _hv_version < '1.18': + if not _IMAGESTACK_AVAILABLE: raise ImportError('ImageStack requires HoloViews 1.18 or greater.') super().__init__(data, kdims=kdims, vdims=vdims, **params) diff --git a/geoviews/plotting/bokeh/__init__.py b/geoviews/plotting/bokeh/__init__.py index 718e07e7..a4243462 100644 --- a/geoviews/plotting/bokeh/__init__.py +++ b/geoviews/plotting/bokeh/__init__.py @@ -32,9 +32,7 @@ from holoviews.plotting.bokeh.raster import ImageStackPlot except ImportError: class ImageStackPlot: - - def __init__(self, *args, **kwargs): - raise ImportError('ImageStackPlot requires HoloViews>=1.18.0') + ... class TilePlot(GeoPlot): From c751dbae6a09de00839dee7772b19f4b2bcdc09d Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Mon, 22 Jan 2024 11:24:24 -0800 Subject: [PATCH 10/10] AAdd skiptest --- geoviews/tests/plotting/mpl/test_chart.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/geoviews/tests/plotting/mpl/test_chart.py b/geoviews/tests/plotting/mpl/test_chart.py index f1cbdbca..092f0bf1 100644 --- a/geoviews/tests/plotting/mpl/test_chart.py +++ b/geoviews/tests/plotting/mpl/test_chart.py @@ -1,3 +1,4 @@ +import pytest import numpy as np import xarray as xr import geoviews as gv @@ -10,6 +11,11 @@ from test_plot import TestMPLPlot +try: + import datashader +except ImportError: + datashader = None + mpl_renderer = Store.renderers["matplotlib"] @@ -199,6 +205,7 @@ def test_windbarbs_color_warning(self): class TestImageStackPlot(TestMPLPlot): + @pytest.mark.skipif(datashader is None, reason="Needs datashader to be installed") def test_image_stack_crs(self): x = np.arange(-120, -115) y = np.arange(40, 43)