You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Right now, the macOS backend has a lot of "misfires" where it will momentary render a blank figure. This typically occurs when the figure is first displayed as well as during a window resize.
Here's a screen recording of me resizing "galleries/examples/pie_and_polar_charts/polar_demo.py" on an old MacBook Air:
Video of problem
⚠️WARNING: This video shows a flashing/flickering white box on top of a dark background.
movie.mp4
This also occurs on modern/faster hardware although not as pronounced.
The root cause is the use of timers to call setNeedsDisplay:YES. This was implemented in #21790 in order to fix #10980 and #17445. However, I believe that pull request was done without realizing it's possible to send the Agg buffer directly to an NSView (via layer-backing or layer-hosting) without the need of a -drawRect: callback.
At a very general level, the macOS run loop has different phases of execution:
Event-processing / Timers
Layout
Drawing
Right now, in response to a draw_idle() call, the macosx backend creates a single-shot NSTimer and adds it to the run loop. At best, the timer will not fire until the next run loop cycle. If we are in "Phase 1" above, the earliest that _draw_idle() will be called is the next "Phase 1". We will skip over the actual draw phase ("Phase 3") of the current run loop cycle.
"The system reserves the right to apply a small amount of tolerance to certain timers regardless of the value of the tolerance property.
Basically, using an NSTimer is the equivalent of telling the system: "perform this invocation no earlier than X, but you can delay a bit after X to save power."
draw_idle() should instead do the following:
If running in the main thread, immediately call setNeedsDisplay.
If running on a background thread, dispatch_async() to the main thread and then call setNeedsDisplay.
Caution
This assumes a layer-backed/layer-hosted approach. It won't work with the current -drawRect: approach without breaking blitting.
Bug summary
Right now, the macOS backend has a lot of "misfires" where it will momentary render a blank figure. This typically occurs when the figure is first displayed as well as during a window resize.
Here's a screen recording of me resizing "galleries/examples/pie_and_polar_charts/polar_demo.py" on an old MacBook Air:
Video of problem
movie.mp4
This also occurs on modern/faster hardware although not as pronounced.
The root cause is the use of timers to call
setNeedsDisplay:YES. This was implemented in #21790 in order to fix #10980 and #17445. However, I believe that pull request was done without realizing it's possible to send the Agg buffer directly to an NSView (via layer-backing or layer-hosting) without the need of a-drawRect:callback.At a very general level, the macOS run loop has different phases of execution:
Right now, in response to a
draw_idle()call, the macosx backend creates a single-shot NSTimer and adds it to the run loop. At best, the timer will not fire until the next run loop cycle. If we are in "Phase 1" above, the earliest that_draw_idle()will be called is the next "Phase 1". We will skip over the actual draw phase ("Phase 3") of the current run loop cycle.Again, this is a best case scenario. Per Timer Tolerance:
Basically, using an NSTimer is the equivalent of telling the system: "perform this invocation no earlier than X, but you can delay a bit after X to save power."
draw_idle()should instead do the following:setNeedsDisplay.dispatch_async()to the main thread and then callsetNeedsDisplay.Caution
This assumes a layer-backed/layer-hosted approach. It won't work with the current
-drawRect:approach without breaking blitting.Code for reproduction
# galleries/examples/pie_and_polar_charts/polar_demo.pyActual outcome
Flicker, misalignment with macOS drawing phase
Expected outcome
No flicker when resizing. No flicker upon first showing the figure.
Additional information
No response
Operating system
macOS (Tested on 10.14, 14.7, and 27 beta 2)
Matplotlib Version
3.11
Matplotlib Backend
macosx
Python version
3.14.5
Jupyter version
No response
Installation
None