Skip to content

Commit

Permalink
Merge pull request #923 from ioam/get_dynamic_item_fix
Browse files Browse the repository at this point in the history
Ensured dynamic callback is only called once
  • Loading branch information
jlstevens authored Oct 10, 2016
2 parents d4186ec + ce05161 commit 3f9842d
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 7 deletions.
6 changes: 4 additions & 2 deletions holoviews/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,8 @@ def get_dynamic_item(map_obj, dimensions, key):
dmaps = map_obj.traverse(lambda x: x, ['DynamicMap'])
dmap = dmaps[0] if dmaps else map_obj
if key == () and (not dimensions or not dmap.kdims):
return key, map_obj.map(lambda x: x[()], ['DynamicMap', 'HoloMap'])
return key, map_obj.map(lambda x: x[()], ['DynamicMap', 'HoloMap'],
clone=False)
elif isinstance(key, tuple):
dims = {d.name: k for d, k in zip(dimensions, key)
if d in map_obj.kdims}
Expand All @@ -967,7 +968,8 @@ def get_dynamic_item(map_obj, dimensions, key):
key_offset = max([key-map_obj.cache_size, 0])
key = map_obj.keys()[min([key-key_offset,
len(map_obj)-1])]
el = map_obj.map(lambda x: x[key], ['DynamicMap'])
el = map_obj.map(lambda x: x[key], ['DynamicMap'],
clone=False)
elif key >= map_obj.counter:
el = next(map_obj)
key = list(map_obj.keys())[-1]
Expand Down
57 changes: 52 additions & 5 deletions tests/testplotinstantiation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Tests of plot instantiation (not display tests, just instantiation)
"""

from collections import deque
from unittest import SkipTest
from io import BytesIO

Expand All @@ -12,7 +13,7 @@
HeatMap, QuadMesh, Spikes, ErrorBars,
Scatter3D)
from holoviews.element.comparison import ComparisonTestCase
from holoviews.streams import PositionXY
from holoviews.streams import PositionXY, PositionX
from holoviews.plotting import comms

# Standardize backend due to random inconsistencies
Expand Down Expand Up @@ -46,11 +47,11 @@ def setUp(self):
Store.current_backend = 'matplotlib'
if mpl_renderer is None:
raise SkipTest("Matplotlib required to test plot instantiation")
self.default_comm, _ = mpl_renderer.comms['default']
self.default_comm = mpl_renderer.comms['default']
mpl_renderer.comms['default'] = (comms.Comm, '')

def teardown(self):
mpl_renderer.comms['default'] = (self.default_comm, '')
mpl_renderer.comms['default'] = self.default_comm
Store.current_backend = self.previous_backend

def test_interleaved_overlay(self):
Expand Down Expand Up @@ -87,6 +88,19 @@ def test_errorbar_test(self):
plot = mpl_renderer.get_plot(errorbars)
plot.initialize_plot()

def test_stream_callback_single_call(self):
def history_callback(x, history=deque(maxlen=10)):
history.append(x)
return Curve(list(history))
stream = PositionX()
dmap = DynamicMap(history_callback, kdims=[], streams=[stream])
plot = mpl_renderer.get_plot(dmap)
mpl_renderer(plot)
for i in range(20):
stream.update(x=i)
x, y = plot.handles['artist'].get_data()
self.assertEqual(x, np.arange(10))
self.assertEqual(y, np.arange(10, 20))


class TestBokehPlotInstantiation(ComparisonTestCase):
Expand All @@ -97,13 +111,13 @@ def setUp(self):
raise SkipTest("Bokeh required to test plot instantiation")
Store.current_backend = 'bokeh'
Callback._comm_type = comms.Comm
self.default_comm, _ = bokeh_renderer.comms['default']
self.default_comm = bokeh_renderer.comms['default']
bokeh_renderer.comms['default'] = (comms.Comm, '')

def teardown(self):
Store.current_backend = self.previous_backend
Callback._comm_type = comms.JupyterCommJS
mpl_renderer.comms['default'] = (self.default_comm, '')
mpl_renderer.comms['default'] = self.default_comm

def test_batched_plot(self):
overlay = NdOverlay({i: Points(np.arange(i)) for i in range(1, 100)})
Expand Down Expand Up @@ -156,16 +170,35 @@ def test_stream_callback(self):
self.assertEqual(data['y'], np.array([-10]))


def test_stream_callback_single_call(self):
def history_callback(x, history=deque(maxlen=10)):
history.append(x)
return Curve(list(history))
stream = PositionX()
dmap = DynamicMap(history_callback, kdims=[], streams=[stream])
plot = bokeh_renderer.get_plot(dmap)
bokeh_renderer(plot)
for i in range(20):
stream.update(x=i)
data = plot.handles['source'].data
self.assertEqual(data['x'], np.arange(10))
self.assertEqual(data['y'], np.arange(10, 20))


class TestPlotlyPlotInstantiation(ComparisonTestCase):

def setUp(self):
self.previous_backend = Store.current_backend
Store.current_backend = 'plotly'
self.default_comm = bokeh_renderer.comms['default']
if not plotly_renderer:
raise SkipTest("Plotly required to test plot instantiation")
plotly_renderer.comms['default'] = (comms.Comm, '')


def teardown(self):
Store.current_backend = self.previous_backend
plotly_renderer.comms['default'] = self.default_comm

def _get_plot_state(self, element):
plot = plotly_renderer.get_plot(element)
Expand Down Expand Up @@ -219,3 +252,17 @@ def test_grid_state(self):
self.assertEqual(state['data'][3]['y'], np.array([1, 1]))
self.assertEqual(state['data'][3]['xaxis'], 'x2')
self.assertEqual(state['data'][3]['yaxis'], 'y2')

def test_stream_callback_single_call(self):
def history_callback(x, history=deque(maxlen=10)):
history.append(x)
return Curve(list(history))
stream = PositionX()
dmap = DynamicMap(history_callback, kdims=[], streams=[stream])
plot = plotly_renderer.get_plot(dmap)
plotly_renderer(plot)
for i in range(20):
stream.update(x=i)
state = plot.state
self.assertEqual(state['data'][0]['x'], np.arange(10))
self.assertEqual(state['data'][0]['y'], np.arange(10, 20))

0 comments on commit 3f9842d

Please sign in to comment.