Skip to content

Commit

Permalink
Improved legends and tick labels on Bars
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Jun 9, 2015
1 parent 3a3d8de commit 5a12882
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 32 deletions.
36 changes: 20 additions & 16 deletions holoviews/plotting/chart.py
Expand Up @@ -11,7 +11,7 @@
from ..core import OrderedDict, NdMapping, ViewableElement, CompositeOverlay, HoloMap
from ..core.util import match_spec
from ..element import Scatter, Curve, Histogram, Bars, Points, Raster, VectorField, ErrorBars, Polygons
from .element import ElementPlot
from .element import ElementPlot, LegendPlot
from .plot import MPLPlot


Expand Down Expand Up @@ -735,7 +735,7 @@ def update_handles(self, axis, view, key, ranges=None):
quiver.set_clim(ranges[magnitude_dim])


class BarPlot(ElementPlot):
class BarPlot(LegendPlot):

group_index = param.Integer(default=0, doc="""
Index of the dimension in the supplied Bars
Expand Down Expand Up @@ -764,6 +764,13 @@ class BarPlot(ElementPlot):
style_opts = ['alpha', 'color', 'align', 'visible', 'edgecolor',
'log', 'facecolor', 'capsize', 'error_kw', 'hatch']

legend_specs = dict(LegendPlot.legend_specs, **{
'top': dict(bbox_to_anchor=(0., 1.02, 1., .102),
ncol=3, loc=3, mode="expand", borderaxespad=0.),
'bottom': dict(ncol=3, mode="expand", loc=2,
bbox_to_anchor=(0., -0.4, 1., .102),
borderaxespad=0.1)})

_dimensions = OrderedDict([('group', 0),
('category',1),
('stack',2)])
Expand Down Expand Up @@ -833,22 +840,17 @@ def initialize_plot(self, ranges=None):
ranges = match_spec(element, ranges)
dims = element.dimensions('key', label=True)

self.handles['bars'], xticks = self._create_bars(axis, element)
self.handles['bars'], xticks, xlabel = self._create_bars(axis, element)
self.handles['legend_handle'] = self.handles['bars']
self._set_ticks(axis, dims, xticks)
return self._finalize_axis(key, ranges=ranges, ylabel=str(vdim))
return self._finalize_axis(key, ranges=ranges, xticks=xticks, xlabel=xlabel, ylabel=str(vdim))


def _set_ticks(self, axis, dims, xticks):
def _finalize_ticks(self, axis, xticks, yticks, zticks):
"""
Apply ticks with appropriate offsets.
"""
ndims = len(dims)
idx = self.group_index if self.group_index < ndims else self.category_index
ticks, labels, yalignments = zip(*sorted(xticks, key=lambda x: x[0]))
axis.set_xlabel(dims[idx], labelpad=-0.15 if idx < ndims else -0.05)
axis.set_xticks(ticks)
axis.set_xticklabels(labels)
super(BarPlot, self)._finalize_ticks(axis, [ticks, labels], yticks, zticks)
for t, y in zip(axis.get_xticklabels(), yalignments):
t.set_y(y)

Expand All @@ -864,6 +866,7 @@ def _create_bars(self, axis, element):
style_opts, color_groups, sopts = self._compute_styles(element, style_groups)
dims = element.dimensions('key', label=True)
ndims = len(dims)
xlabel = ' / '.join([str(d) for d in [cdim, gdim] if d is not None])

# Compute widths
width = (1-(2.*self.padding)) / len(values['category'])
Expand All @@ -886,8 +889,7 @@ def _create_bars(self, axis, element):
style_key[idx] = grp_name
val_key[gi] = grp_name
if ci < ndims:
yalign = -0.125
xticks.append((gidx+0.5, dims[ci], -0.05))
yalign = -0.04
else:
yalign = 0
xticks.append((gidx+0.5, grp_name, yalign))
Expand Down Expand Up @@ -921,9 +923,11 @@ def _create_bars(self, axis, element):
labels.append(label)
title = [str(element.kdims[indices[cg]])
for cg in self.color_by if indices[cg] < ndims]
if any(len(l) for l in labels):
axis.legend(title=', '.join(title))
return bars, xticks
if self.show_legend and any(len(l) for l in labels):
leg_spec = self.legend_specs[self.legend_position]
if self.legend_cols: leg_spec['ncol'] = self.legend_cols
axis.legend(title=', '.join(title), **leg_spec)
return bars, xticks, xlabel


def update_handles(self, axis, element, key, ranges=None):
Expand Down
41 changes: 25 additions & 16 deletions holoviews/plotting/element.py
Expand Up @@ -495,38 +495,46 @@ def update_handles(self, axis, view, key, ranges=None):
raise NotImplementedError


class OverlayPlot(ElementPlot):
"""
OverlayPlot supports compositors processing of Overlays across maps.
"""

style_grouping = param.Integer(default=2,
doc="""The length of the type.group.label
spec that will be used to group Elements into style groups, i.e.
a style_grouping value of 1 will group just by type, a value of 2
will group by type and group and a value of 3 will group by the
full specification.""")
class LegendPlot(ElementPlot):

show_legend = param.Boolean(default=True, doc="""
Whether to show legend for the plot.""")

legend_cols = param.Integer(default=None, doc="""
Number of legend columns in the legend.""")

legend_position = param.ObjectSelector(objects=['inner', 'right',
'bottom', 'top',
'left'],
'left', 'best'],
default='inner', doc="""
Allows selecting between a number of predefined legend position
options. The predefined options may be customized in the
legend_specs class attribute.""")

legend_specs = {'inner': {},
'left': dict(bbox_to_anchor=(-.15, 1)),
'right': dict(bbox_to_anchor=(1.25, 1)),
'best': {},
'left': dict(bbox_to_anchor=(-.15, 1), loc=1),
'right': dict(bbox_to_anchor=(1.05, 1), loc=2),
'top': dict(bbox_to_anchor=(0., 1.02, 1., .102),
ncol=3, mode="expand", borderaxespad=0.),
'bottom': dict(ncol=3, mode="expand",
ncol=3, loc=3, mode="expand", borderaxespad=0.),
'bottom': dict(ncol=3, mode="expand", loc=2,
bbox_to_anchor=(0., -0.25, 1., .102),
borderaxespad=0.1)}



class OverlayPlot(LegendPlot):
"""
OverlayPlot supports compositors processing of Overlays across maps.
"""

style_grouping = param.Integer(default=2,
doc="""The length of the type.group.label
spec that will be used to group Elements into style groups, i.e.
a style_grouping value of 1 will group just by type, a value of 2
will group by type and group and a value of 3 will group by the
full specification.""")

def __init__(self, overlay, ranges=None, **params):
super(OverlayPlot, self).__init__(overlay, ranges=ranges, **params)

Expand Down Expand Up @@ -642,6 +650,7 @@ def _adjust_legend(self, axis):
legend.set_visible(False)
else:
leg_spec = self.legend_specs[self.legend_position]
if self.legend_cols: leg_spec['ncol'] = self.legend_cols
leg = axis.legend(data.keys(), data.values(),
title=title, scatterpoints=1,
**leg_spec)
Expand Down

0 comments on commit 5a12882

Please sign in to comment.