FIX: round copy_from_bbox regions out to whole pixels by larsoner · Pull Request #32264 · matplotlib/matplotlib · GitHub
Skip to content

FIX: round copy_from_bbox regions out to whole pixels - #32264

Open
larsoner wants to merge 1 commit into
matplotlib:mainfrom
larsoner:blit
Open

FIX: round copy_from_bbox regions out to whole pixels#32264
larsoner wants to merge 1 commit into
matplotlib:mainfrom
larsoner:blit

Conversation

@larsoner

Copy link
Copy Markdown
Contributor

PR summary

I noticed some visual drift while working on evoked.animate_topomap code in MNE-python, whittled down to MWE (forced full-repaint exposes the full Agg canvas to show the bug more obviously):

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots(figsize=(4, 2), dpi=100, layout="constrained")
ax.spines["top"].set_color("white")
ln = ax.axvline(0, color="r", lw=3)

def animate(i):
    ln.set_xdata([i / 199] * 2)
    if i % 20 == 0:
        fig.canvas.update()          # full repaint: buffer -> screen
    return [ln]

anim = FuncAnimation(fig, animate, frames=200, interval=10, blit=True, cache_frame_data=False)
fig.canvas.draw()  # force it to settle geometry
assert ax.bbox.y1 % 1, f"need a fractional Axes top edge, got {ax.bbox.y1}"
plt.show(block=True)

gives this for main, with just the copy-from-bbox fix, then with that plus the Qt fix:

Screencap movies

main

Screen.Recording.2026-08-30.at.07.53.48.mov

Just copy-to-bbox fix

Screen.Recording.2026-08-30.at.07.54.36.mov

copy-to-box plus Qt (this PR's state)

Screen.Recording.2026-08-30.at.08.17.19.mov

I then refactored the code into a shared helper, and searched for other places for likely truncation errors, and fixed those too (gtk3agg, wxagg, cairo). Hopefully everything is consistently applied across backends now 🤞 Happy to reduce scope if you want, this is a (perhaps overly optimistic) "let's try to get everything consistent at once" push!

Related to #8837 (sadly, doesn't close because that issue tracks a second bug about GUIs being "unable to render the image with a non-integer origin").

Similar class of fix that #14461 made in Tk, and refactors that code to use a shared helper (DRY) to perhaps/hopefully address @anntzer comment there:

we should specify somewhere how rounding of bboxes passed to blit() (and to copy_from_bbox()) works

AI Disclosure

Claude Opus 5 was used to examine the issue and draft the changes. I reviewed and iterated (a lot) with it on the code (DRY helper, scoping backends, interactively testing, verifying fixes, etc.), and believe I ended up with the changes I likely would have made if I sat down for many hours working on this alone.

PR quality check

  • Use an expressive title, e.g. "Fix title font property precedence"
  • New and changed code is tested
  • Plotting related features are demonstrated in an example (too subtle I think, but MWE above)
  • New features and API changes have release notes
  • Documentation complies with general and docstring guidelines (not a doc change)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant