Skip to content

Commit

Permalink
Merge pull request #1086 from ioam/bokeh_box_timeseries
Browse files Browse the repository at this point in the history
Fix for datetime support on bokeh BoxPlot
  • Loading branch information
jlstevens committed Jan 30, 2017
2 parents 9829748 + f432840 commit bcf4b23
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 11 deletions.
5 changes: 5 additions & 0 deletions holoviews/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
Dimension.type_formatters[np.float64] = "%.5g"
Dimension.type_formatters[np.datetime64] = '%Y-%m-%d %H:%M:%S'

try:
import pandas as pd
Dimension.type_formatters[pd.tslib.Timestamp] = "%Y-%m-%d %H:%M:%S"
except:
pass

def public(obj):
if not isinstance(obj, type): return False
Expand Down
23 changes: 14 additions & 9 deletions holoviews/plotting/bokeh/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,24 +563,29 @@ class BoxPlot(ChartPlot):
"""
BoxPlot generates a box and whisker plot from a BoxWhisker
Element. This allows plotting the median, mean and various
percentiles. Displaying outliers is currently not supported
as they cannot be consistently updated.
percentiles.
"""

style_opts = ['color', 'whisker_color'] + line_properties
style_opts = ['color', 'whisker_color', 'marker'] + line_properties

def _init_chart(self, element, ranges):
properties = self.style[self.cyclic_index]
dframe = element.dframe()
label = element.dimensions('key', True)
if len(element.dimensions()) == 1:
dframe = element.dframe()

# Fix for displaying datetimes which are not handled by bokeh
for kd in element.kdims:
col = dframe[kd.name]
if col.dtype.kind in ('M',):
dframe[kd.name] = [kd.pprint_value(v).replace(':', ';')
for v in col]

if not element.kdims:
dframe[''] = ''
label = ['']
plot = BokehBoxPlot(dframe, label=label,
values=element.dimensions('value', True)[0],
**properties)

return plot
return BokehBoxPlot(dframe, label=label, values=element.vdims[0].name,
**properties)


class BarPlot(ChartPlot):
Expand Down
15 changes: 13 additions & 2 deletions tests/testplotinstantiation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import unicode_literals

import logging
import datetime as dt
from collections import deque
from unittest import SkipTest
from io import BytesIO, StringIO
Expand All @@ -14,7 +15,7 @@
NdOverlay, GridSpace, HoloMap, Layout)
from holoviews.element import (Curve, Scatter, Image, VLine, Points,
HeatMap, QuadMesh, Spikes, ErrorBars,
Scatter3D, Path, Polygons, Bars)
Scatter3D, Path, Polygons, Bars, BoxWhisker)
from holoviews.element.comparison import ComparisonTestCase
from holoviews.streams import PositionXY, PositionX
from holoviews.plotting import comms
Expand All @@ -32,7 +33,7 @@
import holoviews.plotting.bokeh
bokeh_renderer = Store.renderers['bokeh']
from holoviews.plotting.bokeh.callbacks import Callback
from bokeh.models import Div
from bokeh.models import Div, ColumnDataSource
from bokeh.models.mappers import LinearColorMapper, LogColorMapper
from bokeh.models.tools import HoverTool
except:
Expand Down Expand Up @@ -400,6 +401,16 @@ def test_points_non_numeric_size_warning(self):
'cannot use to scale Points size.\n' % plot.name)
self.assertEqual(log_msg, warning)

def test_box_whisker_datetime(self):
times = np.arange(dt.datetime(2017,1,1), dt.datetime(2017,2,1),
dt.timedelta(days=1))
box = BoxWhisker((times, np.random.rand(len(times))), kdims=['Date'])
plot = bokeh_renderer.get_plot(box)
formatted = [box.kdims[0].pprint_value(t).replace(':', ';') for t in times]
self.assertTrue(all('Date' in cds.data for cds in
plot.state.select(ColumnDataSource)))
self.assertTrue(cds.data['Date'][0] in formatted for cds in
plot.state.select(ColumnDataSource))


class TestPlotlyPlotInstantiation(ComparisonTestCase):
Expand Down

0 comments on commit bcf4b23

Please sign in to comment.