Skip to content

Commit

Permalink
Ensure linked streams are resolved on HoloMap and Table objects (#2252)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Feb 9, 2018
1 parent 660fa1f commit 6e2892e
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 38 deletions.
33 changes: 0 additions & 33 deletions holoviews/plotting/bokeh/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,39 +179,6 @@ def __init__(self, element, plot=None, **params):
self._shared = {'x': False, 'y': False}


def _construct_callbacks(self):
"""
Initializes any callbacks for streams which have defined
the plotted object as a source.
"""
if isinstance(self, OverlayPlot):
zorders = []
elif self.batched:
zorders = list(range(self.zorder, self.zorder+len(self.hmap.last)))
else:
zorders = [self.zorder]

if isinstance(self, OverlayPlot) and not self.batched:
sources = []
elif not self.static or isinstance(self.hmap, DynamicMap):
sources = [(i, o) for i, inputs in self.stream_sources.items()
for o in inputs if i in zorders]
else:
sources = [(self.zorder, self.hmap.last)]
cb_classes = set()
for _, source in sources:
streams = Stream.registry.get(id(source), [])
registry = Stream._callbacks['bokeh']
cb_classes |= {(registry[type(stream)], stream) for stream in streams
if type(stream) in registry and stream.linked}
cbs = []
sorted_cbs = sorted(cb_classes, key=lambda x: id(x[0]))
for cb, group in groupby(sorted_cbs, lambda x: x[0]):
cb_streams = [s for _, s in group]
cbs.append(cb(self, cb_streams, source))
return cbs


def _hover_opts(self, element):
if self.batched:
dims = list(self.hmap.last.kdims)
Expand Down
40 changes: 38 additions & 2 deletions holoviews/plotting/bokeh/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
from bokeh.models.widgets import Panel, Tabs

from ...core import (OrderedDict, Store, GridMatrix, AdjointLayout,
NdLayout, Empty, GridSpace, HoloMap, Element)
NdLayout, Empty, GridSpace, HoloMap, Element,
DynamicMap)
from ...core.util import basestring, wrap_tuple, unique_iterator
from ...element import Histogram
from ...streams import Stream
from ..plot import (DimensionedPlot, GenericCompositePlot, GenericLayoutPlot,
GenericElementPlot)
GenericElementPlot, GenericOverlayPlot)
from ..util import attach_streams
from .util import (layout_padding, pad_plots, filter_toolboxes, make_axis,
update_shared_sources, empty_plot)
Expand Down Expand Up @@ -99,6 +101,40 @@ def get_data(self, element, ranges, style):
raise NotImplementedError


def _construct_callbacks(self):
"""
Initializes any callbacks for streams which have defined
the plotted object as a source.
"""
if isinstance(self, GenericOverlayPlot):
zorders = []
elif self.batched:
zorders = list(range(self.zorder, self.zorder+len(self.hmap.last)))
else:
zorders = [self.zorder]

if isinstance(self, GenericOverlayPlot) and not self.batched:
sources = []
elif not self.static or isinstance(self.hmap, DynamicMap):
sources = [(i, o) for i, inputs in self.stream_sources.items()
for o in inputs if i in zorders]
else:
sources = [(self.zorder, self.hmap.last)]

cb_classes = set()
for _, source in sources:
streams = Stream.registry.get(id(source), [])
registry = Stream._callbacks['bokeh']
cb_classes |= {(registry[type(stream)], stream) for stream in streams
if type(stream) in registry and stream.linked}
cbs = []
sorted_cbs = sorted(cb_classes, key=lambda x: id(x[0]))
for cb, group in groupby(sorted_cbs, lambda x: x[0]):
cb_streams = [s for _, s in group]
cbs.append(cb(self, cb_streams, source))
return cbs


def push(self):
"""
Pushes updated plot data via the Comm.
Expand Down
4 changes: 2 additions & 2 deletions holoviews/plotting/bokeh/tabular.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ def __init__(self, element, plot=None, **params):
self.handles = {} if plot is None else self.handles['plot']
element_ids = self.hmap.traverse(lambda x: id(x), [Dataset, ItemTable])
self.static = len(set(element_ids)) == 1 and len(self.keys) == len(self.hmap)
self.callbacks = [] # Callback support on tables not implemented
self.callbacks = self._construct_callbacks()
self.streaming = [s for s in self.streams if isinstance(s, Buffer)]

self.static_source = False

def _execute_hooks(self, element):
"""
Expand Down
7 changes: 7 additions & 0 deletions holoviews/plotting/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ def compute_overlayable_zorders(obj, path=[]):
if isinstance(obj, CompositeOverlay):
for z, o in enumerate(obj):
zorder_map[z] = [o, obj]
elif isinstance(obj, HoloMap):
for el in obj.values():
if isinstance(el, CompositeOverlay):
for k, v in compute_overlayable_zorders(el, path).items():
zorder_map[k] += v + [obj]
else:
zorder_map[0] += [obj, el]
else:
if obj not in zorder_map[0]:
zorder_map[0].append(obj)
Expand Down
15 changes: 14 additions & 1 deletion tests/testplotutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np

from holoviews import NdOverlay, Overlay
from holoviews.core.spaces import DynamicMap
from holoviews.core.spaces import DynamicMap, HoloMap
from holoviews.core.options import Store, Cycle
from holoviews.element.comparison import ComparisonTestCase
from holoviews.element import Curve, Area, Points
Expand All @@ -21,6 +21,19 @@

class TestOverlayableZorders(ComparisonTestCase):

def test_compute_overlayable_zorders_holomap(self):
hmap = HoloMap({0: Points([])})
sources = compute_overlayable_zorders(hmap)
self.assertEqual(sources[0], [hmap, hmap.last])

def test_compute_overlayable_zorders_with_overlaid_holomap(self):
points = Points([])
hmap = HoloMap({0: points})
curve = Curve([])
combined = hmap*curve
sources = compute_overlayable_zorders(combined)
self.assertEqual(sources[0], [points, combined.last, combined])

def test_dynamic_compute_overlayable_zorders_two_mixed_layers(self):
area = Area(range(10))
dmap = DynamicMap(lambda: Curve(range(10)), kdims=[])
Expand Down

0 comments on commit 6e2892e

Please sign in to comment.