Skip to content

Commit

Permalink
Handle nans in bokeh Area and Spread plots
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Oct 25, 2018
1 parent df665cc commit c55b044
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 20 deletions.
60 changes: 40 additions & 20 deletions holoviews/plotting/bokeh/chart.py
Expand Up @@ -484,23 +484,43 @@ class SpreadPlot(ElementPlot):

_stream_data = False # Plot does not support streaming data

def get_data(self, element, ranges, style):
mapping = dict(x='x', y='y')
xvals = element.dimension_values(0)
mean = element.dimension_values(1)
neg_error = element.dimension_values(2)
pos_idx = 3 if len(element.dimensions()) > 3 else 2
pos_error = element.dimension_values(pos_idx)
def _split_area(self, xs, lower, upper):
"""
Splits area plots at nans and returns x- and y-coordinates for
each area separated by nans.
"""
split = np.where(np.isnan(xs) | np.isnan(lower) | np.isnan(upper))[0]
xvals = np.split(xs, split)
lower = np.split(lower, split)
upper = np.split(upper, split)
band_x, band_y = [], []
for i, (x, l, u) in enumerate(zip(xvals, lower, upper)):
if i:
x, l, u = x[1:], l[1:], u[1:]
if not len(x):
continue
band_x += [np.append(x, x[::-1]), np.array([np.nan])]
band_y += [np.append(l, u[::-1]), np.array([np.nan])]
if len(band_x):
return np.concatenate(band_x[:-1]), np.concatenate(band_y[:-1])
return [], []

lower = mean - neg_error
upper = mean + pos_error
band_x = np.append(xvals, xvals[::-1])
band_y = np.append(lower, upper[::-1])
if self.invert_axes:
data = dict(x=band_y, y=band_x)
else:
data = dict(x=band_x, y=band_y)
return data, mapping, style
def get_data(self, element, ranges, style):
mapping = dict(x='x', y='y')
xvals = element.dimension_values(0)
mean = element.dimension_values(1)
neg_error = element.dimension_values(2)
pos_idx = 3 if len(element.dimensions()) > 3 else 2
pos_error = element.dimension_values(pos_idx)
lower = mean - neg_error
upper = mean + pos_error

band_x, band_y = self._split_area(xvals, lower, upper)
if self.invert_axes:
data = dict(x=band_y, y=band_x)
else:
data = dict(x=band_x, y=band_y)
return data, mapping, style



Expand All @@ -522,18 +542,18 @@ def get_extents(self, element, ranges):
def get_data(self, element, ranges, style):
mapping = dict(x='x', y='y')
xs = element.dimension_values(0)
x2 = np.hstack((xs[::-1], xs))

if len(element.vdims) > 1:
bottom = element.dimension_values(2)
else:
bottom = np.zeros(len(element))
ys = np.hstack((bottom[::-1], element.dimension_values(1)))
top = element.dimension_values(1)

band_xs, band_ys = self._split_area(xs, bottom, top)
if self.invert_axes:
data = dict(x=ys, y=x2)
data = dict(x=band_ys, y=band_xs)
else:
data = dict(x=x2, y=ys)
data = dict(x=band_xs, y=band_ys)
return data, mapping, style


Expand Down
24 changes: 24 additions & 0 deletions tests/plotting/bokeh/testareaplot.py
@@ -0,0 +1,24 @@
import numpy as np

from holoviews.element import Area

from .testplot import TestBokehPlot, bokeh_renderer


class TestAreaPlot(TestBokehPlot):

def test_area_with_nans(self):
area = Area([1, 2, 3, np.nan, 5, 6, 7])
plot = bokeh_renderer.get_plot(area)
cds = plot.handles['cds']
self.assertEqual(cds.data['x'], np.array([0., 1., 2., 2., 1., 0., np.nan,
4., 5., 6., 6., 5., 4.]))
self.assertEqual(cds.data['y'], np.array([0., 0., 0., 3., 2., 1., np.nan,
0., 0., 0., 7., 6., 5.]))

def test_area_empty(self):
area = Area([])
plot = bokeh_renderer.get_plot(area)
cds = plot.handles['cds']
self.assertEqual(cds.data['x'], [])
self.assertEqual(cds.data['y'], [])
17 changes: 17 additions & 0 deletions tests/plotting/bokeh/testspreadplot.py
Expand Up @@ -18,3 +18,20 @@ def test_spread_stream_data(self):
cds = plot.handles['cds']
self.assertEqual(cds.data['x'], np.array([0., 1., 2., 3., 3., 2., 1., 0.]))
self.assertEqual(cds.data['y'], np.array([0.5, 1.8, 0.9, 3.5, 4.5, 1.1, 2.2, 1.5]))

def test_spread_with_nans(self):
spread = Spread([(0, 0, 0, 1), (1, 0, 0, 2), (2, 0, 0, 3), (3, np.nan, np.nan, np.nan),
(4, 0, 0, 5), (5, 0, 0, 6), (6, 0, 0, 7)], vdims=['y', 'neg', 'pos'])
plot = bokeh_renderer.get_plot(spread)
cds = plot.handles['cds']
self.assertEqual(cds.data['x'], np.array([0., 1., 2., 2., 1., 0., np.nan,
4., 5., 6., 6., 5., 4.]))
self.assertEqual(cds.data['y'], np.array([0., 0., 0., 3., 2., 1., np.nan,
0., 0., 0., 7., 6., 5.]))

def test_spread_empty(self):
spread = Spread([])
plot = bokeh_renderer.get_plot(spread)
cds = plot.handles['cds']
self.assertEqual(cds.data['x'], [])
self.assertEqual(cds.data['y'], [])

0 comments on commit c55b044

Please sign in to comment.