Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Add legend support for boxplots#27840
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
saranti commentedMar 2, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Other things that need to be done at some stage:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for your work on this@saranti. It looks like you've done some good work pulling a variety of strands together.
One thing I'm a bit confused about is how the legend label is passed fromboxplot
tobxp
. It is passed both as part of theboxprops
dictionary and by itself. Why not just pass with thelabel parameter?
@@ -0,0 +1,5 @@ | |||
``boxplot`` legend labels | |||
~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
The tick labels on `~.Axes.boxplot` were previously set with the `labels` parameter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The tick labels on `~.Axes.boxplot` were previously set with the`labels` parameter. | |
The tick labels on `~.Axes.boxplot` were previously set with the*labels* parameter. |
When you use backticks, Sphinx tries to turn the word into a link. We have a convention to useemphasis for parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
You're right, theboxprops
label is redundant. When i first implemented this, I used it as the only check to see iflabels
has been set but then I realized that it should've been set at the bxp function. Everything in the 'if boxprops' condition is no longer needed.
Legend support for Boxplot | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
Boxplots now generate legend entries and can be labelled with the | ||
new `label` parameter. If a patch is passed to the box with `show_patch=True`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
new`label` parameter. If a patch is passed to the box with `show_patch=True`, | |
new*label* parameter. If a patch is passed to the box with ``show_patch=True``, |
Double backtick gets you code formatting.
lib/matplotlib/axes/_axes.py Outdated
@@ -3884,10 +3885,12 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None, | |||
If `False` produces boxes with the Line2D artist. Otherwise, | |||
boxes are drawn with Patch artists. | |||
labels : sequence, optional | |||
tick_labels : sequence, optional | |||
Labels for each dataset (one per dataset). These are used for | |||
x-tick labels; *not* for legend entries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Since the parameter now has a more specific name, I think we no longer need the note about them not being for the legend.
label : sequence, optional | ||
Legend labels for each boxplot. | ||
.. versionadded:: 3.9 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
IIRC thedata parameter is special and should always come last.
lib/matplotlib/axes/_axes.py Outdated
box_or_whis = boxes if showbox else whiskers | ||
for index, element in enumerate(box_or_whis): | ||
try: | ||
if isinstance(boxprops['label'], list): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I thinkis_scalar_or_string may be useful here.
lib/matplotlib/tests/test_legend.py Outdated
with pytest.warns(mpl.MatplotlibDeprecationWarning, | ||
match='has been renamed \'tick_labels\''): | ||
first = axs[0, 0].boxplot(data, | ||
labels=labels, # `tick_labels` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe usetick_labels here rather than the deprecated name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
If I don't use the deprecated name then this pytest will fail.
lib/matplotlib/tests/test_legend.py Outdated
# This plot will not generate a legend. | ||
with pytest.warns(UserWarning, match='No artists with labels found'): | ||
warnings.warn('No artists with labels found.', UserWarning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think this might be a stray debugging line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yes it is. I'm having trouble trying to get pytest to catch the UserWarning whenlegend
is called without the labels being set. The list of emitted warnings is always null even though the warning is clearly raised in
matplotlib/lib/matplotlib/legend.py
Lines 1364 to 1370 in013757e
eliflen(args)==0:# 0 args: automatically detect labels and handles. | |
handles,labels=_get_legend_handles_labels(axs,handlers) | |
ifnothandles: | |
_api.warn_external( | |
"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.") |
lib/matplotlib/tests/test_legend.py Outdated
showmeans=True, | ||
patch_artist=True) | ||
axs[0, 1].set_title('Tick labels, no legend') | ||
axs[0, 1].legend() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It might be good for this test toget hold of the legend handles and labels and assert that these lists are empty.
Uh oh!
There was an error while loading.Please reload this page.
lib/matplotlib/axes/_axes.py Outdated
@@ -3956,6 +3959,10 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None, | |||
The style of the mean. | |||
data : indexable object, optional | |||
DATA_PARAMETER_PLACEHOLDER | |||
label : sequence, optional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think this could be a single string or a sequence?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This might actually need to bestr or list of str
The tests failed because of a problem with a new version of pytest which has now been yanked. I’m going to close and re-open to restart the CI. |
timhoffm commentedMar 4, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
AFAICT, this needs a rebase to pick up the pytest pinning. |
@melissawm Thanks for the help yesterday, the rebase seems to have gone fine. The only problem I see now is that all the code having to do with the violin plot shouldn't be there and belongs to#27815 |
@saranti your branch is still 60 commits behind
to get it up to date. That should also get rid of the violinplot changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I feel uncomfortable with the scope of the PR - which has prevented me from looking more closely. It mixes the two independent topics legend support and parameter rename. I would I encourage separate PRs or at least separate commits to make it clear which feature is responsible for which code changes, and to ease review.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
9fcf0c0
toc17906f
CompareThe old tick label test was still there after doing |
I’ve never used |
1902592
to9fcf0c0
CompareUh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
To fix the doc build.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
timhoffm commentedMar 19, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Milestoning as 3.9 because it would be nice to get this in and IMO it’s ready. Just needs a second review. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
lib/matplotlib/axes/_axes.py Outdated
raise ValueError("There must be an equal number of legend" | ||
" labels and boxplots.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This check should probably be in the "input validation" section, and reusedatashape_message
.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
PR summary
Closes#27792. Boxplots now get legend entries.
This was previously attempted on#27711 and then reverted#27780 because it used the same parameter for tick labels and didn't generalize well. These 2 issues have been addressed in this PR.
A new
label
parameter has been added toAxes.boxplot
andAxes.bxp
. If called viaax.boxplot()
, label is passed to the bxp function, otherwise bxp can be directly called with the label parameter.The label is passed to the
boxes
object ifshowbox=True
, otherwise it will be passed to themedians
object isshowbox=False
. Attaching the label to the boxes makes sure that the legend handles will get a patch which will be displayed on the legend.If the box is turned off, the legend handles will get a Line2D object from the median line which will be displayed as a line in the legend. This has 2 advantages:
box
,caps
,flyers
andmeans
, themedians
cannot be turned off so they're a good vehicle for the legend label and will ensure that the labels always get set.Click to old test cases
PR checklist