From a94ecc52fbefe62064af652f9137bea258cfe12f Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Sat, 17 Dec 2022 14:18:17 +0100 Subject: [PATCH 01/15] Legend: Include reverse parameter and if cond --- lib/matplotlib/legend.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 82f92167c55c..1d69e025291b 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -312,6 +312,7 @@ def __init__( numpoints=None, # number of points in the legend line markerscale=None, # relative size of legend markers vs. original markerfirst=True, # left/right ordering of legend marker and label + reverse=False # reverse ordering of legend marker and label scatterpoints=None, # number of scatter points scatteryoffsets=None, prop=None, # properties for the legend texts @@ -525,7 +526,7 @@ def val_or_rc(val, rc_name): self._alignment = alignment # init with null renderer - self._init_legend_box(handles, labels, markerfirst) + self._init_legend_box(handles, labels, markerfirst, reverse) tmp = self._loc_used_default self._set_loc(loc) @@ -750,7 +751,7 @@ def get_legend_handler(legend_handler_map, orig_handle): pass return None - def _init_legend_box(self, handles, labels, markerfirst=True): + def _init_legend_box(self, handles, labels, markerfirst=True, reverse=False): """ Initialize the legend_box. The legend_box is an instance of the OffsetBox, which is packed with legend handles and @@ -783,6 +784,9 @@ def _init_legend_box(self, handles, labels, markerfirst=True): # default transform (e.g., Collections), you need to # manually set their transform to the self.get_transform(). legend_handler_map = self.get_legend_handler_map() + if reverse == True: + handles.reverse() + labels.reverse() for orig_handle, label in zip(handles, labels): handler = self.get_legend_handler(legend_handler_map, orig_handle) From cda93348a537960a89f40a1f341fab369b3cc2b6 Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Sat, 17 Dec 2022 14:36:29 +0100 Subject: [PATCH 02/15] Legend: Bugfix comma --- lib/matplotlib/legend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 1d69e025291b..a42a4db16326 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -312,7 +312,7 @@ def __init__( numpoints=None, # number of points in the legend line markerscale=None, # relative size of legend markers vs. original markerfirst=True, # left/right ordering of legend marker and label - reverse=False # reverse ordering of legend marker and label + reverse=False, # reverse ordering of legend marker and label scatterpoints=None, # number of scatter points scatteryoffsets=None, prop=None, # properties for the legend texts From cb52fee59e103503440458a782a0b8d1a7085403 Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Sat, 17 Dec 2022 18:06:23 +0100 Subject: [PATCH 03/15] Legend: Code style --- lib/matplotlib/legend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index a42a4db16326..1a1b7fd1ecca 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -312,7 +312,7 @@ def __init__( numpoints=None, # number of points in the legend line markerscale=None, # relative size of legend markers vs. original markerfirst=True, # left/right ordering of legend marker and label - reverse=False, # reverse ordering of legend marker and label + reverse=False, # reverse ordering of legend marker and label scatterpoints=None, # number of scatter points scatteryoffsets=None, prop=None, # properties for the legend texts From 75d984969ffd01509f22ad69ab06e6578c20a142 Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Sat, 17 Dec 2022 18:41:56 +0100 Subject: [PATCH 04/15] Legend: Linting/flake8 --- lib/matplotlib/legend.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 1a1b7fd1ecca..b600683ae279 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -526,7 +526,7 @@ def val_or_rc(val, rc_name): self._alignment = alignment # init with null renderer - self._init_legend_box(handles, labels, markerfirst, reverse) + self._init_legend_box(handles, labels,reverse, markerfirst) tmp = self._loc_used_default self._set_loc(loc) @@ -751,7 +751,7 @@ def get_legend_handler(legend_handler_map, orig_handle): pass return None - def _init_legend_box(self, handles, labels, markerfirst=True, reverse=False): + def _init_legend_box(self, handles, labels, reverse, markerfirst=True): """ Initialize the legend_box. The legend_box is an instance of the OffsetBox, which is packed with legend handles and @@ -784,7 +784,7 @@ def _init_legend_box(self, handles, labels, markerfirst=True, reverse=False): # default transform (e.g., Collections), you need to # manually set their transform to the self.get_transform(). legend_handler_map = self.get_legend_handler_map() - if reverse == True: + if reverse: handles.reverse() labels.reverse() From a67ee8a7c0a0d42cfb7c28cebcb109d5b8907752 Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Sat, 17 Dec 2022 18:45:19 +0100 Subject: [PATCH 05/15] Legend: missed whitespace after ',' --- lib/matplotlib/legend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index b600683ae279..363bade2ad18 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -526,7 +526,7 @@ def val_or_rc(val, rc_name): self._alignment = alignment # init with null renderer - self._init_legend_box(handles, labels,reverse, markerfirst) + self._init_legend_box(handles, labels, reverse, markerfirst) tmp = self._loc_used_default self._set_loc(loc) From 5633cdf76877dc64731b408b06c9d27644664c8c Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Sun, 18 Dec 2022 21:17:22 +0100 Subject: [PATCH 06/15] Legend: remove reverse from init_legend_box --- lib/matplotlib/legend.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 363bade2ad18..da19eb2e40d2 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -438,6 +438,10 @@ def val_or_rc(val, rc_name): _hand.append(handle) labels, handles = _lab, _hand + if reverse: + labels.reverse() + handles.reverse() + handles = list(handles) if len(handles) < 2: ncols = 1 @@ -526,7 +530,7 @@ def val_or_rc(val, rc_name): self._alignment = alignment # init with null renderer - self._init_legend_box(handles, labels, reverse, markerfirst) + self._init_legend_box(handles, labels, markerfirst) tmp = self._loc_used_default self._set_loc(loc) @@ -751,7 +755,7 @@ def get_legend_handler(legend_handler_map, orig_handle): pass return None - def _init_legend_box(self, handles, labels, reverse, markerfirst=True): + def _init_legend_box(self, handles, labels, markerfirst=True): """ Initialize the legend_box. The legend_box is an instance of the OffsetBox, which is packed with legend handles and @@ -784,9 +788,6 @@ def _init_legend_box(self, handles, labels, reverse, markerfirst=True): # default transform (e.g., Collections), you need to # manually set their transform to the self.get_transform(). legend_handler_map = self.get_legend_handler_map() - if reverse: - handles.reverse() - labels.reverse() for orig_handle, label in zip(handles, labels): handler = self.get_legend_handler(legend_handler_map, orig_handle) From 8964e8a9745ef3f236f42989e46fd1370868af63 Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Mon, 19 Dec 2022 14:04:12 +0100 Subject: [PATCH 07/15] Legend: Add test for reverse option --- lib/matplotlib/tests/test_legend.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 0016dc4d2d14..53f6aade3d4a 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -294,6 +294,21 @@ def test_legend_remove(): assert ax.get_legend() is None +def test_reverse_legend(): + fig, ax = plt.subplots() + x = [1, 2, 3] + y = [1, 2, 3], [2, 3, 4], [3, 4, 5] + labels = ["First label", "Second label", "Third label"] + + ax.plot(x, y, label=labels) + leg = ax.legend(reverse=True) + actual_labels = [] + for text in leg.get_texts(): + actual_labels.append(text.get_text()) + excepted_labels = list(reversed(labels)) + assert actual_labels == excepted_labels + + class TestLegendFunction: # Tests the legend function on the Axes and pyplot. def test_legend_no_args(self): From b9f19e106325e6e564d332d993bf8a3f0a91997d Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Mon, 19 Dec 2022 14:18:07 +0100 Subject: [PATCH 08/15] Legend: Add docstring --- lib/matplotlib/legend.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index da19eb2e40d2..6653327d12c2 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -209,6 +209,10 @@ def _update_bbox_to_anchor(self, loc_in_canvas): If *True*, legend marker is placed to the left of the legend label. If *False*, legend marker is placed to the right of the legend label. +reverse : bool, default: False + If *True*, the legend labels are displayed in reverse order as the input. + If *False*, the legend labels are displayed in the same order as the input. + frameon : bool, default: :rc:`legend.frameon` Whether the legend should be drawn on a patch (frame). From 704184b83cace786a5d38299453a7efc34910e0d Mon Sep 17 00:00:00 2001 From: Marvvxi <101656586+Marvvxi@users.noreply.github.com> Date: Tue, 20 Dec 2022 19:18:43 +0100 Subject: [PATCH 09/15] Update lib/matplotlib/tests/test_legend.py Legend: Refactoring actual labels Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/tests/test_legend.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 53f6aade3d4a..449f846c5fd2 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -302,11 +302,8 @@ def test_reverse_legend(): ax.plot(x, y, label=labels) leg = ax.legend(reverse=True) - actual_labels = [] - for text in leg.get_texts(): - actual_labels.append(text.get_text()) - excepted_labels = list(reversed(labels)) - assert actual_labels == excepted_labels + actual_labels = [t.get_gext() for t in leg.get_texts()] + assert actual_labels == list(reversed(labels)) class TestLegendFunction: From fad4e44d75b3776d1e3b76abaa3aa9a4b5dd384f Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Tue, 20 Dec 2022 19:34:47 +0100 Subject: [PATCH 10/15] Legend: include markers test --- lib/matplotlib/tests/test_legend.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 449f846c5fd2..a6096f8bf6f2 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -297,13 +297,18 @@ def test_legend_remove(): def test_reverse_legend(): fig, ax = plt.subplots() x = [1, 2, 3] - y = [1, 2, 3], [2, 3, 4], [3, 4, 5] + y = [[1, 2, 3], [2, 3, 4], [3, 4, 5]] labels = ["First label", "Second label", "Third label"] + markers = ['.', ',', 'o'] - ax.plot(x, y, label=labels) + ax.plot(x, y[0], markers[0], label=labels[0]) + ax.plot(x, y[1], markers[1], label=labels[1]) + ax.plot(x, y[2], markers[2], label=labels[2]) leg = ax.legend(reverse=True) - actual_labels = [t.get_gext() for t in leg.get_texts()] - assert actual_labels == list(reversed(labels)) + actual_labels = [t.get_text() for t in leg.get_texts()] + actual_markers = [h.get_marker() for h in leg.legend_handles] + assert (actual_labels, actual_markers) == (list(reversed(labels)), + (list(reversed(markers)))) class TestLegendFunction: From 2a5ed700218df6a30802785df87fef5af931cc8a Mon Sep 17 00:00:00 2001 From: Marvvxi Date: Tue, 20 Dec 2022 19:45:32 +0100 Subject: [PATCH 11/15] Legend: Remove x,y list increase readability --- lib/matplotlib/tests/test_legend.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index a6096f8bf6f2..d8af6c5e330f 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -296,14 +296,14 @@ def test_legend_remove(): def test_reverse_legend(): fig, ax = plt.subplots() - x = [1, 2, 3] - y = [[1, 2, 3], [2, 3, 4], [3, 4, 5]] + x = 1 + y = 1 labels = ["First label", "Second label", "Third label"] markers = ['.', ',', 'o'] - ax.plot(x, y[0], markers[0], label=labels[0]) - ax.plot(x, y[1], markers[1], label=labels[1]) - ax.plot(x, y[2], markers[2], label=labels[2]) + ax.plot(x, y, markers[0], label=labels[0]) + ax.plot(x, y, markers[1], label=labels[1]) + ax.plot(x, y, markers[2], label=labels[2]) leg = ax.legend(reverse=True) actual_labels = [t.get_text() for t in leg.get_texts()] actual_markers = [h.get_marker() for h in leg.legend_handles] From 74c5d44d3ffc70e4d811457d7baaa89085a06507 Mon Sep 17 00:00:00 2001 From: Marvvxi <101656586+Marvvxi@users.noreply.github.com> Date: Thu, 22 Dec 2022 17:34:57 +0100 Subject: [PATCH 12/15] Update lib/matplotlib/legend.py Legend: docstring correct spelling Co-authored-by: hannah --- lib/matplotlib/legend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 6653327d12c2..9c2c8af67fe8 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -210,7 +210,7 @@ def _update_bbox_to_anchor(self, loc_in_canvas): If *False*, legend marker is placed to the right of the legend label. reverse : bool, default: False - If *True*, the legend labels are displayed in reverse order as the input. + If *True*, the legend labels are displayed in reverse order from the input. If *False*, the legend labels are displayed in the same order as the input. frameon : bool, default: :rc:`legend.frameon` From 372381500dbdb14a028189555baa5d4498136846 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:01:10 +0100 Subject: [PATCH 13/15] Add a what's new entry for legend(..., reverse=True) --- doc/users/next_whats_new/reverse_legend.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc/users/next_whats_new/reverse_legend.rst diff --git a/doc/users/next_whats_new/reverse_legend.rst b/doc/users/next_whats_new/reverse_legend.rst new file mode 100644 index 000000000000..00f2c0dbeac7 --- /dev/null +++ b/doc/users/next_whats_new/reverse_legend.rst @@ -0,0 +1,4 @@ +Reversed order of legend entries +-------------------------------- +The order of legend entries can now be reversed by passing ``reverse=True`` to +`~.Axes.legend`. From fdb52149e3eaadd5045848d8567a90d04a32c533 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:23:18 +0100 Subject: [PATCH 14/15] Add a test for checking the displayed legend is reversed --- lib/matplotlib/tests/test_legend.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index d8af6c5e330f..56794a3428b8 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -294,7 +294,8 @@ def test_legend_remove(): assert ax.get_legend() is None -def test_reverse_legend(): +def test_reverse_legend_handles_and_labels(): + """Check that the legend handles and labels are reversed.""" fig, ax = plt.subplots() x = 1 y = 1 @@ -307,8 +308,22 @@ def test_reverse_legend(): leg = ax.legend(reverse=True) actual_labels = [t.get_text() for t in leg.get_texts()] actual_markers = [h.get_marker() for h in leg.legend_handles] - assert (actual_labels, actual_markers) == (list(reversed(labels)), - (list(reversed(markers)))) + assert actual_labels == list(reversed(labels)) + assert actual_markers == list(reversed(markers)) + + +@check_figures_equal(extensions=["png"]) +def test_reverse_legend_display(fig_test, fig_ref): + """Check that the rendered legend entries are reversed""" + ax = fig_test.subplots() + ax.plot([1], 'ro', label="first") + ax.plot([2], 'bx', label="second") + ax.legend(reverse=True) + + ax = fig_ref.subplots() + ax.plot([2], 'bx', label="second") + ax.plot([1], 'ro', label="first") + ax.legend() class TestLegendFunction: From 15911a6fb38e6e7cad6b8ad5e9321f1686d57212 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:25:59 +0100 Subject: [PATCH 15/15] Added .. versionadded tag to reverse parameter --- lib/matplotlib/legend.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 9c2c8af67fe8..c61be2c5550a 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -213,6 +213,8 @@ def _update_bbox_to_anchor(self, loc_in_canvas): If *True*, the legend labels are displayed in reverse order from the input. If *False*, the legend labels are displayed in the same order as the input. + ..versionadded:: 3.7 + frameon : bool, default: :rc:`legend.frameon` Whether the legend should be drawn on a patch (frame).