From 1b4ebc88bfb3363fa306bea12e10ff41764fde6b Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 9 Apr 2019 11:58:02 +0100 Subject: [PATCH 1/3] Removed version warnings on draw callbacks --- holoviews/plotting/bokeh/callbacks.py | 59 +++------------------------ 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/holoviews/plotting/bokeh/callbacks.py b/holoviews/plotting/bokeh/callbacks.py index a7274f1b35..bce4e90c15 100644 --- a/holoviews/plotting/bokeh/callbacks.py +++ b/holoviews/plotting/bokeh/callbacks.py @@ -947,22 +947,11 @@ def _process_msg(self, msg): class PointDrawCallback(CDSCallback): def initialize(self, plot_id=None): - try: - from bokeh.models import PointDrawTool - except Exception: - param.main.param.warning('PointDraw requires bokeh >= 0.12.14') - return - stream = self.streams[0] renderers = [self.plot.handles['glyph_renderer']] kwargs = {} if stream.num_objects: - if bokeh_version >= '1.0.0': - kwargs['num_objects'] = stream.num_objects - else: - param.main.param.warning( - 'Specifying num_objects to PointDraw stream requires ' - 'a bokeh version >= 1.0.0.') + kwargs['num_objects'] = stream.num_objects point_tool = PointDrawTool(drag=all(s.drag for s in self.streams), empty_value=stream.empty_value, renderers=renderers, **kwargs) @@ -982,30 +971,15 @@ def initialize(self, plot_id=None): class PolyDrawCallback(CDSCallback): def initialize(self, plot_id=None): - try: - from bokeh.models import PolyDrawTool - except: - param.main.param.warning('PolyDraw requires bokeh >= 0.12.14') - return plot = self.plot stream = self.streams[0] kwargs = {} if stream.num_objects: - if bokeh_version >= '1.0.0': - kwargs['num_objects'] = stream.num_objects - else: - param.main.param.warning( - 'Specifying num_objects to PointDraw stream requires ' - 'a bokeh version >=1.0.0.') + kwargs['num_objects'] = stream.num_objects if stream.show_vertices: - if bokeh_version >= '1.0.0': - vertex_style = dict({'size': 10}, **stream.vertex_style) - r1 = plot.state.scatter([], [], **vertex_style) - kwargs['vertex_renderer'] = r1 - else: - param.main.param.warning( - 'Enabling vertices on the PointDraw stream requires ' - 'a bokeh version >=1.0.0.') + vertex_style = dict({'size': 10}, **stream.vertex_style) + r1 = plot.state.scatter([], [], **vertex_style) + kwargs['vertex_renderer'] = r1 poly_tool = PolyDrawTool(drag=all(s.drag for s in self.streams), empty_value=stream.empty_value, renderers=[plot.handles['glyph_renderer']], @@ -1032,11 +1006,6 @@ def _update_cds_vdims(self): class FreehandDrawCallback(PolyDrawCallback): def initialize(self, plot_id=None): - try: - from bokeh.models import FreehandDrawTool - except: - param.main.param.warning('FreehandDraw requires bokeh >= 0.13.0') - return plot = self.plot stream = self.streams[0] poly_tool = FreehandDrawTool( @@ -1055,24 +1024,13 @@ class BoxEditCallback(CDSCallback): models = ['rect_source'] def initialize(self, plot_id=None): - try: - from bokeh.models import BoxEditTool - except: - param.main.param.warning('BoxEdit requires bokeh >= 0.12.14') - return - plot = self.plot data = plot.handles['cds'].data element = self.plot.current_frame stream = self.streams[0] kwargs = {} if stream.num_objects: - if bokeh_version >= '1.0.0': - kwargs['num_objects'] = stream.num_objects - else: - param.main.param.warning( - 'Specifying num_objects to BoxEdit stream requires ' - 'a bokeh version >=1.0.0.') + kwargs['num_objects'] = stream.num_objects xs, ys, widths, heights = [], [], [], [] for x, y in zip(data['xs'], data['ys']): x0, x1 = (np.nanmin(x), np.nanmax(x)) @@ -1115,11 +1073,6 @@ def _process_msg(self, msg): class PolyEditCallback(PolyDrawCallback): def initialize(self, plot_id=None): - try: - from bokeh.models import PolyEditTool - except: - param.main.param.warning('PolyEdit requires bokeh >= 0.12.14') - return plot = self.plot vertex_tool = None if all(s.shared for s in self.streams): From 52558069c6a0f6a1409098e50f152f41a9f0ad56 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 9 Apr 2019 11:58:42 +0100 Subject: [PATCH 2/3] Added support for cycling through styles on PolyDrawCallback --- holoviews/plotting/bokeh/callbacks.py | 38 ++++++++++++++++++++++++--- holoviews/streams.py | 8 +++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/holoviews/plotting/bokeh/callbacks.py b/holoviews/plotting/bokeh/callbacks.py index bce4e90c15..c3a62efc6e 100644 --- a/holoviews/plotting/bokeh/callbacks.py +++ b/holoviews/plotting/bokeh/callbacks.py @@ -6,7 +6,8 @@ import numpy as np from bokeh.models import ( CustomJS, FactorRange, DatetimeAxis, ColumnDataSource, ToolbarBox, - Range1d, DataRange1d + Range1d, DataRange1d, PolyDrawTool, BoxEditTool, PolyEditTool, + FreehandDrawTool, PointDrawTool ) from pyviz_comms import JS_CALLBACK @@ -16,7 +17,8 @@ RangeY, PointerX, PointerY, BoundsX, BoundsY, Tap, SingleTap, DoubleTap, MouseEnter, MouseLeave, PlotSize, Draw, BoundsXY, PlotReset, BoxEdit, - PointDraw, PolyDraw, PolyEdit, CDSStream, FreehandDraw) + PointDraw, PolyDraw, PolyEdit, CDSStream, + FreehandDraw) from ..links import Link, RangeToolLink, DataLink from ..plot import GenericElementPlot, GenericOverlayPlot from .util import convert_timestamp, bokeh_version @@ -944,6 +946,34 @@ def _process_msg(self, msg): return msg +class DrawCallback(CDSCallback): + + _style_callback = """ + var length = cb_obj.data['xs'].length; + for (i = 0; i < length; i++) { + for (var style in styles) { + if (cb_obj.data[style][i] === empty) { + var values = styles[style]; + cb_obj.data[style][i] = values[i % values.length]; + } + } + } + """ + + def _create_style_callback(self): + plot = self.plot + stream = self.streams[0] + cds = plot.handles['cds'] + for style, values in stream.style_cycles.items(): + cds.data[style] = [values[i % len(values)] for i in range(len(cds.data['xs']))] + glyph = plot.handles['glyph'] + setattr(glyph, style, style) + cb = CustomJS(code=self._style_callback, + args={'styles': stream.style_cycles, + 'empty': stream.empty_value}) + cds.js_on_change('data', cb) + + class PointDrawCallback(CDSCallback): def initialize(self, plot_id=None): @@ -968,7 +998,7 @@ def initialize(self, plot_id=None): super(PointDrawCallback, self).initialize(plot_id) -class PolyDrawCallback(CDSCallback): +class PolyDrawCallback(DrawCallback): def initialize(self, plot_id=None): plot = self.plot @@ -980,6 +1010,8 @@ def initialize(self, plot_id=None): vertex_style = dict({'size': 10}, **stream.vertex_style) r1 = plot.state.scatter([], [], **vertex_style) kwargs['vertex_renderer'] = r1 + if stream.style_cycles: + self._create_style_callback() poly_tool = PolyDrawTool(drag=all(s.drag for s in self.streams), empty_value=stream.empty_value, renderers=[plot.handles['glyph_renderer']], diff --git a/holoviews/streams.py b/holoviews/streams.py index 0b439cc1d1..64fb4d962c 100644 --- a/holoviews/streams.py +++ b/holoviews/streams.py @@ -997,15 +997,21 @@ class PolyDraw(CDSStream): A dictionary specifying the style options for the vertices. The usual bokeh style options apply, e.g. fill_color, line_alpha, size, etc. + + style_cycles: dict + A dictionary specifying lists of styles to cycle over whenever + a new Poly glyph is drawn. """ def __init__(self, empty_value=None, drag=True, num_objects=0, - show_vertices=False, vertex_style={}, **params): + show_vertices=False, vertex_style={}, style_cycles={}, + **params): self.drag = drag self.empty_value = empty_value self.num_objects = num_objects self.show_vertices = show_vertices self.vertex_style = vertex_style + self.style_cycles = style_cycles super(PolyDraw, self).__init__(**params) @property From bd96564159ef98484e7d20c8702b58b280ca085f Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 9 Apr 2019 12:15:12 +0100 Subject: [PATCH 3/3] Fixed flakes --- holoviews/plotting/bokeh/callbacks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/holoviews/plotting/bokeh/callbacks.py b/holoviews/plotting/bokeh/callbacks.py index c3a62efc6e..e09b2b0ea8 100644 --- a/holoviews/plotting/bokeh/callbacks.py +++ b/holoviews/plotting/bokeh/callbacks.py @@ -21,7 +21,7 @@ FreehandDraw) from ..links import Link, RangeToolLink, DataLink from ..plot import GenericElementPlot, GenericOverlayPlot -from .util import convert_timestamp, bokeh_version +from .util import convert_timestamp class MessageCallback(object): @@ -946,7 +946,7 @@ def _process_msg(self, msg): return msg -class DrawCallback(CDSCallback): +class GlyphDrawCallback(CDSCallback): _style_callback = """ var length = cb_obj.data['xs'].length; @@ -998,7 +998,7 @@ def initialize(self, plot_id=None): super(PointDrawCallback, self).initialize(plot_id) -class PolyDrawCallback(DrawCallback): +class PolyDrawCallback(GlyphDrawCallback): def initialize(self, plot_id=None): plot = self.plot