Skip to content

Commit

Permalink
Allow defining categorical axis ordering via Dimension.values (#3675)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Apr 30, 2019
1 parent 8cbbfc7 commit 3ec07b4
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 13 deletions.
8 changes: 5 additions & 3 deletions holoviews/plotting/bokeh/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand All @@ -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]
Expand Down
14 changes: 7 additions & 7 deletions holoviews/plotting/bokeh/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions holoviews/plotting/bokeh/heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/bokeh/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand Down
20 changes: 20 additions & 0 deletions holoviews/tests/plotting/bokeh/testelementplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
#################################################################
Expand Down Expand Up @@ -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'])

0 comments on commit 3ec07b4

Please sign in to comment.