diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 31577e11f8..1b9b4aa0c9 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -1127,8 +1127,11 @@ def _update_glyph(self, renderer, properties, mapping, glyph, source, data): allowed_properties = glyph.properties() properties = mpl_to_bokeh(properties) merged = dict(properties, **mapping) - legend_prop = 'legend_label' if bokeh_version >= '1.3.5' else 'legend' - legend = merged.pop(legend_prop, None) + legend_props = ('legend_field', 'legend_label') if bokeh_version >= '1.3.5' else ('legend',) + for lp in legend_props: + legend = merged.pop(lp, None) + if legend is not None: + break columns = list(source.data.keys()) glyph_updates = [] for glyph_type in ('', 'selection_', 'nonselection_', 'hover_', 'muted_'): @@ -1170,7 +1173,16 @@ def _update_glyph(self, renderer, properties, mapping, glyph, source, data): for leg in self.state.legend: for item in leg.items: if renderer in item.renderers: - item.label = legend + if isinstance(legend, dict): + label = legend + elif lp != 'legend': + prop = 'value' if 'label' in lp else 'field' + label = {prop: legend} + elif isinstance(item.label, dict): + label = {list(item.label)[0]: legend} + else: + label = {'value': legend} + item.label = label for glyph, update in glyph_updates: glyph.update(**update) @@ -1758,7 +1770,7 @@ def _get_color_data(self, element, ranges, style, name='color', factors=None, co data[field] = cdata if factors is not None and self.show_legend: legend_prop = 'legend_field' if bokeh_version >= '1.3.5' else 'legend' - mapping[legend_prop] = {'field': field} + mapping[legend_prop] = field mapping[name] = {'field': field, 'transform': mapper} return data, mapping diff --git a/holoviews/tests/plotting/bokeh/testoverlayplot.py b/holoviews/tests/plotting/bokeh/testoverlayplot.py index ef38bab5f8..b7e58ac698 100644 --- a/holoviews/tests/plotting/bokeh/testoverlayplot.py +++ b/holoviews/tests/plotting/bokeh/testoverlayplot.py @@ -209,7 +209,7 @@ class TestLegends(TestBokehPlot): def test_overlay_legend(self): overlay = Curve(range(10), label='A') * Curve(range(10), label='B') plot = bokeh_renderer.get_plot(overlay) - legend_labels = [l.label for l in plot.state.legend[0].items] + legend_labels = [l.label['value'] for l in plot.state.legend[0].items] self.assertEqual(legend_labels, ['A', 'B']) def test_dynamic_subplot_remapping(self): @@ -220,7 +220,7 @@ def cb(X): plot = bokeh_renderer.get_plot(dmap) plot.update((3,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['1', '2']) + self.assertEqual(legend_labels, [{'value': '1'}, {'value': '2'}]) colors = Cycle().values for i, (subplot, color) in enumerate(zip(plot.subplots.values(), colors[3:])): self.assertEqual(subplot.handles['glyph'].line_color, color) @@ -232,25 +232,25 @@ def test_holomap_legend_updates(self): for i in range(3)}) plot = bokeh_renderer.get_plot(hmap) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['C', 'B']) + self.assertEqual(legend_labels, [{'value': 'C'}, {'value': 'B'}]) plot.update((1,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['B', 'D']) + self.assertEqual(legend_labels, [{'value': 'B'}, {'value': 'D'}]) plot.update((2,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['B', 'E']) + self.assertEqual(legend_labels, [{'value': 'B'}, {'value': 'E'}]) def test_holomap_legend_updates_varying_lengths(self): hmap = HoloMap({i: Overlay([Curve([1, 2, j], label=chr(65+j)) for j in range(i)]) for i in range(1, 4)}) plot = bokeh_renderer.get_plot(hmap) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['A']) + self.assertEqual(legend_labels, [{'value': 'A'}]) plot.update((2,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['A', 'B']) + self.assertEqual(legend_labels, [{'value': 'A'}, {'value': 'B'}]) plot.update((3,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['A', 'B', 'C']) + self.assertEqual(legend_labels, [{'value': 'A'}, {'value': 'B'}, {'value': 'C'}]) def test_dynamicmap_legend_updates(self): hmap = HoloMap({i: Curve([1, 2, 3], label=chr(65+i+2)) * Curve([1, 2, 3], label='B') @@ -258,26 +258,26 @@ def test_dynamicmap_legend_updates(self): dmap = Dynamic(hmap) plot = bokeh_renderer.get_plot(dmap) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['C', 'B']) + self.assertEqual(legend_labels, [{'value': 'C'}, {'value': 'B'}]) plot.update((1,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['D', 'B']) + self.assertEqual(legend_labels, [{'value': 'D'}, {'value': 'B'}]) plot.update((2,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['E', 'B']) + self.assertEqual(legend_labels, [{'value': 'E'}, {'value': 'B'}]) def test_dynamicmap_legend_updates_add_dynamic_plots(self): hmap = HoloMap({i: Overlay([Curve([1, 2, j], label=chr(65+j)) for j in range(i)]) for i in range(1, 4)}) dmap = Dynamic(hmap) plot = bokeh_renderer.get_plot(dmap) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['A']) + self.assertEqual(legend_labels, [{'value': 'A'}]) plot.update((2,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['A', 'B']) + self.assertEqual(legend_labels, [{'value': 'A'}, {'value': 'B'}]) plot.update((3,)) legend_labels = [item.label for item in plot.state.legend[0].items] - self.assertEqual(legend_labels, ['A', 'B', 'C']) + self.assertEqual(legend_labels, [{'value': 'A'}, {'value': 'B'}, {'value': 'C'}]) def test_dynamicmap_ndoverlay_shrink_number_of_items(self): selected = Stream.define('selected', items=3)() @@ -287,4 +287,3 @@ def callback(items): plot = bokeh_renderer.get_plot(dmap) selected.event(items=2) self.assertEqual(len([r for r in plot.state.renderers if r.visible]), 2) - diff --git a/holoviews/tests/plotting/bokeh/testpathplot.py b/holoviews/tests/plotting/bokeh/testpathplot.py index 96a4615bfa..761691d637 100644 --- a/holoviews/tests/plotting/bokeh/testpathplot.py +++ b/holoviews/tests/plotting/bokeh/testpathplot.py @@ -181,7 +181,8 @@ def test_path_continuously_varying_color_legend(self): path = Path(data, vdims="cat").opts(color="cat", cmap=dict(zip(levels, colors)), line_width=4, show_legend=True) plot = bokeh_renderer.get_plot(path) item = plot.state.legend[0].items[0] - self.assertEqual(item.label, 'color_str__') + legend = {'field': 'color_str__'} + self.assertEqual(item.label, legend) self.assertEqual(item.renderers, [plot.handles['glyph_renderer']])