Skip to content

Invalid pixel ratio update when changing screen resolution #19656

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

Closed
rayosborn opened this issue Mar 6, 2021 · 5 comments
Closed

Invalid pixel ratio update when changing screen resolution #19656

rayosborn opened this issue Mar 6, 2021 · 5 comments

Comments

@rayosborn
Copy link

rayosborn commented Mar 6, 2021

Bug report

Bug summary

When switching from an external monitor, with a dpi ratio of 1.0, to my MacBook Pro laptop, with a dpi ratio of 2.0, existing PyQt windows containing Matplotlib plots look fine after waking from sleep but switch to a quarter size as soon as I select the window, i.e., the fix in the PR #19123 doesn't seem to work in this scenario.

Code for reproduction

I am using the NeXpy package, which embeds Matplotlib canvases in separate PyQt5 windows. Each window is added to a dictionary, called plotviews, which is available to an embedded Python shell. If I initially plot on my external monitor, I get the following plot:
external-monitor
In the shell, I see the following ratios.

In [1]: for pv in plotviews:
            print(plotviews[pv].canvas._dpi_ratio, plotviews[pv].canvas._dpi_ratio_prev)
1.0 1.0
1.0 1.0
1.0 1.0

Actual outcome
When I switch to my laptop, the plots look fine initially, but as soon as I select any window, the plot shrinks to quarter size:
laptop-screen

In [2]: for pv in plotviews:
            print(plotviews[pv].canvas._dpi_ratio, plotviews[pv].canvas._dpi_ratio_prev)
2.0 1.0
2.0 1.0
2.0 1.0

After the plots have shrunk, the _dpi_ratio_prev has still not been updated.

In [3]: for pv in plotviews:
            print(plotviews[pv].canvas._dpi_ratio, plotviews[pv].canvas._dpi_ratio_prev)
2.0 1.0
2.0 1.0
2.0 1.0

Expected outcome
Obviously, the plots should not change size. Selecting the window does not appear to trigger the canvas showEvent function. I'm not sure what does. If I force an update, the plot does expand to the correct size. Note that _dpi_ratio_prev has been updated after the explicit call to _update_screen but only for the third figure. The others are still shrunk.

In [4]: screen=plotviews['Figure 3'].canvas.window().windowHandle()
In [5]: plotviews['Figure 3'].canvas._update_screen(screen.screen())
In [6]: for pv in plotviews:
            print(plotviews[pv].canvas._dpi_ratio, plotviews[pv].canvas._dpi_ratio_prev)
2.0 1.0
2.0 1.0
2.0 2.0

I wonder if the screenChanged signal should be connected to _update_screen at an earlier stage in initializing the window without depending on a call to showEvent.

Matplotlib version

  • Operating system: Mac OS X 10.15.7
  • Matplotlib version: 3.4.0rc1
  • Matplotlib backend: Qt5agg
  • Python version: 3.8.6
  • PyQt5 version: 5.15.2

I used pip to update to the latest release candidate within a conda environment.

Edited to correct reference to the screen.

@rayosborn
Copy link
Author

rayosborn commented Mar 6, 2021

As a follow-up, if I add the following code when I create a new plotview, i.e., as soon as the PyQt5 window exists, the windows change resolution correctly.

        try:
            self.window().windowHandle().screenChanged.connect(self.canvas._update_screen)
        except Exception as error:
            pass

Edit: I might have spoken too soon. It seemed to fix it in initial tests, but the problem is recurring now, although I can always manually force a call to _update_screen to fix it. There may be subtleties I don't understand about when the screenChanged signal is triggered.
EditEdit: I think I had introduced the above code too soon - if I set up the signal-slot connection when I first make the window active, it works well. So I think the fix in #19123 is good, but showEvent is not the ideal place to make the connection, at least in some contexts. For example, it might only affect packages that embed Matplotlib canvases in their own windows.

@dstansby
Copy link
Member

dstansby commented Jan 2, 2023

Is this still an issue with Matplotlib 3.6? There were some improvements to HiDPI scaling since version 3.4, so there's a chance this might have been fixed since originally reported.

@rayosborn
Copy link
Author

In NeXpy, I fixed this a long time ago by calling _update_screen whenever a plot window is made active. I will see if it is still needed when I next connect to an external monitor.

@rayosborn
Copy link
Author

I think it has been fixed now in version 3.6.2. I commented out the call to _update_screen and was able to switch from external monitor to laptop without seeing the same issue I had before. I can't use the canvas._dpi_ratio as a diagnostic since it seems to have been removed.

Thanks for asking the question. I will probably keep the call to _update_screen for now, since NeXpy users might still be using older versions of Matplotlib, but I guess I should add a version check in case the function gets removed, since it's private.

@dstansby
Copy link
Member

dstansby commented Jan 2, 2023

👍

@dstansby dstansby closed this as completed Jan 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants