Skip to content

fix: resolve FigureCanvasTkAgg clipping on Windows HiDPI#31133

Merged
timhoffm merged 9 commits intomatplotlib:mainfrom
statxc:fix/issue-31126
Mar 11, 2026
Merged

fix: resolve FigureCanvasTkAgg clipping on Windows HiDPI#31133
timhoffm merged 9 commits intomatplotlib:mainfrom
statxc:fix/issue-31126

Conversation

@statxc
Copy link
Copy Markdown
Contributor

@statxc statxc commented Feb 11, 2026

PR summary

Closes #31126

Why is this change necessary?

  • On HiDPI displays, FigureCanvasTkAgg embedded in layout-managed containers renders plots larger than the visible area, clipping axis labels and legends.

What problem does it solve?

  • When DPI changes, the canvas is configured to a larger size but layout managers constrain it, preventing the <Configure> event from firing and leaving figure.size_inches miscalculated, causing the render buffer to exceed the visible canvas size.

What is the reasoning for this implementation?

  • After configuring canvas size, explicitly check if the actual displayed size differs from the configured size and call resize() to recalculate figure.size_inches with the correct DPI, ensuring render size matches visible size.

PR checklist

@github-actions
Copy link
Copy Markdown

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.
Please let us know if (and how) you use AI, it will help us give you better feedback on your PR.

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@tacaswell
Copy link
Copy Markdown
Member

I think I understand how this works, but it feels like there should be a better way in tk for widgets to be notified that their size is changed. We should be using that mechanism (possibly re-working how we currently do it) instead#.

@statxc
Copy link
Copy Markdown
Contributor Author

statxc commented Feb 12, 2026

I think I understand how this works, but it feels like there should be a better way in tk for widgets to be notified that their size is changed. We should be using that mechanism (possibly re-working how we currently do it) instead#.

Thanks @tacaswell , I see what you mean. I’ll try to find a better Tk-native way for widgets to react to size changes and rework the current approach based on that.

intelliking added 3 commits February 25, 2026 13:41
…resizing with actual widget dimensions instead of computed ones after DPI changes
@statxc
Copy link
Copy Markdown
Contributor Author

statxc commented Feb 25, 2026

@tacaswell @sanrishi Please review the PR and let me know your feedback. Thanks!

@statxc
Copy link
Copy Markdown
Contributor Author

statxc commented Mar 6, 2026

please any update for me. thanks

@tacaswell
Copy link
Copy Markdown
Member

Running the example code from #31126 on linux with X11 and hi-dpi I get

✔ 21:54:21 [belanna] @ python tk_bug.py
device_pixel_ratio: 1.6763463569165786
figure.dpi: 160.92925026399155 (original: 96)
figure.get_size_inches(): [23.86, 13.17]
Render size: 3840x2120
Canvas configured: 6437x3553
Canvas actual:     3840x2120

and it renders correctly.

vs the buggy case

✔ 21:54:33 [belanna] @ python tk_bug.py
device_pixel_ratio: 1.6763463569165786
figure.dpi: 160.92925026399155 (original: 96)
figure.get_size_inches(): [40.00, 22.08]
Render size: 6437x3553
Canvas configured: 6437x3553
Canvas actual:     3840x2120
BUG: render size (6437x3553) != actual size (3840x2120)

which renders clipped but on manually resizing fixes itself.

Copy link
Copy Markdown
Member

@tacaswell tacaswell left a comment

Choose a reason for hiding this comment

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

Manually verified that this fixes the problem and the fix makes sense.

Would like an explanation of the commit history before we merge.

@tacaswell tacaswell added this to the v3.11.0 milestone Mar 11, 2026
@statxc
Copy link
Copy Markdown
Contributor Author

statxc commented Mar 11, 2026

Manually verified that this fixes the problem and the fix makes sense.

Would like an explanation of the commit history before we merge.

Thanks for approving. What should I do on my end? I don't understand your mention Would like an explanation of the commit history before we merge. What should I explain exactly?

@tacaswell
Copy link
Copy Markdown
Member

There are commits from both @intelliking @statxc in the commit history. We are very much in favor of collaboration (it is the main thing we do here), but I also want to make sure everyone involved is aware they are involved etc. [I had a comment asking about this in another tab and failed to post it before my review]

@statxc
Copy link
Copy Markdown
Contributor Author

statxc commented Mar 11, 2026

@tacaswell Ah, I understand now. At first, my username was @intelliking. After that, I changed username to @statxc . @statxc and @intelliking are same - Me. Sorry for confusion. 🙏

width, height = event.width, event.height
self._resize_canvas(event.width, event.height)

def _resize_canvas(self, width, height):
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.

This should have a docstring

Suggested change
def _resize_canvas(self, width, height):
def _resize_canvas(self, width, height):
"""Update figure size and redraw based on a given canvas size."""

Also, the name _resize_canvas is a bit vague. Should this be _resize_figure_for_canvas_size?

# canvas backing store on that event.
# The easiest way to resize the canvas is to emit a
# resize event since we implement all the logic for resizing
# the canvas backing store on that event.
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.

Is the description correct? Isn't it primarily that we set the canvas size and then explicitly update the figure size using _resize_canvas (or possibly better named _resize_figure_for_canvas_size())? The event seems now an implementation detail of the called _resize_... method and seems to not be relevant here anymore.

@timhoffm timhoffm merged commit 8095b72 into matplotlib:main Mar 11, 2026
34 of 37 checks passed
@github-project-automation github-project-automation bot moved this from Needs review to Merged in First Time Contributors Mar 11, 2026
@timhoffm
Copy link
Copy Markdown
Member

Thanks @statxc !

@statxc statxc deleted the fix/issue-31126 branch March 11, 2026 20:40
andreas16700 added a commit to andreas16700/matplotlib that referenced this pull request Mar 16, 2026
andreas16700 added a commit to andreas16700/matplotlib that referenced this pull request Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

[Bug]: FigureCanvasTkAgg renders clipped/oversized when embedded in layout-managed container on Windows HiDPI

4 participants