Skip to content

Commit

Permalink
Fixed bug initializing PolyDrawCallback (#2679)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored and jlstevens committed May 14, 2018
1 parent 26d7b22 commit 32b07e8
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 23 deletions.
4 changes: 1 addition & 3 deletions holoviews/plotting/bokeh/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,12 +922,10 @@ def initialize(self):
empty_value=self.streams[0].empty_value,
renderers=[plot.handles['glyph_renderer']])
plot.state.tools.append(poly_tool)

element = plot.current_frame
x, y = element.dimensions('key', label=True)
data = dict(plot.handles['source'].data)
for stream in self.streams:
stream.update(data=data)
super(CDSCallback, self).initialize()


class BoxEditCallback(CDSCallback):
Expand Down
97 changes: 77 additions & 20 deletions tests/plotting/bokeh/testcallbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from holoviews.element.comparison import ComparisonTestCase
from holoviews.streams import (PointDraw, PolyDraw, PolyEdit, BoxEdit,
PointerXY, PointerX)
from holoviews.plotting import comms

try:
from bokeh.models import PolyEditTool
Expand All @@ -18,9 +19,11 @@
)
from holoviews.plotting.bokeh.renderer import BokehRenderer
from holoviews.plotting.bokeh.util import bokeh_version
bokeh_renderer = BokehRenderer.instance(mode='server')
bokeh_server_renderer = BokehRenderer.instance(mode='server')
bokeh_renderer = BokehRenderer.instance()
except:
bokeh_renderer = None
bokeh_server_renderer = None


class TestCallbacks(ComparisonTestCase):
Expand All @@ -31,22 +34,23 @@ def setUp(self):

def tearDown(self):
Store.current_backend = self.previous_backend
bokeh_server_renderer.last_plot = None
bokeh_renderer.last_plot = None
Callback._callbacks = {}

def test_stream_callback(self):
dmap = DynamicMap(lambda x, y: Points([(x, y)]), kdims=[], streams=[PointerXY()])
plot = bokeh_renderer.get_plot(dmap)
bokeh_renderer(plot)
plot = bokeh_server_renderer.get_plot(dmap)
bokeh_server_renderer(plot)
plot.callbacks[0].on_msg({"x": 10, "y": -10})
data = plot.handles['source'].data
self.assertEqual(data['x'], np.array([10]))
self.assertEqual(data['y'], np.array([-10]))

def test_stream_callback_with_ids(self):
dmap = DynamicMap(lambda x, y: Points([(x, y)]), kdims=[], streams=[PointerXY()])
plot = bokeh_renderer.get_plot(dmap)
bokeh_renderer(plot)
plot = bokeh_server_renderer.get_plot(dmap)
bokeh_server_renderer(plot)
model = plot.state
plot.callbacks[0].on_msg({"x": {'id': model.ref['id'], 'value': 10},
"y": {'id': model.ref['id'], 'value': -10}})
Expand All @@ -60,8 +64,8 @@ def history_callback(x, history=deque(maxlen=10)):
return Curve(list(history))
stream = PointerX(x=0)
dmap = DynamicMap(history_callback, kdims=[], streams=[stream])
plot = bokeh_renderer.get_plot(dmap)
bokeh_renderer(plot)
plot = bokeh_server_renderer.get_plot(dmap)
bokeh_server_renderer(plot)
for i in range(20):
stream.event(x=i)
data = plot.handles['source'].data
Expand All @@ -71,7 +75,7 @@ def history_callback(x, history=deque(maxlen=10)):
def test_callback_cleanup(self):
stream = PointerX(x=0)
dmap = DynamicMap(lambda x: Curve([x]), streams=[stream])
plot = bokeh_renderer.get_plot(dmap)
plot = bokeh_server_renderer.get_plot(dmap)
self.assertTrue(bool(stream._subscribers))
self.assertTrue(bool(Callback._callbacks))
plot.cleanup()
Expand All @@ -83,36 +87,47 @@ class TestEditToolCallbacks(ComparisonTestCase):

def setUp(self):
self.previous_backend = Store.current_backend
if not bokeh_renderer or bokeh_version < '0.12.14':
if not bokeh_server_renderer or bokeh_version < '0.12.14':
raise SkipTest("Bokeh >= 0.12.14 required to test edit tool streams")
Store.current_backend = 'bokeh'
self.comm_manager = bokeh_renderer.comm_manager
bokeh_renderer.comm_manager = comms.CommManager

def tearDown(self):
Store.current_backend = self.previous_backend
bokeh_server_renderer.last_plot = None
bokeh_renderer.last_plot = None
Callback._callbacks = {}
bokeh_renderer.comm_manager = self.comm_manager

def test_point_draw_callback(self):
points = Points([(0, 1)])
point_draw = PointDraw(source=points)
plot = bokeh_renderer.get_plot(points)
plot = bokeh_server_renderer.get_plot(points)
self.assertIsInstance(plot.callbacks[0], PointDrawCallback)
callback = plot.callbacks[0]
data = {'x': [1, 2, 3], 'y': [1, 2, 3]}
callback.on_msg({'data': data})
self.assertEqual(point_draw.element, Points(data))

def test_point_draw_callback_initialize(self):
def test_point_draw_callback_initialized_server(self):
points = Points([(0, 1)])
point_draw = PointDraw(source=points)
PointDraw(source=points)
plot = bokeh_server_renderer.get_plot(points)
self.assertEqual(plot.handles['source']._callbacks,
{'data': [plot.callbacks[0].on_change]})

def test_point_draw_callback_initialized_js(self):
points = Points([(0, 1)])
PointDraw(source=points)
plot = bokeh_renderer.get_plot(points)
self.assertIsInstance(plot.callbacks[0], PointDrawCallback)
self.assertEqual(point_draw.element, points)
self.assertEqual(plot.handles['source'].js_property_callbacks,
{'change:data': [plot.callbacks[0].callbacks[0]]})

