Skip to content

Commit

Permalink
Improved handling of the bokeh root model and comm (#3066)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored and jlstevens committed Oct 9, 2018
1 parent b4f2b53 commit aae1590
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 24 deletions.
20 changes: 10 additions & 10 deletions holoviews/plotting/bokeh/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def get_customjs(self, references, plot_id=None):
"""
# Generate callback JS code to get all the requested data
if plot_id is None:
plot_id = self.plot.id if self.plot.top_level else 'PLACEHOLDER_PLOT_ID'
plot_id = self.plot.id or 'PLACEHOLDER_PLOT_ID'
self_callback = self.js_callback.format(comm_id=self.comm.id,
timeout=self.timeout,
debounce=self.debounce,
Expand Down Expand Up @@ -1067,8 +1067,8 @@ class LinkCallback(param.Parameterized):
source_code = None
target_code = None

def __init__(self, root_plot, link, source_plot, target_plot=None):
self.root_plot = root_plot
def __init__(self, root_model, link, source_plot, target_plot=None):
self.root_model = root_model
self.link = link
self.source_plot = source_plot
self.target_plot = target_plot
Expand Down Expand Up @@ -1121,6 +1121,7 @@ def find_links(cls, root_plot):
for plot, links in source_links:
for link in links:
if link.target is None:
# If link has no target don't look further
found.append((link, plot, None))
continue
potentials = [cls.find_link(plot, link) for plot in plots]
Expand Down Expand Up @@ -1156,22 +1157,21 @@ class RangeToolLinkCallback(LinkCallback):
specified axes on the target plot
"""

def __init__(self, root_plot, link, source_plot, target_plot):
def __init__(self, root_model, link, source_plot, target_plot):
try:
from bokeh.models.tools import RangeTool
except:
raise Exception('RangeToolLink requires bokeh >= 0.13')
toolbar = [model for model in root_plot.state.children
if isinstance(model, ToolbarBox)]
toolbars = list(root_model.select({'type': ToolbarBox}))
axes = {}
if 'x' in link.axes:
axes['x_range'] = target_plot.handles['x_range']
if 'y' in link.axes:
axes['y_range'] = target_plot.handles['y_range']
tool = RangeTool(**axes)
source_plot.state.add_tools(tool)
if toolbar:
toolbar = toolbar[0].toolbar
if toolbars:
toolbar = toolbars[0].toolbar
toolbar.tools.append(tool)


Expand All @@ -1180,7 +1180,7 @@ class DataLinkCallback(LinkCallback):
Merges the source and target ColumnDataSource
"""

def __init__(self, root_plot, link, source_plot, target_plot):
def __init__(self, root_model, link, source_plot, target_plot):
src_cds = source_plot.handles['source']
tgt_cds = target_plot.handles['source']
src_len = [len(v) for v in src_cds.data.values()]
Expand Down Expand Up @@ -1214,7 +1214,7 @@ def __init__(self, root_plot, link, source_plot, target_plot):
renderer.view.update(source=src_cds)
target_plot.handles['source'] = src_cds
for callback in target_plot.callbacks:
callback.initialize(plot_id=root_plot.id)
callback.initialize(plot_id=root_model.ref['id'])


callbacks = Link._callbacks['bokeh']
Expand Down
4 changes: 4 additions & 0 deletions holoviews/plotting/bokeh/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,10 @@ class OverlayPlot(GenericOverlayPlot, LegendPlot):
'legend_cols', 'gridstyle', 'legend_muted', 'padding',
'xlim', 'ylim', 'zlim']

def __init__(self, overlay, **params):
super(OverlayPlot, self).__init__(overlay, **params)
self.set_root(params.pop('root', None))

def _process_legend(self):
plot = self.handles['plot']
if not self.show_legend or len(plot.legend) == 0:
Expand Down
27 changes: 19 additions & 8 deletions holoviews/plotting/bokeh/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,18 @@ class BokehPlot(DimensionedPlot):
def document(self):
return self._document


@property
def id(self):
return self.state.ref['id']
return self.root.ref['id'] if self.root else None

@property
def root(self):
if self._root:
return self._root
elif 'plot' in self.handles and self.top_level:
return self.state
else:
return None

@document.setter
def document(self, doc):
Expand All @@ -104,9 +111,10 @@ def document(self, doc):


def __init__(self, *args, **params):
root = params.pop('root', None)
super(BokehPlot, self).__init__(*args, **params)
self._document = None
self.root = None
self._root = root


def get_data(self, element, ranges, style):
Expand Down Expand Up @@ -175,10 +183,12 @@ def push(self):

def set_root(self, root):
"""
Sets the current document on all subplots.
Sets the root model on all subplots.
"""
if root is None:
return
for plot in self.traverse(lambda x: x):
plot.root = root
plot._root = root


def _init_datasource(self, data):
Expand Down Expand Up @@ -324,12 +334,11 @@ def sync_sources(self):
plots.append(plot)
shared_sources.append(new_source)
source_cols[id(new_source)] = [c for c in new_source.data]
plot_id = self.id if self.top_level else None
for plot in plots:
for hook in plot.finalize_hooks:
hook(plot, plot.current_frame)
for callback in plot.callbacks:
callback.initialize(plot_id=plot_id)
callback.initialize(plot_id=self.id)
self.handles['shared_sources'] = shared_sources
self.handles['source_cols'] = source_cols

Expand All @@ -338,7 +347,7 @@ def init_links(self):
callbacks = []
for link, src_plot, tgt_plot in links:
cb = Link._callbacks['bokeh'][type(link)]
callbacks.append(cb(self, link, src_plot, tgt_plot))
callbacks.append(cb(self.root, link, src_plot, tgt_plot))
return callbacks


Expand Down Expand Up @@ -464,6 +473,7 @@ def __init__(self, layout, ranges=None, layout_num=1, keys=None, **params):
ranges=ranges, keys=keys, **params)
self.cols, self.rows = layout.shape
self.subplots, self.layout = self._create_subplots(layout, ranges)
self.set_root(params.pop('root', None))
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
Expand Down Expand Up @@ -664,6 +674,7 @@ class LayoutPlot(CompositePlot, GenericLayoutPlot):
def __init__(self, layout, keys=None, **params):
super(LayoutPlot, self).__init__(layout, keys=keys, **params)
self.layout, self.subplots, self.paths = self._init_layout(layout)
self.set_root(params.pop('root', None))
if self.top_level:
self.comm = self.init_comm()
self.traverse(lambda x: setattr(x, 'comm', self.comm))
Expand Down
4 changes: 2 additions & 2 deletions holoviews/plotting/bokeh/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def _save_prefix(self_or_cls, ext):


@bothmethod
def get_plot(self_or_cls, obj, doc=None, renderer=None):
def get_plot(self_or_cls, obj, doc=None, renderer=None, **kwargs):
"""
Given a HoloViews Viewable return a corresponding plot instance.
Allows supplying a document attach the plot to, useful when
Expand All @@ -159,7 +159,7 @@ def get_plot(self_or_cls, obj, doc=None, renderer=None):
if self_or_cls.notebook_context:
curdoc().theme = self_or_cls.theme
doc.theme = self_or_cls.theme
plot = super(BokehRenderer, self_or_cls).get_plot(obj, renderer)
plot = super(BokehRenderer, self_or_cls).get_plot(obj, renderer, **kwargs)
plot.document = doc
return plot

Expand Down
7 changes: 5 additions & 2 deletions holoviews/plotting/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ class DimensionedPlot(Plot):

def __init__(self, keys=None, dimensions=None, layout_dimensions=None,
uniform=True, subplot=False, adjoined=None, layout_num=0,
style=None, subplots=None, dynamic=False, renderer=None, **params):
style=None, subplots=None, dynamic=False, renderer=None,
comm=None, **params):
self.subplots = subplots
self.adjoined = adjoined
self.dimensions = dimensions
Expand All @@ -236,7 +237,7 @@ def __init__(self, keys=None, dimensions=None, layout_dimensions=None,
self.current_key = None
self.ranges = {}
self.renderer = renderer if renderer else Store.renderers[self.backend].instance()
self.comm = None
self.comm = comm
self._force = False
self._updated = False # Whether the plot should be marked as updated

Expand Down Expand Up @@ -572,6 +573,8 @@ def init_comm(self):
"""
Initializes comm and attaches streams.
"""
if self.comm:
return self.comm
comm = None
if self.dynamic or self.renderer.widget_mode == 'live':
comm = self.renderer.comm_manager.get_server_comm()
Expand Down
5 changes: 3 additions & 2 deletions holoviews/plotting/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def __init__(self, **params):


@bothmethod
def get_plot(self_or_cls, obj, renderer=None):
def get_plot(self_or_cls, obj, renderer=None, **kwargs):
"""
Given a HoloViews Viewable return a corresponding plot instance.
"""
Expand All @@ -193,7 +193,8 @@ def get_plot(self_or_cls, obj, renderer=None):
renderer = self_or_cls.instance()
if not isinstance(obj, Plot):
obj = Layout.from_values(obj) if isinstance(obj, AdjointLayout) else obj
plot_opts = self_or_cls.plot_options(obj, self_or_cls.size)
plot_opts = dict(self_or_cls.plot_options(obj, self_or_cls.size),
**kwargs)
plot = self_or_cls.plotting_class(obj)(obj, renderer=renderer,
**plot_opts)
defaults = [kd.default for kd in plot.dimensions]
Expand Down

0 comments on commit aae1590

Please sign in to comment.