-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
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
Check if the mappable is in a different Figure than the one fig.color… #27458
Conversation
…bar is being called on. Ignore this check if the mappable has no host Figure. Warn in case of a mismatch.
Hi! This is my first time contributing to matplotlib. |
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.
Thank you for opening your first PR into Matplotlib!
If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks.
You can also join us on gitter for real-time discussion.
For details on testing, writing docs, and our review process, please see the developer guide
We strive to be a welcoming and open project. Please follow our Code of Conduct.
Thank you for working on this! Could you also add a test that this warning is in fact raised? Could you also try adding the repr of the two figures to the warning? I'm not sure it is super helpful right now but might benifit if we improve the figure repr in the future. |
Oops, there seem to be a problem. I'll try fixing it. |
lib/matplotlib/figure.py
Outdated
@@ -1242,6 +1242,12 @@ def colorbar( | |||
fig.sca(current_ax) | |||
cax.grid(visible=False, which='both', axis='both') | |||
|
|||
if hasattr(mappable, "figure") and mappable.figure is not self.figure: | |||
_log.warning( |
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.
Did we want a _log.warning or a warning.warning? How bad do we think it is that a user has put a colorbar on a different figure?
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.
We should probably use warn_external
rather that _log.warning
.
I think we should also only add this warning if we inferred what axes to steal from
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
fig2, (axA, axB) = plt.subplots(2)
im = ax.imshow([[1, 2], [3, 4]])
fig2.colorbar(im) # this should warn
fig2.colorbar(im, ax=ax) # this is weird, but should not warn
fig2.colorbar(im, ax=axA) # this should not warn
fig2.colorbar(im, cax=axB) # also should not warn
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, warn_external
is the way to go.
I think we should also only add this warning if we inferred what axes to steal from
I'm not convinced. Generally, it is dubious if the mappable is in another figure than the colorbar, because there's no guarantee that both are shown together. Scenarios I could imagine are somewhat contrieved: (1) you have two figures with images in a paper, but only want to show one colorbar; (2) You have a GUI app and want to render the colorbar in a separate widget. In such cases I would recommend to reconsider whether that's actually a good idea (which the warning would serve to). And if somebody is convinced this is still the right path to take, they can filter the warning.
In turn, it's quite likely that the user has mixed up some fig/ax variables when mappable and colorbar are on different figures, e.g. fig2.colorbar(im, ax=ax)
above could very well have been a typo and fig.colorbar(im, ax=ax)
was actually intended.
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 agree with @timhoffm. I think we should warn anyway, and users can decide if it is a mistake or what they intend to do. For now I'm going to go ahead with this and submit a new commit which also includes some code style fixes and hopefully we can resolve this conversation.
Good point. Using `_api.warn_external` is probably more proper as users can
change code to stop the warning. As a new contributor I'm not in a position
to make the decision though. Can I have your advice on this?
…On Thu, Dec 7, 2023 at 12:38 PM Jody Klymak ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In lib/matplotlib/figure.py
<#27458 (comment)>
:
> @@ -1242,6 +1242,12 @@ def colorbar(
fig.sca(current_ax)
cax.grid(visible=False, which='both', axis='both')
+ if hasattr(mappable, "figure") and mappable.figure is not self.figure:
+ _log.warning(
Did we want a _log.warning or a warning.warning? How bad do we think it is
that a user has put a colorbar on a different figure?
—
Reply to this email directly, view it on GitHub
<#27458 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ALGAZZGAUR6BCQYYEH766W3YIISM5AVCNFSM6AAAAABAKPQ2FOVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMYTONZRGA3TAOJQGE>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Just checked the failure log. Turns out that this new mismatch warning was emitted in Should I delete the test
|
no. You should assert that the new warning is thrown using |
with pytest.warns(UserWarning, match="different Figure"): | ||
subfig.colorbar(cs, ax=ax, orientation=orientation, fraction=0.4, |
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.
Ah, subfigures are an edge case. IMHO we should not warn on different subfigures as long as the colorbar and mappable are in the same top-level figure. To that end, subfigures are more a layout element, and it is still ensured that mappable and colorbar are rendered alongside each other.
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 see, thanks for clarifying.
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'd probably do whatever is easier - if you can be more permissive then fine, but warning if the colorbar is in the wrong subfigure is probably fine too - its hard to think of a use case where that would be any more useful than having the colorbar on another figure.
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.
Agreed. But if it's not useful, we should rewrite the test. Doesn't make sense to have a contrived test that needs handling of a warning because of its awkward structure.
Actually, looking at the test, why does it raise the warning? All operation seem to run on the
sub figures individually. AFAICS
- we create subplots in the sub figure
- we add a contourset to each Axes
- Add a colorbar for each contourset, stealing space from the associated Axes
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 the test case warned because I was checking if self.figure
is the same instance as mappable.figure
in fig.colorbar(mappable)
, which returned false when:
- Both
self.figure
andmappable.figure
are figure instances, but not the same one. - One of them is figure and the other subfigure.
In the latest commit this should be fixed. When self.figure
or mappable.figure
is a subfigure, I use the associated figure for comparison.
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.
Oh, also, if i'm getting your question correctly, the test case failed in the previous run becasue it did not warn while with pytest.warns(...)
is to make sure it actually warns.
Hi! Just want to follow up on this. Is there anything else I need to do with this PR? |
lib/matplotlib/figure.py
Outdated
if isinstance(mappable_host_fig, mpl.figure.SubFigure): | ||
mappable_host_fig = mappable_host_fig.figure | ||
if isinstance(self_host_fig, mpl.figure.SubFigure): | ||
self_host_fig = self_host_fig.figure |
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.
Given our discussion, it seems like this should get a test?
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.
Sure. These lines are for the subfigure cases. In the latest commit, there are tests regarding subfigures in test_figure::test_warn_colorbar_mismatch
, line 1685:1702, which specifically include:
- Test that no warning is emitted when calling fig.colorbar(subfig), where subfig is associated with the fig.
- Test that no warning is emitted when calling subfig1.colorbar(subfig2), where both subfigs are associated with the same figure.
- Test that a warning is emitted when calling subfig1.colorbar(subfig2), where subfig1 is not associated with the same figure as subfig2.
Which cases am I missing? Please let me know and I'll add them.
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.
Oh, and the reason L1252 is not covered by test is that self_host_fig
is always a figure object no matter if we call colorbar() on a subfigure or figure. I should remove L1251:1252 in the next commit. Thanks!
I still am 50/50 that we should only warn if we picked the different figure, but will defer to @timhoffm . |
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.
LGTM, modulo one minor stylistic issue.
lib/matplotlib/figure.py
Outdated
if hasattr(mappable, "figure") and mappable.figure is not None: | ||
# Get top level artists | ||
mappable_host_fig = mappable.figure | ||
self_host_fig = self.figure |
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 would not declare an extra variable for this. It’s only used once and using self.figure is fine there.
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.
Will fix this.
Great. Thanks!
…On Wed, Dec 20, 2023, 06:22 Tim Hoffmann ***@***.***> wrote:
***@***.**** approved this pull request.
LGTM.
------------------------------
In lib/matplotlib/figure.py
<#27458 (comment)>
:
> @@ -1242,6 +1242,20 @@ def colorbar(
fig.sca(current_ax)
cax.grid(visible=False, which='both', axis='both')
+ if hasattr(mappable, "figure") and mappable.figure is not None:
+ # Get top level artists
+ mappable_host_fig = mappable.figure
+ self_host_fig = self.figure
I would not declare an extra variable for this. It’s only used once and
using self.figure is fine there.
—
Reply to this email directly, view it on GitHub
<#27458 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ALGAZZEJ6SEX2JR7VN5CM2DYKLYCZAVCNFSM6AAAAABAKPQ2FOVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMYTOOJQHE4TGMBWGE>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Thank you @zoehcycy and congratulations on your first merged Matplotlib PR 🎉 I hope we hear from you again! I took the liberty of squash-merging this to one commit. |
No problem. Thanks for everyone's help! |
…bar is being called on.
Ignore this check if the mappable has no host Figure. Warn in case of a mismatch.
PR summary
PR checklist