Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for bokeh 0.12 compatibility #725

Merged
merged 7 commits into from
Jun 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 2 additions & 14 deletions holoviews/plotting/bokeh/bokehwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,8 @@ var BokehMethods = {
var data = this.frames[current];
}
if (data !== undefined) {
if (data.root !== undefined) {
var doc = Bokeh.index[data.root].model.document;
}
$.each(data.data, function(i, value) {
if (data.root !== undefined) {
var ds = doc.get_model_by_id(value.id);
} else {
var ds = Bokeh.Collections(value.type).get(value.id);
}
if (ds != undefined) {
ds.set(value.data);
ds.trigger('change');
}
});
var doc = Bokeh.index[data.root].model.document;
doc.apply_json_patch(data.patch);
}
},
dynamic_update : function(current){
Expand Down
40 changes: 12 additions & 28 deletions holoviews/plotting/bokeh/callbacks.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
from collections import defaultdict

import numpy as np
from bokeh.models import CustomJS, TapTool, ColumnDataSource

try:
from bokeh.protocol import serialize_json
bokeh_lt_011 = True
except ImportError:
from bokeh.core.json_encoder import serialize_json
bokeh_lt_011 = False

import param

from ...core.data import ArrayColumns
from .util import models_to_json
from .util import compute_static_patch, models_to_json

from bokeh.models import CustomJS, TapTool, ColumnDataSource
from bokeh.core.json_encoder import serialize_json


class Callback(param.ParameterizedFunction):
Expand Down Expand Up @@ -73,20 +67,11 @@ class Callback(param.ParameterizedFunction):
function callback(msg){
if (msg.msg_type == "execute_result") {
var data = JSON.parse(msg.content.data['text/plain'].slice(1, -1));
if (data.root !== undefined) {
var doc = Bokeh.index[data.root].model.document;
if (data !== undefined) {
console.log(data.root)
var doc = Bokeh.index[data.root].model.document;
doc.apply_json_patch(data.patch);
}
$.each(data.data, function(i, value) {
if (data.root !== undefined) {
var ds = doc.get_model_by_id(value.id);
} else {
var ds = Bokeh.Collections(value.type).get(value.id);
}
if (ds != undefined) {
ds.set(value.data);
ds.trigger('change');
}
});
} else {
console.log("Python callback returned unexpected message:", msg)
}
Expand Down Expand Up @@ -147,14 +132,13 @@ def update(self, data, chained=False):
return self.serialize(objects)


def serialize(self, objects):
def serialize(self, models):
"""
Serializes any Bokeh plot objects passed to it as a list.
"""
data = dict(data=models_to_json(objects))
if not bokeh_lt_011:
plot = self.plots[0]
data['root'] = plot.state._id
plot = self.plots[0]
patch = compute_static_patch(plot.document, models)
data = dict(root=plot.state._id, patch=patch)
return serialize_json(data)


Expand Down
11 changes: 7 additions & 4 deletions holoviews/plotting/bokeh/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from ..util import compute_sizes, get_sideplot_ranges, match_spec, map_colors
from .element import ElementPlot, line_properties, fill_properties
from .path import PathPlot, PolygonPlot
from .util import get_cmap, mpl_to_bokeh, update_plot, rgb2hex
from .util import get_cmap, mpl_to_bokeh, update_plot, rgb2hex, bokeh_version


class PointPlot(ElementPlot):
Expand Down Expand Up @@ -377,11 +377,14 @@ class SideSpikesPlot(SpikesPlot):
all axis labels including ticks and ylabel. Valid options are 'left',
'right', 'bare' 'left-bare' and 'right-bare'.""")

border = param.Integer(default=30, doc="Default borders on plot")
border = param.Integer(default=30 if bokeh_version < '0.12' else 5,
doc="Default borders on plot")

height = param.Integer(default=100, doc="Height of plot")
height = param.Integer(default=100 if bokeh_version < '0.12' else 50,
doc="Height of plot")

width = param.Integer(default=100, doc="Width of plot")
width = param.Integer(default=100 if bokeh_version < '0.12' else 50,
doc="Width of plot")



Expand Down
58 changes: 42 additions & 16 deletions holoviews/plotting/bokeh/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
from ..util import dynamic_update
from .callbacks import Callbacks
from .plot import BokehPlot
from .renderer import bokeh_lt_011
from .util import mpl_to_bokeh, convert_datetime, update_plot
from .util import mpl_to_bokeh, convert_datetime, update_plot, bokeh_version


# Define shared style properties for bokeh plots
Expand Down Expand Up @@ -266,26 +265,27 @@ def _init_plot(self, key, element, plots, ranges=None):
properties['x_axis_label'] = xlabel if 'x' in self.show_labels else ' '
properties['y_axis_label'] = ylabel if 'y' in self.show_labels else ' '

if self.show_title:
title = self._format_title(key, separator=' ')
else:
title = ''

if LooseVersion(bokeh.__version__) >= LooseVersion('0.10'):
properties['webgl'] = self.renderer.webgl
return bokeh.plotting.Figure(x_axis_type=x_axis_type,
y_axis_type=y_axis_type,
y_axis_type=y_axis_type, title=title,
tools=tools, **properties)


def _plot_properties(self, key, plot, element):
"""
Returns a dictionary of plot properties.
"""
title_font = self._fontsize('title', 'title_text_font_size')
plot_props = dict(plot_height=self.height, plot_width=self.width,
title_text_color='black', **title_font)
if self.show_title:
plot_props['title'] = self._format_title(key, separator=' ')
plot_props = dict(plot_height=self.height, plot_width=self.width)
if bokeh_version < '0.12':
plot_props.update(self._title_properties(key, plot, element))
if self.bgcolor:
bg_attr = 'background_fill'
if not bokeh_lt_011: bg_attr += '_color'
plot_props[bg_attr] = self.bgcolor
plot_props['background_fill_color'] = self.bgcolor
if self.border is not None:
for p in ['left', 'right', 'top', 'bottom']:
plot_props['min_border_'+p] = self.border
Expand All @@ -295,6 +295,20 @@ def _plot_properties(self, key, plot, element):
return plot_props


def _title_properties(self, key, plot, element):
if self.show_title:
title = self._format_title(key, separator=' ')
else:
title = ''

if bokeh_version < '0.12':
title_font = self._fontsize('title', 'title_text_font_size')
return dict(title=title, title_text_color='black', **title_font)
else:
title_font = self._fontsize('title', 'text_font_size')
return dict(text=title, text_color='black', **title_font)


def _init_axes(self, plot):
if self.xaxis is None:
plot.xaxis.visible = False
Expand Down Expand Up @@ -350,6 +364,9 @@ def _update_plot(self, key, plot, element=None):
plot.xaxis[0].set(**props['x'])
plot.yaxis[0].set(**props['y'])

if bokeh_version >= '0.12':
plot.title.set(**self._title_properties(key, plot, element))

if not self.show_grid:
plot.xgrid.grid_line_color = None
plot.ygrid.grid_line_color = None
Expand Down Expand Up @@ -533,8 +550,20 @@ def current_handles(self):

plot = self.state
handles.append(plot)
if bokeh_version >= '0.12':
handles.append(plot.title)

if self.current_frame:
framewise = self.lookup_options(self.current_frame, 'norm').options.get('framewise')
if self.subplots:
current_frames = [(sp.current_frame if isinstance(sp.current_frame, Element)
else sp.current_frame.values()[0])
for sp in self.subplots.values()
if sp.current_frame]
framewise = any(self.lookup_options(frame, 'norm').options.get('framewise')
for frame in current_frames)
else:
opts = self.lookup_options(self.current_frame, 'norm')
framewise = opts.options.get('framewise')
if framewise or isinstance(self.hmap, DynamicMap):
handles += [plot.x_range, plot.y_range]
return handles
Expand Down Expand Up @@ -678,10 +707,7 @@ def _process_legend(self):
if legend_fontsize:
plot.legend[0].label_text_font_size = legend_fontsize

if bokeh_lt_011:
plot.legend.orientation = self.legend_position
else:
plot.legend.location = self.legend_position
plot.legend.location = self.legend_position
legends = plot.legend[0].legends
new_legends = []
for label, l in legends:
Expand Down
19 changes: 14 additions & 5 deletions holoviews/plotting/bokeh/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@
AdjointLayout, NdLayout, Empty, GridSpace, HoloMap)
from ...core import traversal
from ...core.options import Compositor
from ...core.util import basestring
from ...core.util import basestring, wrap_tuple
from ...element import Histogram
from ..plot import DimensionedPlot, GenericCompositePlot, GenericLayoutPlot
from ..util import get_dynamic_mode, initialize_sampled
from .renderer import BokehRenderer
from .util import layout_padding
from .util import bokeh_version, layout_padding

if bokeh_version >= '0.12':
from bokeh.layouts import gridplot


class BokehPlot(DimensionedPlot):
"""
Expand Down Expand Up @@ -253,15 +257,18 @@ def initialize_plot(self, ranges=None, plots=[]):
passed_plots = list(plots)
for i, coord in enumerate(self.layout.keys(full_grid=True)):
r = i % self.cols
subplot = self.subplots.get(coord, None)
subplot = self.subplots.get(wrap_tuple(coord), None)
if subplot is not None:
plot = subplot.initialize_plot(ranges=ranges, plots=passed_plots)
plots[r].append(plot)
passed_plots.append(plots[r][-1])
else:
plots[r].append(None)
passed_plots.append(None)
self.handles['plot'] = BokehGridPlot(children=plots[::-1])
if bokeh_version < '0.12':
self.handles['plot'] = BokehGridPlot(children=plots[::-1])
else:
self.handles['plot'] = gridplot(plots[::-1])
self.handles['plots'] = plots
if self.shared_datasource:
self.sync_sources()
Expand Down Expand Up @@ -481,7 +488,7 @@ def initialize_plot(self, ranges=None):

# Replace None types with empty plots
# to avoid bokeh bug
if adjoined:
if adjoined and bokeh_version < '0.12':
plots = layout_padding(plots)

# Determine the most appropriate composite plot type
Expand All @@ -496,6 +503,8 @@ def initialize_plot(self, ranges=None):
for c, child in enumerate(row)
if child is not None]
layout_plot = Tabs(tabs=panels)
elif bokeh_version >= '0.12':
layout_plot = gridplot(children=plots)
elif len(plots) == 1 and not adjoined:
layout_plot = VBox(children=[HBox(children=plots[0])])
elif len(plots[0]) == 1:
Expand Down
44 changes: 20 additions & 24 deletions holoviews/plotting/bokeh/renderer.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import uuid

from ...core import Store, HoloMap
from ..renderer import Renderer, MIME_TYPES
from .widgets import BokehScrubberWidget, BokehSelectionWidget
from .util import models_to_json
from .util import compute_static_patch

import param
from param.parameterized import bothmethod

import bokeh
from bokeh.embed import notebook_div
from bokeh.io import load_notebook
from bokeh.resources import CDN, INLINE
from bokeh.io import _CommsHandle
from bokeh.util.notebook import get_comms

try:
from bokeh.protocol import serialize_json
bokeh_lt_011 = True
except ImportError:
from bokeh.core.json_encoder import serialize_json
from bokeh.model import _ModelInDocument as add_to_document
bokeh_lt_011 = False
from bokeh.core.json_encoder import serialize_json
from bokeh.model import _ModelInDocument as add_to_document
from bokeh.document import Document


class BokehRenderer(Renderer):
Expand Down Expand Up @@ -55,30 +55,26 @@ def __call__(self, obj, fmt=None):
return plot(), info
elif fmt == 'html':
html = self.figure_data(plot)
html = '<center>%s</center>' % html
html = "<div style='display: table; margin: 0 auto;'>%s</div>" % html
return self._apply_post_render_hooks(html, obj, fmt), info
elif fmt == 'json':
plotobjects = [h for handles in plot.traverse(lambda x: x.current_handles)
for h in handles]
data = dict(data=[])
if not bokeh_lt_011:
data['root'] = plot.state._id
data['data'] = models_to_json(plotobjects)
patch = compute_static_patch(plot.document, plotobjects)
data = dict(root=plot.state._id, patch=patch)
return self._apply_post_render_hooks(serialize_json(data), obj, fmt), info


def figure_data(self, plot, fmt='html', **kwargs):
if not bokeh_lt_011:
doc_handler = add_to_document(plot.state)
with doc_handler:
doc = doc_handler._doc
comms_target = str(uuid.uuid4())
doc.last_comms_target = comms_target
div = notebook_div(plot.state, comms_target)
plot.document = doc
return div
else:
return notebook_div(plot.state)
doc_handler = add_to_document(plot.state)
with doc_handler:
doc = doc_handler._doc
comms_target = str(uuid.uuid4())
doc.last_comms_target = comms_target
div = notebook_div(plot.state, comms_target)
plot.document = doc
doc.add_root(plot.state)
return div


@classmethod
Expand Down
Loading