FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

FIX: Make widget blitting compatible with swapped canvas by timhoffm · Pull Request #30591 · matplotlib/matplotlib · GitHub

Repository navigation

FIX: Make widget blitting compatible with swapped canvas - #30591

Merged
tacaswell merged 2 commits into
matplotlib:mainfrom
timhoffm:safe-blit
Dec 23, 2025
Merged

tacaswell merged 2 commits into
matplotlib:mainfrom
timhoffm:safe-blit

Conversation

timhoffm commented Sep 20, 2025 •
edited
Loading

Copy link
Copy Markdown
Member

First step towards improving blitting - towards #30503 and fixing #30575.

This PR proposes a minimal low-level API to store background information on the canvas.
It also adds higher-level methods save_blit_background() and load_blit_background() to AxesWidgets. Child classes can execrise managed background storage though this API.

I specifically would like to have feedback on the solution idea and API design. Note: This is not intended to be a solution for everything right away, but I would like to learn more on blitting through the case of widgets.

Open topics

  • Check whether widgets act reasonably if the background is pulled under them. - As implemented now, they won't crash, but we must ensure that they can recover the background. It may be (to be checked) that they just loose the background.
  • We still need to refactor useblit from statically including canvas blitting capability to dynamic handling.

Edit: Tested the following examples all with blitting enabled, and they work as expected (after closing the figure, plt.figure(fig); plt.show() recrates the figure and the widgets continue to work.

timhoffm commented Sep 26, 2025 •
edited
Loading

Copy link
Copy Markdown
Member Author

Recent update/commit: Support blitting with changing canvas in some widgets

Approach depends a bit on the widget, but generally:

  • self._useblit only stores the flag passed to __init__
  • canvas.supports_blit is checked dynamically when needed
  • we sometimes have the property sef.useblit, which is the effective
    value of flag and capability
  • if animated artists are used, that state is set during
    __init__ based on the flag. This relies on the fact that
    the flag cannot be changed later, and that the value of
    "animated" does not play a role for drawing canvases without blit support.

Supported:

  • Button
  • _SelectorWidget
  • SpanSelector
  • ToolLineHandles
  • ToolHandles
  • RectangleSelector
  • LassoSelector
  • PolygonSelector

Not supported yet:

  • CheckButtons
  • RadioButtons
  • Cursor
  • MultiCursor
  • Lasso

This should already fix #30575 as Selector widgets are covered.

Note: It's probably best to review the commits individually.

timhoffm force-pushed the safe-blit branch 2 times, most recently from b418b60 to f7ca7cc Compare September 26, 2025 10:21
timhoffm marked this pull request as ready for review September 26, 2025 10:46

Copy link
Copy Markdown
Member

Drat, I did not re-look at this PR before I opened #30605

timhoffm commented Oct 3, 2025

Copy link
Copy Markdown
Member Author

Rebased.

timhoffm commented Oct 3, 2025 •
edited
Loading

Copy link
Copy Markdown
Member Author

@tacaswell How do we want to continue here? I consider this PR complete for the handled widgets, and suggest that we review and merge it. The remaining widgets should be handled in a follow-up PR to keep this PR more manageable.

Here's a summary of this PR approach:

  • First commit: Create an infrastructure that safely handles background images by storing them on the canvas and defining an API in a way that there is no guarantee a background image is available. Consumers can try to obtain a background but must gracefully handle the case that no background is available.
    This is the basis to be able to reasonably handle blit-backgrounds while swapping canvas. Apply this to widgets that store backgrounds.
  • Second commit: Fix dynamic changes in useblit on the individual Widgets case-by-case. Since logic slightly differs between widgets, we have to think them through individually. The list of currently fixed widgets is in FIX: Make widget blitting compatible with swapped canvas #30591 (comment).

Comment thread lib/matplotlib/widgets.py
Comment thread lib/matplotlib/widgets.py
Comment thread lib/matplotlib/widgets.py
"""Update the canvas cursor."""
self.ax.get_figure(root=True).canvas.set_cursor(cursor)

def _save_blit_background(self, background):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Do we want to pass the bounding box in instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

For symmetry reasons and to keep the changes within the PR minimal, I would leave the complete handling to the individual widgets for now.

They do

self._save_blit_background(self.canvas.copy_from_bbox(self.ax.bbox))

and

background = self._load_blit_background()
if background is not None:
    self.canvas.restore_region(background)

It may be reasonable to refactor in a follow-up and move that logic to the base class.

Comment thread lib/matplotlib/widgets.py
timhoffm force-pushed the safe-blit branch 2 times, most recently from 30ca550 to 87fa6db Compare October 3, 2025 18:15
tacaswell added this to the v3.11.0 milestone Oct 3, 2025
tacaswell added the Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. label Oct 3, 2025
Approach depends a bit on the widget, but generally:
- `self._useblit` only stores the flag passed to __init__
- canvas.supports_blit is checked dynamically when needed
- we sometimes have the property `sef.useblit`, which is the effective
value of flag and capability
- if animated artists are needed that state is set during
  __init__ based on the flag. This relies on the fact that
  the flag cannot be changed later, and that the value of
  "animated" does not play a role for drawing canvases without blit support.

Supported:
- Button
- _SelectorWidget
- SpanSelector
- ToolLineHandles
- ToolHandles
- RectangleSelector
- LassoSelector
- PolygonSelector

Not supported yet:
- CheckButtons
- RadioButtons
- Cursor
- MultiCursor
- Lasso
tacaswell linked an issue Oct 30, 2025 that may be closed by this pull request
Comment thread lib/matplotlib/widgets.py

self._useblit = useblit and self.canvas.supports_blit
self._background = None
self._useblit = useblit and self.canvas.supports_blit # TODO: make dynamic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@timhoffm are you planning on addressing this TODO in this PR or is it a follow-up?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This is a follow-up and can land in 3.11 or later.

QuLogic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This API is semi-private, so it's open to change a bit, but I think it looks good regardless.

Comment thread lib/matplotlib/widgets.py

self._useblit = useblit and self.canvas.supports_blit
self._background = None
self._useblit = useblit and self.canvas.supports_blit # TODO: make dynamic

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Is this TODO necessary to complete before 3.11?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This is a follow-up and can land in 3.11 or later.

greglucas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think this is good to go with the current implementation and the TODOs can be addressed in follow-up PRs, but will leave that up to Tim whether he wants to get it in now.

Copy link
Copy Markdown
Member Author

First and foremost. This covers the regression #30575. That's prerequisite for 3.11.

We can live with not supporting canvas swapping on all widgets for 3.11. So it's ok to leave the TODOs and #30503 open.

tacaswell merged commit 15697ea into matplotlib:main Dec 23, 2025
44 checks passed
timhoffm deleted the safe-blit branch December 23, 2025 21:08
andreas16700 added a commit to andreas16700/matplotlib that referenced this pull request Jan 30, 2026
…widgets

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. topic: canvas and figure manager topic: widgets/UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Regression in widget behavior

4 participants


Back | FazBrowse Home | New Git URL