Repository navigation
Description
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:

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:

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.
Activity
rayosborn commentedon 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.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_screento fix it. There may be subtleties I don't understand about when thescreenChangedsignal 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
showEventis 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 commentedon 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 commentedon Jan 2, 2023
In NeXpy, I fixed this a long time ago by calling
_update_screenwhenever a plot window is made active. I will see if it is still needed when I next connect to an external monitor.rayosborn commentedon Jan 2, 2023
I think it has been fixed now in version 3.6.2. I commented out the call to
_update_screenand was able to switch from external monitor to laptop without seeing the same issue I had before. I can't use thecanvas._dpi_ratioas a diagnostic since it seems to have been removed.Thanks for asking the question. I will probably keep the call to
_update_screenfor 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 commentedon Jan 2, 2023
👍