Skip to content

Commit

Permalink
Fixed regression in datetime key handling on Widgets (#3228)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Nov 30, 2018
1 parent 456c92e commit df1720c
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 15 deletions.
5 changes: 3 additions & 2 deletions holoviews/plotting/bokeh/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,9 @@ class BokehSelectionWidget(BokehWidget, SelectionWidget):

def _get_data(self):
if not self.plot.dynamic:
_, _, init_dim_vals = self.get_widgets()
self.plot.update(tuple(init_dim_vals))
widgets, _, _ = self.get_widgets()
key = tuple(w['value'] for w in widgets)
self.plot.update(key)
return super(BokehSelectionWidget, self)._get_data()

class BokehScrubberWidget(BokehWidget, ScrubberWidget):
Expand Down
5 changes: 3 additions & 2 deletions holoviews/plotting/plotly/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ class PlotlySelectionWidget(PlotlyWidget, SelectionWidget):

def _get_data(self):
if not self.plot.dynamic:
_, _, init_dim_vals = self.get_widgets()
self.plot.update(tuple(init_dim_vals))
widgets, _, _ = self.get_widgets()
key = tuple(w['value'] for w in widgets)
self.plot.update(tuple(key))
return super(PlotlySelectionWidget, self)._get_data()

class PlotlyScrubberWidget(PlotlyWidget, ScrubberWidget):
Expand Down
25 changes: 15 additions & 10 deletions holoviews/plotting/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from ...core.options import Store
from ...core.ndmapping import item_check
from ...core.util import (
dimension_sanitizer, bytes_to_unicode, unique_array, unicode,
dimension_sanitizer, bytes_to_unicode, unique_iterator, unicode,
isnumeric, cross_index, wrap_tuple_streams, drop_streams
)
from ...core.traversal import hierarchical
Expand Down Expand Up @@ -350,32 +350,36 @@ def _get_static_widget(cls, idx, dim, mock_obj, hierarchy, init_dim_vals):
next_vals = {}
visible = True
if next_vals:
dim_vals = next_vals[init_dim_vals[idx-1]]
values = next_vals[init_dim_vals[idx-1]]
else:
dim_vals = (list(dim.values) if dim.values else
list(unique_array(mock_obj.dimension_values(dim.name))))
visible = visible and len(dim_vals) > 1
values = (list(dim.values) if dim.values else
list(unique_iterator(mock_obj.dimension_values(dim.name))))
visible = visible and len(values) > 1

if idx < mock_obj.ndims-1:
next_vals = hierarchy[idx]
next_dim = bytes_to_unicode(mock_obj.kdims[idx+1])
else:
next_vals = {}

if isinstance(dim_vals[0], np.datetime64):
dim_vals = sorted([str(v.astype('datetime64[ns]')) for v in dim_vals])
if isinstance(values[0], np.datetime64):
values = sorted(values)
dim_vals = [str(v.astype('datetime64[ns]')) for v in values]
widget_type = 'slider'
elif isnumeric(dim_vals[0]):
dim_vals = sorted([round(v, 10) for v in dim_vals])
elif isnumeric(values[0]):
values = sorted(values)
dim_vals = [round(v, 10) for v in values]
if next_vals:
next_vals = {round(k, 10): [round(v, 10) if isnumeric(v) else v
for v in vals]
for k, vals in next_vals.items()}
widget_type = 'slider'
else:
dim_vals = values
next_vals = dict(next_vals)
widget_type = 'dropdown'

value = values[0] if dim.default is None else dim.default
value_labels = escape_list(escape_vals([dim.pprint_value(v)
for v in dim_vals]))

Expand All @@ -393,7 +397,8 @@ def _get_static_widget(cls, idx, dim, mock_obj, hierarchy, init_dim_vals):
next_vals = escape_dict({k: escape_vals(v) for k, v in next_vals.items()})
return {'type': widget_type, 'vals': dim_vals, 'labels': value_labels,
'step': 1, 'default': default, 'next_vals': next_vals,
'next_dim': next_dim or None, 'init_val': init_val, 'visible': visible}
'next_dim': next_dim or None, 'init_val': init_val,
'visible': visible, 'value': value}


@classmethod
Expand Down
8 changes: 8 additions & 0 deletions holoviews/tests/plotting/bokeh/testwidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ def test_holomap_slider_unsorted_initialization(self):
self.assertEqual(slider['vals'], "['1.0', '3.0']")
self.assertEqual(slider['labels'], "['1', '3']")

def test_holomap_slider_unsorted_datetime_values_initialization(self):
hmap = HoloMap([(np.datetime64(10005, 'D'), Curve([1, 2, 3])),
(np.datetime64(10000, 'D'), Curve([1, 2, 4]))], sort=False)
widgets = bokeh_renderer.get_widget(hmap, 'widgets')
widgets()
self.assertEqual(widgets.plot.current_key, (np.datetime64(10000, 'D'),))
self.assertEqual(widgets.plot.current_frame, hmap[np.datetime64(10000, 'D')])

def test_holomap_dropdown(self):
hmap = HoloMap({chr(65+i): Curve([1, 2, 3]) for i in range(10)}, 'X')
widgets = bokeh_renderer.get_widget(hmap, 'widgets')
Expand Down
2 changes: 1 addition & 1 deletion holoviews/tests/plotting/matplotlib/testwidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def test_holomap_datetime_widgets(self):
'step': 1, 'default': 0, 'next_vals': '{}', 'next_dim': None,
'init_val': '2017-01-01T00:00:00.000000000', 'visible': True,
'dim': 'Default', 'dim_label': 'Default', 'dim_idx': 0,
'visibility': ''
'visibility': '', 'value': np.datetime64(dt.datetime(2017, 1, 1))
}
self.assertEqual(widget_data[0], expected)

Expand Down
27 changes: 27 additions & 0 deletions holoviews/tests/plotting/plotly/testwidgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from unittest import SkipTest
import numpy as np

from holoviews.core import HoloMap, Store
from holoviews.element import Curve
from holoviews.element.comparison import ComparisonTestCase

try:
import holoviews.plotting.plotly # noqa (Activate backend)
plotly_renderer = Store.renderers['plotly']
except:
plotly_renderer = None


class TestSelectionWidget(ComparisonTestCase):

def setUp(self):
if plotly_renderer is None:
raise SkipTest("Plotly required to test plotly widgets")

def test_holomap_slider_unsorted_datetime_values_initialization(self):
hmap = HoloMap([(np.datetime64(10005, 'D'), Curve([1, 2, 3])),
(np.datetime64(10000, 'D'), Curve([1, 2, 4]))], sort=False)
widgets = plotly_renderer.get_widget(hmap, 'widgets')
widgets()
self.assertEqual(widgets.plot.current_key, (np.datetime64(10000, 'D'),))
self.assertEqual(widgets.plot.current_frame, hmap[np.datetime64(10000, 'D')])

0 comments on commit df1720c

Please sign in to comment.