diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index ded4595fbfb6..44fb904620c0 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -506,7 +506,19 @@ def legend(self, *args, **kwargs): else: raise TypeError('Invalid arguments to legend.') - self.legend_ = mlegend.Legend(self, handles, labels, **kwargs) + # If uniform_size is specified, verify that there's no conflicting + # parameters. + if 'uniform_size' in kwargs: + if 'markerscale' in kwargs or 'handler_map' in kwargs: + raise TypeError("Cannot specify 'markerscale' or " + + "'handler_map' to legend when " + + "'uniform_size' is specified.") + uniform_size = kwargs.pop('uniform_size') + self.legend_ = mlegend.UniformLegend(self, handles, labels, + uniform_size, **kwargs) + else: + self.legend_ = mlegend.Legend(self, handles, labels, **kwargs) + self.legend_._remove_method = lambda h: setattr(self, 'legend_', None) return self.legend_ diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 78ce8d98e18d..825643e36e4c 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -40,6 +40,7 @@ from matplotlib.axes import Axes, SubplotBase, subplot_class_factory from matplotlib.blocking_input import BlockingMouseInput, BlockingKeyMouseInput from matplotlib.legend import Legend +from matplotlib.legend import UniformLegend from matplotlib.patches import Rectangle from matplotlib.projections import (get_projection_names, process_projection_requirements) @@ -1222,7 +1223,21 @@ def legend(self, handles, labels, *args, **kwargs): .. plot:: mpl_examples/pylab_examples/figlegend_demo.py """ - l = Legend(self, handles, labels, *args, **kwargs) + + # If uniform_size is specified, verify that there's no conflicting + # parameters. + l = None + if 'uniform_size' in kwargs: + if 'markerscale' in kwargs or 'handler_map' in kwargs: + raise TypeError("Cannot specify 'markerscale' or " + + "'handler_map' to legend when " + + "'uniform_size' is specified.") + uniform_size = kwargs.pop('uniform_size') + l = UniformLegend(self, handles, labels, uniform_size, *args, + **kwargs) + else: + l = Legend(self, handles, labels, *args, **kwargs) + self.legends.append(l) l._remove_method = lambda h: self.legends.remove(h) return l diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py old mode 100644 new mode 100755 index a312bbd113a3..2140d937f408 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -993,3 +993,93 @@ def draggable(self, state=None, use_blit=False, update="loc"): self._draggable = None return self._draggable + + +class UniformLegend(Legend): + def __str__(self): + return "uniformLegend" + + def __init__(self, parent, handles, labels, uniform_size, + loc=None, + numpoints=None, # the number of points in the legend line + markerfirst=True, # controls ordering (left-to-right) of + # legend marker and label + scatterpoints=None, # number of scatter points + scatteryoffsets=None, + prop=None, # properties for the legend texts + fontsize=None, # keyword to set font size directly + + # spacing & pad defined as a fraction of the font-size + borderpad=None, # the whitespace inside the legend border + labelspacing=None, # the vertical space between the legend + # entries + handlelength=None, # the length of the legend handles + handleheight=None, # the height of the legend handles + handletextpad=None, # the pad between the legend handle + # and text + borderaxespad=None, # the pad between the axes and legend + # border + columnspacing=None, # spacing between columns + + ncol=1, # number of columns + mode=None, # mode for horizontal distribution of columns. + # None, "expand" + + fancybox=None, # True use a fancy box, false use a rounded + # box, none use rc + shadow=None, + title=None, # set a title for the legend + + framealpha=None, # set frame alpha + + bbox_to_anchor=None, # bbox that the legend will be anchored. + bbox_transform=None, # transform for the bbox + frameon=None + ): + uniformHandlerMap = { + StemContainer: + legend_handler.HandlerUniformStem(uniform_size=uniform_size), + ErrorbarContainer: + legend_handler.HandlerUniformErrorBar(uniform_size=uniform_size), + Line2D: + legend_handler.HandlerUniformLine2D(uniform_size=uniform_size), + PathCollection: + legend_handler.HandlerPathCollection(sizes=[uniform_size]*3), + RegularPolyCollection: + legend_handler.HandlerRegularPolyCollection( + sizes=[uniform_size]*3), + CircleCollection: + legend_handler.HandlerCircleCollection(sizes=[uniform_size]*3), + } + + # Consult Legend.__init__ for purpose of each parameter. + Legend.__init__(self, parent, handles, labels, + loc=loc, + numpoints=numpoints, + # markerscale does nothing when using uniform sizing. + markerscale=None, + markerfirst=markerfirst, + scatterpoints=scatterpoints, + scatteryoffsets=scatteryoffsets, + prop=prop, + fontsize=fontsize, + borderpad=borderpad, + labelspacing=labelspacing, + handlelength=handlelength, + handleheight=handleheight, + handletextpad=handletextpad, + borderaxespad=borderaxespad, + columnspacing=columnspacing, + ncol=1, + mode=mode, + fancybox=fancybox, + shadow=shadow, + title=title, + framealpha=framealpha, + bbox_to_anchor=bbox_to_anchor, + bbox_transform=bbox_transform, + frameon=frameon, + # Override with custom handler map that forces uniform + # sizing. + handler_map=uniformHandlerMap, + ) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py old mode 100644 new mode 100755 index 69af7aca28c8..f36de5c808f5 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -617,3 +617,60 @@ def create_artists(self, legend, orig_handle, self.update_prop(p, orig_handle, legend) p.set_transform(trans) return [p] + + +class HandlerUniformLine2D(HandlerLine2D): + """ + Handler for Uniform sized Line2D instances + """ + + def __init__(self, uniform_size, **kw): + self._uniform_size = uniform_size + HandlerLine2D.__init__(self, **kw) + + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, + trans): + artists = HandlerLine2D.create_artists(self, legend, orig_handle, + xdescent, ydescent, + width, height, + fontsize, trans) + artists[-1].set_markersize(self._uniform_size) + return artists + + +class HandlerUniformErrorBar(HandlerErrorbar): + """ + Handler for Uniform sized Error instances + """ + + def __init__(self, uniform_size, **kw): + self._uniform_size = uniform_size + HandlerErrorbar.__init__(self, **kw) + + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, + trans): + artists = HandlerErrorbar.create_artists(self, legend, orig_handle, + xdescent, ydescent, + width, height, + fontsize, trans) + artists[-1].set_markersize(self._uniform_size) + return artists + + +class HandlerUniformStem(HandlerStem): + def __init__(self, uniform_size, **kw): + + HandlerStem.__init__(self, **kw) + self._uniform_size = uniform_size + + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, + trans): + artists = HandlerStem.create_artists(self, legend, orig_handle, + xdescent, ydescent, + width, height, + fontsize, trans) + artists[0].set_markersize(self._uniform_size) + return artists