-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[Bug]: Figure does not scale to window size #22822
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
Comments
For what it is worth: this does not seem to be an issue on main using Linux (CentOS 7). So either it has been fixed in main or it is a platform dependent issue. |
I can reproduce this (with the additional issue that it bigger than half of my screen but it may be half of the size of the union of my two screens?). I think this is related to hi-dpi screens. If I do: import numpy as np
import matplotlib.pyplot as plt
# Generate some data
t = np.arange(0, 10, 0.1)
x = np.cos(t)
fig, ax = plt.subplots(1,1)
print(fig.canvas.device_pixel_ratio)
fig.canvas.mpl_connect('resize_event', lambda *args, **kwargs: print(args, kwargs))
# Put the figure in the top-left half of the screen
cur_win = fig.canvas.manager.window # Current window
screen_size = cur_win.wm_maxsize() # Get the screen size
# top-left half of the window:
(pos_x, pos_y, width, height) = (0, 0, screen_size[0]//2, screen_size[1]//2)
position = f'{width}x{height}+{pos_x}+{pos_y}' # Window geometry string
cur_win.geometry(position)
ax.plot(t, x)
plt.show()
print(fig.canvas.device_pixel_ratio) I see
and the 1.68 is the value that comes out of my system via
I think what is happening here is:
If I change the code to import numpy as np
import matplotlib.pyplot as plt
# Generate some data
t = np.arange(0, 10, 0.1)
x = np.cos(t)
fig, ax = plt.subplots(1,1)
print(fig.canvas.device_pixel_ratio)
fig.canvas.mpl_connect('resize_event', lambda *args, **kwargs: print(args, kwargs))
# Put the figure in the top-left half of the screen
cur_win = fig.canvas.manager.window # Current window
screen_size = cur_win.wm_maxsize() # Get the screen size
# top-left half of the window:
(pos_x, pos_y, width, height) = (0, 0, screen_size[0]//2, screen_size[1]//2)
position = f'{width}x{height}+{pos_x}+{pos_y}' # Window geometry string
plt.pause(.1) # <- NOTE THIS LINE it forces the window to display before we resize it!
cur_win.geometry(position)
ax.plot(t, x)
plt.show(); print(fig.canvas.device_pixel_ratio) I get a figure that shows the whole figure and is placed at the top-left of the theoretical union of my two screens (which are set up like attn @QuLogic This is related to the issues we were chasing down last week. attn @richardsheridan Should we be ignoring this scaling on *nix? |
That all looks right, but I'm not sure we need to support changing the window size without changing the figure size. In this case doesn't the user just need to fire the window resize callback manually since they are changing the window size manually? |
The issue is that when the window size is initially changed we have bad information about what the effective dpi should be so compute the wrong figure size to forward on. I think the core of the issue is that Tk handles the scaling / hi-dpi differently than the other backends. |
I'm leaning toward this.
which has the amusing side-effect of immediately resetting the window geometry if you try to resize it with the mouse. A real workaround would need to immediately un-register the callback. |
Yes, on Windows, the 'standard' monitor is 96 DPI, and for monitors with HiDPI scaling, we then increase that value by whatever that scale is. The 'scaling' value we use within Tk is the DPI over a 'standard' 72 DPI. This does not appear to be the case on Linux, and possibly is not true on macOS either. The Tk 'scaling' value is the true DPI (or at least whatever X wants to tell it it is) over 72 DPI and so we end up setting a fake HiDPI mode, even if that's not enabled on the system. The initial mixed DPI support was only intended for Windows, and so Linux/macOS don't even rescale properly when moving across monitors. I still haven't figured out how to do the rescaling on those systems (and I don't think it's really possible on X.) All that means, I think we need to ignore 'scaling' on non-Windows systems. |
Bug summary
When changing the window size of a figure, the figure does not scale immediately, so part of it is obscured. Only after a manual re-scaling (even if minute) the figure is displayed correctly.
Code for reproduction
Actual outcome
Expected outcome
When the size of the window is then MANUALLY changed, the figure immediately changes to the accurate scale:

Additional information
The bug appears from Matplotlib 3.5.1 onward
Operating system
Windows 11
Matplotlib Version
3.5.1
Matplotlib Backend
TkAgg
Python version
3.9.10
Jupyter version
No response
Installation
No response
The text was updated successfully, but these errors were encountered: