diff --git a/holoviews/plotting/bokeh/chart.py b/holoviews/plotting/bokeh/chart.py index 912e9f39b4..cce6c5177d 100644 --- a/holoviews/plotting/bokeh/chart.py +++ b/holoviews/plotting/bokeh/chart.py @@ -803,7 +803,7 @@ def get_extents(self, element, ranges, range_type='combined'): return (x0, y0, x1, y1) - def _get_factors(self, element): + def _get_factors(self, element, ranges): """ Get factors for categorical axes. """ @@ -817,11 +817,13 @@ def _get_factors(self, element): sdim = element.get_dimension(1) xdim, ydim = element.dimensions()[:2] - xvals = element.dimension_values(0, False) + + xvals = np.asarray(xdim.values or element.dimension_values(0, False)) xvals = [x if xvals.dtype.kind in 'SU' else xdim.pprint_value(x) for x in xvals] + if gdim and not sdim: - gvals = element.dimension_values(gdim, False) + gvals = np.asarray(gdim.values or element.dimension_values(gdim, False)) xvals = sorted([(x, g) for x in xvals for g in gvals]) is_str = gvals.dtype.kind in 'SU' xvals = [(x, g if is_str else gdim.pprint_value(g)) for (x, g) in xvals] diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 5e3aba4689..e73f0e0a0f 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -744,7 +744,7 @@ def _update_ranges(self, element, ranges): xfactors, yfactors = None, None if any(isinstance(ax_range, FactorRange) for ax_range in [x_range, y_range]): - xfactors, yfactors = self._get_factors(element) + xfactors, yfactors = self._get_factors(element, ranges) framewise = self.framewise streaming = (self.streaming and any(stream._triggering for stream in self.streaming)) xupdate = ((not (self.model_changed(x_range) or self.model_changed(plot)) @@ -912,15 +912,15 @@ def get_aspect(self, xspan, yspan): return 1 - def _get_factors(self, element): + def _get_factors(self, element, ranges): """ Get factors for categorical axes. """ xdim, ydim = element.dimensions()[:2] - xvals, yvals = [element.dimension_values(i, False) - for i in range(2)] + xvals = np.asarray(xdim.values or element.dimension_values(0, False)) + yvals = np.asarray(ydim.values or element.dimension_values(1, False)) coords = tuple([v if vals.dtype.kind in 'SU' else dim.pprint_value(v) for v in vals] - for dim, vals in [(xdim, xvals), (ydim, yvals)]) + for dim, vals in [(xdim, xvals), (ydim, yvals)]) if self.invert_axes: coords = coords[::-1] return coords @@ -2019,12 +2019,12 @@ def _merge_tools(self, subplot): self.handles['hover'] = tool - def _get_factors(self, overlay): + def _get_factors(self, overlay, ranges): xfactors, yfactors = [], [] for k, sp in self.subplots.items(): el = overlay.data.get(k) if el is not None: - xfs, yfs = sp._get_factors(el) + xfs, yfs = sp._get_factors(el, ranges) xfactors.append(xfs) yfactors.append(yfs) if xfactors: diff --git a/holoviews/plotting/bokeh/heatmap.py b/holoviews/plotting/bokeh/heatmap.py index e318991483..c759d86627 100644 --- a/holoviews/plotting/bokeh/heatmap.py +++ b/holoviews/plotting/bokeh/heatmap.py @@ -63,8 +63,8 @@ def is_radial(cls, heatmap): return ((any(o in opts for o in ('start_angle', 'radius_inner', 'radius_outer')) and not (opts.get('radial') == False)) or opts.get('radial', False)) - def _get_factors(self, element): - return super(HeatMapPlot, self)._get_factors(element.gridded) + def _get_factors(self, element, ranges): + return super(HeatMapPlot, self)._get_factors(element.gridded, ranges) def get_data(self, element, ranges, style): x, y, z = [dimension_sanitizer(d) for d in element.dimensions(label=True)[:3]] diff --git a/holoviews/plotting/bokeh/stats.py b/holoviews/plotting/bokeh/stats.py index 09d07197dc..119e4e2724 100644 --- a/holoviews/plotting/bokeh/stats.py +++ b/holoviews/plotting/bokeh/stats.py @@ -109,7 +109,7 @@ def _apply_transforms(self, element, data, ranges, style, group=None): element = element.clone([(agg,)]) return super(BoxWhiskerPlot, self)._apply_transforms(element, data, ranges, style, group) - def _get_factors(self, element): + def _get_factors(self, element, ranges): """ Get factors for categorical axes. """ diff --git a/holoviews/tests/plotting/bokeh/testelementplot.py b/holoviews/tests/plotting/bokeh/testelementplot.py index a64b180b06..5f0f8f0cf4 100644 --- a/holoviews/tests/plotting/bokeh/testelementplot.py +++ b/holoviews/tests/plotting/bokeh/testelementplot.py @@ -378,6 +378,12 @@ def test_hover_tooltip_update(self): plot.update(('b',)) self.assertEqual(plot.handles['hover'].tooltips, [('x', '@{x}'), ('b', '@{b}')]) + def test_categorical_dimension_values(self): + curve = Curve([('C', 1), ('B', 3)]).redim.values(x=['A', 'B', 'C']) + plot = bokeh_renderer.get_plot(curve) + x_range = plot.handles['x_range'] + self.assertEqual(x_range.factors, ['A', 'B', 'C']) + ################################################################# # Aspect tests ################################################################# @@ -794,3 +800,17 @@ def test_active_tools_draw_stream(self): toolbar = plot.state.toolbar self.assertIsInstance(toolbar.active_tap, tools.PointDrawTool) self.assertIsInstance(toolbar.active_drag, tools.PointDrawTool) + + def test_categorical_overlay_dimension_values(self): + curve = Curve([('C', 1), ('B', 3)]).redim.values(x=['A', 'B', 'C']) + scatter = Scatter([('A', 2)]) + plot = bokeh_renderer.get_plot(curve*scatter) + x_range = plot.handles['x_range'] + self.assertEqual(x_range.factors, ['A', 'B', 'C']) + + def test_categorical_overlay_dimension_values_skip_factor(self): + curve = Curve([('C', 1), ('B', 3)]) + scatter = Scatter([('A', 2)]) + plot = bokeh_renderer.get_plot((curve*scatter).redim.values(x=['A', 'C'])) + x_range = plot.handles['x_range'] + self.assertEqual(x_range.factors, ['A', 'C'])