def test_point_draw_callback_with_vdims(self):
points = Points([(0, 1, 'A')], vdims=['A'])
point_draw = PointDraw(source=points)
plot = bokeh_renderer.get_plot(points)
plot = bokeh_server_renderer.get_plot(points)
self.assertIsInstance(plot.callbacks[0], PointDrawCallback)
callback = plot.callbacks[0]
data = {'x': [1, 2, 3], 'y': [1, 2, 3], 'A': [None, None, 1]}
Expand All @@ -122,18 +137,32 @@ def test_point_draw_callback_with_vdims(self):
def test_poly_draw_callback(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
poly_draw = PolyDraw(source=polys)
plot = bokeh_renderer.get_plot(polys)
plot = bokeh_server_renderer.get_plot(polys)
self.assertIsInstance(plot.callbacks[0], PolyDrawCallback)
callback = plot.callbacks[0]
data = {'x': [[1, 2, 3], [3, 4, 5]], 'y': [[1, 2, 3], [3, 4, 5]]}
callback.on_msg({'data': data})
element = Polygons([[(1, 1), (2, 2), (3, 3)], [(3, 3), (4, 4), (5, 5)]])
self.assertEqual(poly_draw.element, element)

def test_poly_draw_callback_initialized_server(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
PolyDraw(source=polys)
plot = bokeh_server_renderer.get_plot(polys)
self.assertEqual(plot.handles['source']._callbacks,
{'data': [plot.callbacks[0].on_change]})

def test_poly_draw_callback_initialized_js(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
PolyDraw(source=polys)
plot = bokeh_renderer.get_plot(polys)
self.assertEqual(plot.handles['source'].js_property_callbacks,
{'change:data': [plot.callbacks[0].callbacks[0]]})

def test_poly_draw_callback_with_vdims(self):
polys = Polygons([{'x': [0, 2, 4], 'y': [0, 2, 0], 'A': 1}], vdims=['A'])
poly_draw = PolyDraw(source=polys)
plot = bokeh_renderer.get_plot(polys)
plot = bokeh_server_renderer.get_plot(polys)
self.assertIsInstance(plot.callbacks[0], PolyDrawCallback)
callback = plot.callbacks[0]
data = {'x': [[1, 2, 3], [3, 4, 5]], 'y': [[1, 2, 3], [3, 4, 5]], 'A': [1, 2]}
Expand All @@ -145,7 +174,7 @@ def test_poly_draw_callback_with_vdims(self):
def test_box_edit_callback(self):
boxes = Polygons([Box(0, 0, 1)])
box_edit = BoxEdit(source=boxes)
plot = bokeh_renderer.get_plot(boxes)
plot = bokeh_server_renderer.get_plot(boxes)
self.assertIsInstance(plot.callbacks[0], BoxEditCallback)
callback = plot.callbacks[0]
source = plot.handles['rect_source']
Expand All @@ -155,23 +184,51 @@ def test_box_edit_callback(self):
element = Polygons([Box(0, 0, (0.5, 2)), Box(1, 1, (2, 0.5))])
self.assertEqual(box_edit.element, element)

def test_box_edit_callback_initialized_server(self):
boxes = Polygons([Box(0, 0, 1)])
BoxEdit(source=boxes)
plot = bokeh_server_renderer.get_plot(boxes)
self.assertEqual(plot.handles['rect_source']._callbacks,
{'data': [plot.callbacks[0].on_change]})

def test_box_edit_callback_initialized_js(self):
boxes = Polygons([Box(0, 0, 1)])
BoxEdit(source=boxes)
plot = bokeh_renderer.get_plot(boxes)
self.assertEqual(plot.handles['rect_source'].js_property_callbacks,
{'change:data': [plot.callbacks[0].callbacks[0]]})

def test_poly_edit_callback(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
poly_edit = PolyEdit(source=polys)
plot = bokeh_renderer.get_plot(polys)
plot = bokeh_server_renderer.get_plot(polys)
self.assertIsInstance(plot.callbacks[0], PolyEditCallback)
callback = plot.callbacks[0]
data = {'x': [[1, 2, 3], [3, 4, 5]], 'y': [[1, 2, 3], [3, 4, 5]]}
callback.on_msg({'data': data})
element = Polygons([[(1, 1), (2, 2), (3, 3)], [(3, 3), (4, 4), (5, 5)]])
self.assertEqual(poly_edit.element, element)

def test_poly_edit_callback_initialized_server(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
PolyEdit(source=polys)
plot = bokeh_server_renderer.get_plot(polys)
self.assertEqual(plot.handles['source']._callbacks,
{'data': [plot.callbacks[0].on_change]})

def test_poly_edit_callback_initialized_js(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
PolyEdit(source=polys)
plot = bokeh_renderer.get_plot(polys)
self.assertEqual(plot.handles['source'].js_property_callbacks,
{'change:data': [plot.callbacks[0].callbacks[0]]})

def test_poly_edit_shared_callback(self):
polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
polys2 = Polygons([[(0, 0), (2, 2), (4, 0)]])
poly_edit = PolyEdit(source=polys, shared=True)
poly_edit2 = PolyEdit(source=polys2, shared=True)
plot = bokeh_renderer.get_plot(polys*polys2)
plot = bokeh_server_renderer.get_plot(polys*polys2)
edit_tools = [t for t in plot.state.tools if isinstance(t, PolyEditTool)]
self.assertEqual(len(edit_tools), 1)
plot1, plot2 = plot.subplots.values()
Expand Down

0 comments on commit 32b07e8

Please sign in to comment.