Skip to content

Fix scaling in Tk on non-Windows systems #28588

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 21, 2024
Merged

Conversation

rnhmjoj
Copy link
Contributor

@rnhmjoj rnhmjoj commented Jul 17, 2024

PR summary

Fix scaling in Tk on non-Windows systems, closes #10388

PR checklist

cc: @tacaswell

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

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

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

@tacaswell tacaswell added this to the v3.10.0 milestone Jul 18, 2024
@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Aug 22, 2024

ping

@tacaswell
Copy link
Member

Thank you for the ping!

attn @richardsheridan as our Tk expert.

@richardsheridan
Copy link
Contributor

This needs to be tested manually on Linux with two monitors with different dpi or scaling. I can't help with that though!

@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Aug 23, 2024

Here's a comparison:

comparison

@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Aug 23, 2024

I took the screenshots of the windows of the same plot at about the same physical dimensions on two different screens.
One is a full HD display with 96 dpi, the other a 4K display with 200 dpi. For comparison I upscaled the 96dpi screenshot to match those at 200dpi without an antialiasing filter (nearest-neighbour method).
As you can see by comparing the plot labels and the buttons this patch gives roughly the same results for both screens.

I tested everything on GNU/Linux with X.org. Someone should try a Wayland compositor and maybe macOS.

@timhoffm
Copy link
Member

Thanks for the comparison images. Positioning looks correct. I can't tell for the linewidths. Obviously, that depends on the upscaling. Probably an additional helpful comparison would be hidpi Qt backend vs hidpi Tk backend. I'd expect that the plot area would be pixel identical if we properly detect hidpi/magnification and feed it to the agg renderer.

@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Aug 23, 2024

There you go, Qt vs Tk on a 200dpi display:
comparison2

Copy link
Contributor

@richardsheridan richardsheridan left a comment

Choose a reason for hiding this comment

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

The scaling looks right, and if the window maintains about the same real-world dimensions when you drag it between monitors with different dpi, then I think it is good to go.

@timhoffm
Copy link
Member

There are two Tk tests on MacOS failing. I'm unclear whether this is related to the PR.

@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Aug 24, 2024

if the window maintains about the same real-world dimensions when you drag it between monitors with different dpi, then I think it is good to go.

It doesn't for me, but for neither toolkit. When dragging the window from the 200dpi to 96dpi screen the physical dimensions increase (because my window manager doesn't really do anything about DPI) and the canvas remains scaled at 2x.
With Qt, only if I force QT_SCREEN_SCALE_FACTORS='2;1' (despite both screens correctly reporting their physical dimensions) I can get the canvas to be re-rendered at 1x once the windows is fully contained in the 96dpi screen.

@tacaswell
Copy link
Member

I could not get to the build logs, but re-started the failed job.

@tacaswell tacaswell closed this Aug 28, 2024
@tacaswell tacaswell reopened this Aug 28, 2024
@tacaswell
Copy link
Member

"power cycled" to get the tests to run again.

@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Sep 16, 2024

Did anyone test this on macOS? If it's a concern I can enable it only for sys.platform == "linux".

Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

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

While I cannot test on OSX, I'm very much convinced that the non-windows way is "more correct" than the windows specific solution - Linux and OSX are typically similar on those matters.

If nobody can test in the next couple of days, IMHO we should be bold enough to merge as is.

@greglucas
Copy link
Contributor

I tested this on osx and it looks good locally to me. There are failing tests on osx with the tkagg backend which seem like they could be related.

@timhoffm
Copy link
Member

We can also be more defensive and only change for linux as proposed above and then create a followup issue to investigate OSX. It would be good to have at least the linux version included in 3.10.

@tacaswell
Copy link
Member

The test failure is real and we can reproduce it locally.

Debugging on a mac, it seems that ._tkcanvas.winfo_fpixels('1i') will always return something that is almost 72. It seems to depend on the screen resolution you use:

In [4]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[4]: 72.0354505169867

In [5]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[5]: 71.98228782287823

In [6]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[6]: 71.98228782287823

In [7]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[7]: 72.0354505169867

In [8]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[8]: 72.04875346260387

In [9]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[9]: 72.0354505169867

In [10]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[10]: 71.98228782287823

In [11]: fig.canvas._tkcanvas.winfo_fpixels('1i')
Out[11]: 72.00885935769656

in between the calls I changed the resolution OSX was using. I think we need to exclude OSX here as this method does not actually work there as it tries to "help" a bit too much.

# scaled vs 96 dpi, and pixel ratio settings are given in whole
# percentages, so round to 2 digits.
ratio = round(self._tkcanvas.tk.call('tk', 'scaling') / (96 / 72), 2)
else:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
else:
elif sys.platform == "linux":

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for testing it out! I limited the change to just "linux" and made sure _set_device_pixel_ratio is called only on supported platforms.

@QuLogic QuLogic merged commit 8552c7a into matplotlib:main Sep 21, 2024
40 checks passed
@QuLogic
Copy link
Member

QuLogic commented Sep 21, 2024

Thanks @rnhmjoj! Congratulations on your first PR to Matplotlib 🎉 We hope to hear from you again.

@rnhmjoj
Copy link
Contributor Author

rnhmjoj commented Sep 21, 2024

Thank you all for reviewing my patch!

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

Successfully merging this pull request may close these issues.

Add retina screen support for TkAgg backend
6 participants