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`. diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 82f92167c55c..c61be2c5550a 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -209,6 +209,12 @@ 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 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). @@ -312,6 +318,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 @@ -437,6 +444,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 diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 0016dc4d2d14..56794a3428b8 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -294,6 +294,38 @@ def test_legend_remove(): assert ax.get_legend() is None +def test_reverse_legend_handles_and_labels(): + """Check that the legend handles and labels are reversed.""" + fig, ax = plt.subplots() + x = 1 + y = 1 + labels = ["First label", "Second label", "Third label"] + markers = ['.', ',', 'o'] + + 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] + 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: # Tests the legend function on the Axes and pyplot. def test_legend_no_args(self):