Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

FIX: be very paranoid about checking what the current canvas is#25573

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

Merged
timhoffm merged 2 commits intomatplotlib:mainfromtacaswell:fix_removed_widget_axes
Jul 18, 2025

Conversation

tacaswell
Copy link
Member

PR Summary

closes#25572

There are many ways for things to end up in odd states, the goal here is to detect if the the canvas has changed under us when trying to manage the state of widgets.

PR Checklist

Documentation and Tests

  • Has pytest style unit tests (andpytest passes)
  • [N/A] Documentation is sphinx and numpydoc compliant (the docs shouldbuild without error).
  • [N/A] New plotting related features are documented with examples.

Release Notes

  • [N/A] New features are marked with a.. versionadded:: directive in the docstring and documented indoc/users/next_whats_new/
  • [N/A] API changes are marked with a.. versionchanged:: directive in the docstring and documented indoc/api/next_api_changes/
  • [N/A] Release notes conform with instructions innext_whats_new/README.rst ornext_api_changes/README.rst

@tacaswelltacaswell added this to thev3.7.2 milestoneMar 29, 2023
@anntzer
Copy link
Contributor

Perhaps the simpler check would beself.canvas is self.canvas.figure.canvas? Note that while figure.canvas can change (hence the introduction of _changed_canvas), I think canvas.figure does not ever change (at least in practice... it may even be possible to spec that), so the proposed check is effectively "does the figure I initially got still use the same canvas as initially?" Also none of these attributes should ever be None, AFAICT.

Alternatively, we could additionally recordself._figure = ax.figure in the constructor and checkself._figure.canvas is self.canvas; again this should sidestep the None problems?

@tacaswell
Copy link
MemberAuthor

Alternatively, we could additionally record self._figure = ax.figure in the constructor and check self._figure.canvas is self.canvas; again this should sidestep the None problems?

I think that would still miss the "middle removed" issue as we have references that skip generations and we should avoid adding more hard-references than we strictly need....

But I will change toself.canvas is self.canvas.figure.canvas

@tacaswelltacaswellforce-pushed thefix_removed_widget_axes branch from54db976 to7100b57CompareMarch 31, 2023 20:08
Copy link
Contributor

@anntzeranntzer left a comment

Choose a reason for hiding this comment

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

Modulo CI, and with an optional additional comment.

@tacaswell
Copy link
MemberAuthor

Hmm, we are back to not being careful enough...but only an azure?!

@anntzer
Copy link
Contributor

That's a bit fishy, but perhaps just change all theself.ax.draw_artist(artist) byartist.draw(self.canvas.get_renderer())? (which should bypass the problem of whetherself.ax.figure is None or not -- anyways, having draw_artist be an Axes method always seemed a bit weird to me (I do realize that historically we cached the renderer on the axes, but that's not really the logical place to have it)).

@QuLogicQuLogic modified the milestones:v3.7.2,v3.7.3Jul 5, 2023
@QuLogicQuLogic modified the milestones:v3.7.3,v3.8.0Sep 9, 2023
@ksundenksunden removed this from thev3.8.0 milestoneSep 12, 2023
@tacaswelltacaswellforce-pushed thefix_removed_widget_axes branch froma9f4c6c todb2176fCompareJuly 18, 2025 00:15
@tacaswelltacaswell added this to thev3.11.0 milestoneJul 18, 2025
@@ -1085,7 +1087,7 @@ def __init__(self, ax, labels, actives=None, *, useblit=True,

def _clear(self, event):
"""Internal event handler to clear the buttons."""
if self.ignore(event) or self.canvas.is_saving():
if self.ignore(event) or self.canvas is None or self.canvas.is_saving():
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the canvas is not None check rather go to a newAxesWidget.ignore? (def AxesWidget.ignore(self, event): return not self.active or self.canvas is None)
Then this change and the one immediately below could go away.

Copy link
Member

Choose a reason for hiding this comment

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

I agree. This belongs logically in anAxesWidget.ignore().

Copy link
Contributor

@anntzeranntzer left a comment

Choose a reason for hiding this comment

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

I think the patch could be better, but this is also correct.

@tacaswell
Copy link
MemberAuthor

tacaswell commentedJul 18, 2025
edited
Loading

I tried putting the check inWidget.ignore which breaks for other things which is why I originally went with the checks in_clear.

Added a new method and a couple ofsuper() calls.

Comment on lines 1762 to 1782
def test_parent_axes_removal():

fig, (ax_radio, ax_checks) = plt.subplots(1, 2)

radio = widgets.RadioButtons(ax_radio, ['1', '2'], 0)
checks = widgets.CheckButtons(ax_checks, ['1', '2'], [True, False])

ax_checks.remove()
ax_radio.remove()
with io.BytesIO() as out:
fig.savefig(out, format='raw')

renderer = fig._get_renderer()
evt = DrawEvent('draw_event', fig.canvas, renderer)
radio._clear(evt)
checks._clear(evt)
Copy link
Member

Choose a reason for hiding this comment

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

This is obviously some kind of smoke test as it does not contain assertions. A short description would be helpful though.

I understand that removal of the buttons should not brick the figure. But what exactly are we testing with the savefig, and what with the _clear calls? (I assume there are actually two separate tests?

@tacaswelltacaswellforce-pushed thefix_removed_widget_axes branch from9f1da21 to5c83d7bCompareJuly 18, 2025 14:24
@timhoffmtimhoffm merged commit1503ac4 intomatplotlib:mainJul 18, 2025
39 of 40 checks passed
@tacaswelltacaswell deleted the fix_removed_widget_axes branchJuly 18, 2025 19:37
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@anntzeranntzeranntzer approved these changes

@timhoffmtimhoffmtimhoffm approved these changes

Assignees
No one assigned
Projects
None yet
Milestone
v3.11.0
Development

Successfully merging this pull request may close these issues.

[Bug]: Artist.remove() isn't fully removing it from figure
6 participants
@tacaswell@anntzer@timhoffm@QuLogic@jklymak@ksunden

[8]ページ先頭

©2009-2025 Movatter.jp