Skip to content

Partly revert #27711 #27780

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 1 commit into from
Feb 14, 2024
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
6 changes: 2 additions & 4 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3885,7 +3885,8 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
boxes are drawn with Patch artists.

labels : sequence, optional
Labels for each dataset (one per dataset).
Labels for each dataset (one per dataset). These are used for
x-tick labels; *not* for legend entries.

manage_ticks : bool, default: True
If True, the tick locations and labels will be adjusted to match
Expand Down Expand Up @@ -4004,9 +4005,6 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
if 'color' in boxprops:
boxprops['edgecolor'] = boxprops.pop('color')

if labels:
boxprops['label'] = labels

# if non-default sym value, put it into the flier dictionary
# the logic for providing the default symbol ('b+') now lives
# in bxp in the initial value of flierkw
Expand Down
41 changes: 13 additions & 28 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,31 +1429,16 @@ def test_legend_text():
assert_allclose(leg_bboxes[1].bounds, leg_bboxes[0].bounds)


def test_boxplot_legend():
# Test that boxplot legends handles are patches
# and labels are generated from boxplot's labels parameter.
fig, axs = plt.subplots()
A = 5*np.random.rand(100, 1)
B = 10*np.random.rand(100, 1) - 5
C = 7*np.random.rand(100, 1) - 5
labels = ['a', 'b', 'c']

bp0 = axs.boxplot(A, positions=[0], patch_artist=True, labels=labels[0])
bp1 = axs.boxplot(B, positions=[1], patch_artist=True, labels=labels[1])
bp2 = axs.boxplot(C, positions=[2], patch_artist=True, labels=labels[2])
# red, blue, green
colors = [(1.0, 0.0, 0.0, 1), (0.0, 0.0, 1.0, 1), (0.0, 0.5, 0.0, 1)]
box_list = [bp0, bp1, bp2]
# Set colors to the boxes
lbl_index = 0
for b_plot, color in zip(box_list, colors):
for patch in b_plot['boxes']:
patch.set_color(color)
lbl_index += 1

legend = axs.legend()
for index, handle in enumerate(legend.legend_handles):
assert isinstance(handle, mpl.patches.Rectangle)
assert handle.get_facecolor() == colors[index]
assert handle.get_edgecolor() == colors[index]
assert handle.get_label() == labels[index]
def test_boxplot_labels():
# Test that boxplot(..., labels=) sets the tick labels but not legend entries
# This is not consistent with other plot types but is the current behavior.
fig, ax = plt.subplots()
np.random.seed(19680801)
data = np.random.random((10, 3))
bp = ax.boxplot(data, labels=['A', 'B', 'C'])
# Check that labels set the tick labels ...
assert [l.get_text() for l in ax.get_xticklabels()] == ['A', 'B', 'C']
# ... but not legend entries
handles, labels = ax.get_legend_handles_labels()
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't this need an ax.legend() call first to properley test if any legend entries are added? It seems to work as intended, but locally I get a UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument. which is expected and I think should be caught in this test when ax.legend() is called.

Copy link
Member Author

@timhoffm timhoffm Feb 14, 2024

Choose a reason for hiding this comment

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

get_legend_handles_and_labels() is the "give me all entries for a legend" function. It traverses all artists and return handle+label for those that should be included in a legend because they have a label. Compare

grafik

ax.legend() calls that internally. IMHO it's more straight forward to just check that there are no artists for a legend that to try and create a legend and check that this warns that there are no entries.

assert len(handles) == 0
assert len(labels) == 0