diff --git a/holoviews/plotting/bokeh/raster.py b/holoviews/plotting/bokeh/raster.py index c8d5153312..25285b68df 100644 --- a/holoviews/plotting/bokeh/raster.py +++ b/holoviews/plotting/bokeh/raster.py @@ -177,10 +177,17 @@ def get_data(self, element, ranges, style): img = np.dstack([element.dimension_values(d, flat=False) for d in element.vdims]) + + nan_mask = np.isnan(img) + img[nan_mask] = 0 + if img.ndim == 3: - if img.dtype.kind == 'f': + img_max = img.max() if img.size else np.nan + # Can be 0 to 255 if nodata has been used + if img.dtype.kind == 'f' and img_max <= 1: img = img*255 - if img.size and (img.min() < 0 or img.max() > 255): + # img_max * 255 <- have no effect + if img.size and (img.min() < 0 or img_max > 255): self.param.warning('Clipping input data to the valid ' 'range for RGB data ([0..1] for ' 'floats or [0..255] for integers).') @@ -197,6 +204,8 @@ def get_data(self, element, ranges, style): img = img.copy() img = img.view(dtype=np.uint32).reshape((N, M)) + img[nan_mask.any(-1)] = 0 + # Ensure axis inversions are handled correctly l, b, r, t = element.bounds.lbrt() if self.invert_axes: diff --git a/holoviews/tests/element/test_raster.py b/holoviews/tests/element/test_raster.py index cd3f5d5d41..8edf0f6f4a 100644 --- a/holoviews/tests/element/test_raster.py +++ b/holoviews/tests/element/test_raster.py @@ -55,6 +55,19 @@ def test_not_using_class_variables_vdims(self): assert i is not c assert i == c + def test_nodata(self): + N = 2 + rgb_d = np.linspace(0, 1, N * N * 3).reshape(N, N, 3) + rgb = RGB(rgb_d) + assert sum(np.isnan(rgb["R"])) == 0 + assert sum(np.isnan(rgb["G"])) == 0 + assert sum(np.isnan(rgb["B"])) == 0 + + rgb_n = rgb.redim.nodata(R=0) + assert sum(np.isnan(rgb_n["R"])) == 1 + assert sum(np.isnan(rgb_n["G"])) == 0 + assert sum(np.isnan(rgb_n["B"])) == 0 + class TestHSV(ComparisonTestCase): def setUp(self): diff --git a/holoviews/tests/plotting/bokeh/test_rasterplot.py b/holoviews/tests/plotting/bokeh/test_rasterplot.py index 51e0de98ba..319cd7f0e1 100644 --- a/holoviews/tests/plotting/bokeh/test_rasterplot.py +++ b/holoviews/tests/plotting/bokeh/test_rasterplot.py @@ -42,6 +42,15 @@ def test_nodata_array_uint(self): self.assertEqual(source.data['image'][0], np.array([[2, np.NaN], [np.NaN, 1]])) + def test_nodata_rgb(self): + N = 2 + rgb_d = np.linspace(0, 1, N * N * 3).reshape(N, N, 3) + rgb = RGB(rgb_d).redim.nodata(R=0) + plot = bokeh_renderer.get_plot(rgb) + image_data = plot.handles["source"].data["image"][0] + # Image sets nan-values to 0 + assert (image_data == 0).sum() == 1 + def test_raster_invert_axes(self): arr = np.array([[0, 1, 2], [3, 4, 5]]) raster = Raster(arr).opts(invert_axes=True)