Skip to content

Reverse legend #24759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Dec 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/users/next_whats_new/reverse_legend.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Reversed order of legend entries
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Reversed order of legend entries
Reverse order of legend entries

--------------------------------
The order of legend entries can now be reversed by passing ``reverse=True`` to
`~.Axes.legend`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's overkill to have a teeny example here, something like

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(4,2))

for ax in [ax1, ax2]:
    ax.axhline(.25, label="25")
    ax.axhline(.75, label="75")

ax1.legend()
ax2.legend(reverse=True)

11 changes: 11 additions & 0 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Comment on lines +212 to +215
Copy link
Member

@story645 story645 Dec 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot, but based on @tacaswell comment this should also get a version added at the end (skip a line) so like:

    ..versionadded:: 3.7

https://matplotlib.org/devdocs/devel/coding_guide.html#new-features-and-api-changes

..versionadded:: 3.7

frameon : bool, default: :rc:`legend.frameon`
Whether the legend should be drawn on a patch (frame).

Expand Down Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a docstring as well. This should go in line 212 (we do a bit of docstring processing that is why the docstring text is in a separate place).

scatterpoints=None, # number of scatter points
scatteryoffsets=None,
prop=None, # properties for the legend texts
Expand Down Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
handles = list(handles)

if len(handles) < 2:
ncols = 1
Expand Down
32 changes: 32 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down