From 766efaaa017603e660ae14522d3b6898facda3ad Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Sat, 18 May 2013 23:58:47 +0900 Subject: [PATCH 1/9] fix legend_handler.HandlerNpoints.get_xdata of wrong xdescent interpretation. --- lib/matplotlib/legend_handler.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 82fbea1f88c..a382a70886c 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -150,13 +150,14 @@ def get_xdata(self, legend, xdescent, ydescent, width, height, fontsize): if numpoints > 1: # we put some pad here to compensate the size of the # marker - xdata = np.linspace(-xdescent + self._marker_pad * fontsize, - width - self._marker_pad * fontsize, + pad = self._marker_pad * fontsize + xdata = np.linspace(-xdescent + pad, + -xdescent + width - pad, numpoints) xdata_marker = xdata elif numpoints == 1: - xdata = np.linspace(-xdescent, width, 2) - xdata_marker = [0.5 * width - 0.5 * xdescent] + xdata = np.linspace(-xdescent, -xdescent+width, 2) + xdata_marker = [-xdescent + 0.5 * width] return xdata, xdata_marker From ffe8ed4c39bf8036ac957bcaa2f9d0429cfcedd9 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Sun, 19 May 2013 00:00:15 +0900 Subject: [PATCH 2/9] modify legend_hadler.HandlerTuple to display multiple handles side-by-side. --- examples/pylab_examples/legend_demo6.py | 22 ++++++++++++++++++++++ lib/matplotlib/legend_handler.py | 25 +++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 examples/pylab_examples/legend_demo6.py diff --git a/examples/pylab_examples/legend_demo6.py b/examples/pylab_examples/legend_demo6.py new file mode 100644 index 00000000000..8892837b43e --- /dev/null +++ b/examples/pylab_examples/legend_demo6.py @@ -0,0 +1,22 @@ +import matplotlib.pyplot as plt +from matplotlib.legend_handler import HandlerTuple + +fig, (ax1, ax2) = plt.subplots(2, 1) +p1 = ax1.scatter([1],[5], c='r', marker='s', s=100) +p2 = ax1.scatter([3],[2], c='b', marker='o', s=100) + +l = ax1.legend([(p1, p2)],['points'], scatterpoints=1, + handler_map={tuple: HandlerTuple(ndivide=0)}) + +ind = [1,2,3] +pos1 = [1, 3, 2] +neg1 = [2, 1, 4] +width=[0.5, 0.5, 0.5] + +rpos1 = ax2.bar(ind, pos1, width=0.5, color='k', label='+1') +rneg1 = ax2.bar(ind, neg1, width=0.5, color='w', hatch='///', label='-1') + +l = ax2.legend([(rpos1, rneg1)],['Test'], + handler_map={(rpos1, rneg1): HandlerTuple(ndivide=0, pad=0.)}) + +plt.show() diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index a382a70886c..09419985c96 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -568,7 +568,9 @@ class HandlerTuple(HandlerBase): """ Handler for Tuple """ - def __init__(self, **kwargs): + def __init__(self, ndivide=1, pad=None, **kwargs): + self._ndivide = ndivide + self._pad = pad HandlerBase.__init__(self, **kwargs) def create_artists(self, legend, orig_handle, @@ -576,11 +578,30 @@ def create_artists(self, legend, orig_handle, trans): handler_map = legend.get_legend_handler_map() + + if self._ndivide == 0: + ndivide = len(orig_handle) + else: + ndivide = self._ndivide + + if self._pad is None: + pad = legend.borderpad * fontsize + else: + pad = self._pad * fontsize + + if ndivide > 1: + width = (width - pad*(ndivide - 1)) / ndivide + + xds = [xdescent - (width + pad) * i for i in range(ndivide)] + from itertools import cycle + xd_next = cycle(xds).next + a_list = [] for handle1 in orig_handle: handler = legend.get_legend_handler(handler_map, handle1) _a_list = handler.create_artists(legend, handle1, - xdescent, ydescent, width, height, + xd_next(), ydescent, + width, height, fontsize, trans) a_list.extend(_a_list) From 59f3cc71ae675478cc6b228d2fd8d8dc9182ffc3 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 19 Apr 2015 13:49:25 -0400 Subject: [PATCH 3/9] MNT : move import to top level --- lib/matplotlib/legend_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 09419985c96..4d13681e1d8 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -29,6 +29,7 @@ def legend_artist(self, legend, orig_handle, fontsize, handlebox): from matplotlib.externals import six from matplotlib.externals.six.moves import zip +from itertools import cycle import numpy as np @@ -593,7 +594,6 @@ def create_artists(self, legend, orig_handle, width = (width - pad*(ndivide - 1)) / ndivide xds = [xdescent - (width + pad) * i for i in range(ndivide)] - from itertools import cycle xd_next = cycle(xds).next a_list = [] From 07a3f805448f13c39a93ae464cf3db64968599fd Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 19 Apr 2015 14:05:01 -0400 Subject: [PATCH 4/9] DOC : added docstring --- lib/matplotlib/legend_handler.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 4d13681e1d8..eef9343b1ba 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -567,9 +567,27 @@ def create_artists(self, legend, orig_handle, class HandlerTuple(HandlerBase): """ - Handler for Tuple + Handler for Tuple. + + Additional kwargs are passed through to `HandlerBase`. + + Parameters + ---------- + + ndivide : int, optional + The number of sections to divide the legend area into. If 0, + use the length of the input tuple. + + + pad : float, optional + If None, fall back to `legend.borderpad` as the default. + In units of fraction of font size. + + + """ def __init__(self, ndivide=1, pad=None, **kwargs): + self._ndivide = ndivide self._pad = pad HandlerBase.__init__(self, **kwargs) From 2131d3d5040578dd5d4d4c42115e0ac84a26c3fa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 19 Apr 2015 14:21:47 -0400 Subject: [PATCH 5/9] MNT : python3 compatibility updates --- lib/matplotlib/legend_handler.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index eef9343b1ba..eaaf1a64dac 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -501,6 +501,7 @@ def create_artists(self, legend, orig_handle, return artists + class HandlerStem(HandlerNpointsYoffsets): """ Handler for Errorbars @@ -612,13 +613,14 @@ def create_artists(self, legend, orig_handle, width = (width - pad*(ndivide - 1)) / ndivide xds = [xdescent - (width + pad) * i for i in range(ndivide)] - xd_next = cycle(xds).next + xds_cycle = cycle(xds) a_list = [] for handle1 in orig_handle: handler = legend.get_legend_handler(handler_map, handle1) _a_list = handler.create_artists(legend, handle1, - xd_next(), ydescent, + six.next(xds_cycle), + ydescent, width, height, fontsize, trans) From 609571e43a5f241f264334392cc6096bc99a14ef Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 19 Apr 2015 16:20:44 -0400 Subject: [PATCH 6/9] STY : pep8 on legend example --- examples/pylab_examples/legend_demo6.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/pylab_examples/legend_demo6.py b/examples/pylab_examples/legend_demo6.py index 8892837b43e..03fbee8235d 100644 --- a/examples/pylab_examples/legend_demo6.py +++ b/examples/pylab_examples/legend_demo6.py @@ -2,21 +2,21 @@ from matplotlib.legend_handler import HandlerTuple fig, (ax1, ax2) = plt.subplots(2, 1) -p1 = ax1.scatter([1],[5], c='r', marker='s', s=100) -p2 = ax1.scatter([3],[2], c='b', marker='o', s=100) +p1 = ax1.scatter([1], [5], c='r', marker='s', s=100) +p2 = ax1.scatter([3], [2], c='b', marker='o', s=100) -l = ax1.legend([(p1, p2)],['points'], scatterpoints=1, +l = ax1.legend([(p1, p2)], ['points'], scatterpoints=1, handler_map={tuple: HandlerTuple(ndivide=0)}) -ind = [1,2,3] +ind = [1, 2, 3] pos1 = [1, 3, 2] neg1 = [2, 1, 4] -width=[0.5, 0.5, 0.5] +width = [0.5, 0.5, 0.5] rpos1 = ax2.bar(ind, pos1, width=0.5, color='k', label='+1') rneg1 = ax2.bar(ind, neg1, width=0.5, color='w', hatch='///', label='-1') -l = ax2.legend([(rpos1, rneg1)],['Test'], +l = ax2.legend([(rpos1, rneg1)], ['Test'], handler_map={(rpos1, rneg1): HandlerTuple(ndivide=0, pad=0.)}) plt.show() From c721a1567ea8be23bad7ebdadc7a4197d4881a8b Mon Sep 17 00:00:00 2001 From: Julian Mehne Date: Fri, 4 Dec 2015 00:08:54 +0100 Subject: [PATCH 7/9] Various documentation changes - Add what's new entry - Update legend guide - Document HandlerTuple's default values --- doc/users/legend_guide.rst | 15 +++++++++++++++ doc/users/whats_new/multiple_legend_keys.rst | 10 ++++++++++ lib/matplotlib/legend_handler.py | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 doc/users/whats_new/multiple_legend_keys.rst diff --git a/doc/users/legend_guide.rst b/doc/users/legend_guide.rst index 8287a5ca071..613090a6d9b 100644 --- a/doc/users/legend_guide.rst +++ b/doc/users/legend_guide.rst @@ -198,6 +198,21 @@ following example demonstrates combining two legend keys on top of one another: plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"]) +The :class:`~matplotlib.legend_handler.HandlerTuple` class can also be used to +assign several legend keys to the same entry: + +.. plot:: + :include-source: + + import matplotlib.pyplot as plt + from matplotlib.legend_handler import HandlerLine2D, HandlerTuple + + p1, = plt.plot([1, 2.5, 3], 'r-d') + p2, = plt.plot([3, 2, 1], 'k-o') + + l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1, + handler_map={tuple: HandlerTuple(ndivide=0)}) + Implementing a custom legend handler ------------------------------------ diff --git a/doc/users/whats_new/multiple_legend_keys.rst b/doc/users/whats_new/multiple_legend_keys.rst new file mode 100644 index 00000000000..9be34e4b36a --- /dev/null +++ b/doc/users/whats_new/multiple_legend_keys.rst @@ -0,0 +1,10 @@ +Multiple legend keys for legend entries +--------------------------------------- + +A legend entry can now contain more than one legend key. The extended +``HandlerTuple`` class now accepts two parameters: ``ndivide`` divides the +legend area in the specified number of sections; ``pad`` changes the padding +between the legend keys. + +.. plot:: mpl_examples/pylab_examples/legend_demo6.py + diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index eaaf1a64dac..c47c287c1eb 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -577,12 +577,12 @@ class HandlerTuple(HandlerBase): ndivide : int, optional The number of sections to divide the legend area into. If 0, - use the length of the input tuple. + use the length of the input tuple. Default is 1. pad : float, optional If None, fall back to `legend.borderpad` as the default. - In units of fraction of font size. + In units of fraction of font size. Default is None. From d255e50e982203f37cc3a5a2b5be92bd0e622bc5 Mon Sep 17 00:00:00 2001 From: Julian Mehne Date: Fri, 4 Dec 2015 00:57:49 +0100 Subject: [PATCH 8/9] Add test, adapt example. --- examples/pylab_examples/legend_demo6.py | 33 ++++++++++++++------- .../test_legend/legend_multiple_keys.png | Bin 0 -> 31611 bytes lib/matplotlib/tests/test_legend.py | 16 ++++++++++ 3 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_legend/legend_multiple_keys.png diff --git a/examples/pylab_examples/legend_demo6.py b/examples/pylab_examples/legend_demo6.py index 03fbee8235d..9ced047ab2f 100644 --- a/examples/pylab_examples/legend_demo6.py +++ b/examples/pylab_examples/legend_demo6.py @@ -1,22 +1,35 @@ +""" +Showcases legend entries with more than one legend key. +""" import matplotlib.pyplot as plt from matplotlib.legend_handler import HandlerTuple fig, (ax1, ax2) = plt.subplots(2, 1) + +# First plot: two legend keys for a single entry p1 = ax1.scatter([1], [5], c='r', marker='s', s=100) p2 = ax1.scatter([3], [2], c='b', marker='o', s=100) +# `plot` returns a list, but we want the handle - thus the comma on the left +p3, = ax1.plot([1, 5], [4, 4], 'm-d') -l = ax1.legend([(p1, p2)], ['points'], scatterpoints=1, - handler_map={tuple: HandlerTuple(ndivide=0)}) +# Assign two of the handles to the same legend entry by putting them in a tuple +# and using a generic handler map (which would be used for any additional +# tuples of handles like (p1, p3)). +l = ax1.legend([(p1, p3), p2], ['two keys', 'one key'], scatterpoints=1, + numpoints=1, handler_map={tuple: HandlerTuple(ndivide=0)}) -ind = [1, 2, 3] -pos1 = [1, 3, 2] -neg1 = [2, 1, 4] -width = [0.5, 0.5, 0.5] +# Second plot: plot two bar charts on top of each other and change the padding +# between the legend keys +x_left = [1, 2, 3] +y_pos = [1, 3, 2] +y_neg = [2, 1, 4] -rpos1 = ax2.bar(ind, pos1, width=0.5, color='k', label='+1') -rneg1 = ax2.bar(ind, neg1, width=0.5, color='w', hatch='///', label='-1') +rneg = ax2.bar(x_left, y_neg, width=0.5, color='w', hatch='///', label='-1') +rpos = ax2.bar(x_left, y_pos, width=0.5, color='k', label='+1') -l = ax2.legend([(rpos1, rneg1)], ['Test'], - handler_map={(rpos1, rneg1): HandlerTuple(ndivide=0, pad=0.)}) +# Treat each legend entry differently by using specific `HandlerTuple`s +l = ax2.legend([(rpos, rneg), (rneg, rpos)], ['pad!=0', 'pad=0'], + handler_map={(rpos, rneg): HandlerTuple(ndivide=0), + (rneg, rpos): HandlerTuple(ndivide=0, pad=0.)}) plt.show() diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_multiple_keys.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_multiple_keys.png new file mode 100644 index 0000000000000000000000000000000000000000..9e432c072067c1dada4276a60682dbc142277d10 GIT binary patch literal 31611 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 Date: Sat, 19 Mar 2016 16:40:29 +0100 Subject: [PATCH 9/9] Use None as sentinel value for ndivide. --- doc/users/legend_guide.rst | 2 +- examples/pylab_examples/legend_demo6.py | 6 +++--- lib/matplotlib/legend_handler.py | 4 ++-- lib/matplotlib/tests/test_legend.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/users/legend_guide.rst b/doc/users/legend_guide.rst index 613090a6d9b..a44bd20a536 100644 --- a/doc/users/legend_guide.rst +++ b/doc/users/legend_guide.rst @@ -211,7 +211,7 @@ assign several legend keys to the same entry: p2, = plt.plot([3, 2, 1], 'k-o') l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1, - handler_map={tuple: HandlerTuple(ndivide=0)}) + handler_map={tuple: HandlerTuple(ndivide=None)}) Implementing a custom legend handler diff --git a/examples/pylab_examples/legend_demo6.py b/examples/pylab_examples/legend_demo6.py index 9ced047ab2f..9fef8a5d17e 100644 --- a/examples/pylab_examples/legend_demo6.py +++ b/examples/pylab_examples/legend_demo6.py @@ -16,7 +16,7 @@ # and using a generic handler map (which would be used for any additional # tuples of handles like (p1, p3)). l = ax1.legend([(p1, p3), p2], ['two keys', 'one key'], scatterpoints=1, - numpoints=1, handler_map={tuple: HandlerTuple(ndivide=0)}) + numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)}) # Second plot: plot two bar charts on top of each other and change the padding # between the legend keys @@ -29,7 +29,7 @@ # Treat each legend entry differently by using specific `HandlerTuple`s l = ax2.legend([(rpos, rneg), (rneg, rpos)], ['pad!=0', 'pad=0'], - handler_map={(rpos, rneg): HandlerTuple(ndivide=0), - (rneg, rpos): HandlerTuple(ndivide=0, pad=0.)}) + handler_map={(rpos, rneg): HandlerTuple(ndivide=None), + (rneg, rpos): HandlerTuple(ndivide=None, pad=0.)}) plt.show() diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index c47c287c1eb..d3574bf4819 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -576,7 +576,7 @@ class HandlerTuple(HandlerBase): ---------- ndivide : int, optional - The number of sections to divide the legend area into. If 0, + The number of sections to divide the legend area into. If None, use the length of the input tuple. Default is 1. @@ -599,7 +599,7 @@ def create_artists(self, legend, orig_handle, handler_map = legend.get_legend_handler_map() - if self._ndivide == 0: + if self._ndivide is None: ndivide = len(orig_handle) else: ndivide = self._ndivide diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 21885738422..8b44a433ba5 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -89,8 +89,8 @@ def test_multiple_keys(): p3, = ax.plot([3, 4, 5], '-d') ax.legend([(p1, p2), (p2, p1), p3], ['two keys', 'pad=0', 'one key'], numpoints=1, - handler_map={(p1, p2): HandlerTuple(ndivide=0), - (p2, p1): HandlerTuple(ndivide=0, pad=0)}) + handler_map={(p1, p2): HandlerTuple(ndivide=None), + (p2, p1): HandlerTuple(ndivide=None, pad=0)}) @image_comparison(baseline_images=['rgba_alpha'],