You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The print_figure function in the FigureCanvasBase class records the current figure's dpi, sets it to the requested dpi for the saved figure, and then resets it to the original. Setting the dpi invokes a property function, _set_dpi that calls the figure's set_size_inches method, which then triggers a resize of the figure manager.
This resize is not evident when I use the standard Pyplot commands within a Qt console, presumably because the plot size doesn't change. However, I have embedded the Matplotlib figure in a PyQt GUI where I don't have the toolbar in the same widget, and it causes a noticeable size change for a fraction of a second before the second dpi reset restores the old size.
Possible solution
I would like to suggest that the FigureCanvasBaseprint_figure function should not invoke the dpi property, but set and then reset the figure's hidden variable, _dpi, which will not trigger the redundant canvas resize. I can submit a pull request, but I wanted to check if there would be side effects.
This is a side-effect of the work to support high-dpi screens and the need to temporarily double the dpi.
What is the dpi on the screen vs the dpi you are saving at? Is it a big change (factor of 2) or a small one? I suspect that this may actually be a bug in the figure size not round-tripping properly rather than in the dpi handling per-say. I am also not sure off the top of my head what is forcing the re-draw in the GUI. Are you using pyplot + embedding?
If we are going to go down the route of disabling the auto-redraw can it be done as a context manager (this is one of many things where we should be using context managers, but the code was written before context managers existed 😜 ).
I would say that it is an approximately 10% reduction in width during the temporary resize. The requested dpi of the PNG file I am saving is 100, and a little googling shows that the Thunderbolt display I am using has a dpi of 109, so that could be consistent. It's puzzling that the value of _dpi was already 100 before the resize, so another possible fix is to make sure that _set_dpi only triggers a resize if the new value is different (or is that something that context managers handle?).
The GUI subclasses FigureManagerQT, so it is using the save_figure function in backend_qt5.py. Matplotlib 2 must have added the _status_and_tool_height parameter, which I have set to 0, since my toolbar is in a different widget. It was while investigating why the parameter was needed that I encountered this issue.
If there is a long-term plan that will render this issue moot, then it can probably wait. It's just disconcerting seeing the window suddenly change size, and it took me a while to persuade myself that it reverted back to the same size.
I've finally realized what the problem is. When setting the dpi figure property, it restores the figure manager window to the canvas height and width, not the original window's height and width. There is a fudge in the FigureManagerQT resize function that adds the toolbar height to the canvas height, which works within Matplotlib, but I would argue that it screws up any attempt to embed a Matplotlib canvas in another GUI as I am doing. It would be much cleaner to confine canvas resizes to the canvas widget, and let PyQt handle the window resizes.
As a follow-up, I had already subclassed FigureManagerQT for other reasons. If I add the following resize function to the class, then my problems disappear, i.e., there is no discernible resize of the plotting window, temporary or permanent. I don't think it is related to screen resolutions.
Hello! Can you please tell me how I can solve this issue? I have the exact same problem: I am saving a figure over and over again, so that I can animate it afterwards but the figure keeps shriniking in size after successive saves...
I have set a custom dpi, which I though was the "fix" mentioned in #8805, but it did not make any difference.
I'm having the same issue as above, particularly like what @Datseris described.
I have a tkinter GUI for doing some plotting which has a tab displaying a single Figure with Axes that get cleared and updated when new plots are created/reselected. When saving one file, (using savefig), there is no issue, but when saving multiple plots iteratively (i.e. save the figure, clear axes, update, repeat...), the graph shrinks (both in the GUI and in the saved images). Here's a gif displaying the issue. The Figure is rendered at 150 DPI in the application, but I am trying to save at 300 DPI (specified when calling savefig, if I leave out the dpi argument I don't have the issue).
I'm using matplotlib v 3.2.1. Any ideas for a fix or workaround? I don't quite follow all of the thread above... but let me know if I can provide any other information. Thanks!
Activity
tacaswell commentedon Jun 9, 2017
This is a side-effect of the work to support high-dpi screens and the need to temporarily double the dpi.
What is the dpi on the screen vs the dpi you are saving at? Is it a big change (factor of 2) or a small one? I suspect that this may actually be a bug in the figure size not round-tripping properly rather than in the dpi handling per-say. I am also not sure off the top of my head what is forcing the re-draw in the GUI. Are you using
pyplot+ embedding?If we are going to go down the route of disabling the auto-redraw can it be done as a context manager (this is one of many things where we should be using context managers, but the code was written before context managers existed 😜 ).
rayosborn commentedon Jun 9, 2017
I would say that it is an approximately 10% reduction in width during the temporary resize. The requested dpi of the PNG file I am saving is 100, and a little googling shows that the Thunderbolt display I am using has a dpi of 109, so that could be consistent. It's puzzling that the value of
_dpiwas already 100 before the resize, so another possible fix is to make sure that_set_dpionly triggers a resize if the new value is different (or is that something that context managers handle?).The GUI subclasses FigureManagerQT, so it is using the
save_figurefunction inbackend_qt5.py. Matplotlib 2 must have added the_status_and_tool_heightparameter, which I have set to 0, since my toolbar is in a different widget. It was while investigating why the parameter was needed that I encountered this issue.If there is a long-term plan that will render this issue moot, then it can probably wait. It's just disconcerting seeing the window suddenly change size, and it took me a while to persuade myself that it reverted back to the same size.
tacaswell commentedon Jun 12, 2017
Probably related to roughly related to #8717
rayosborn commentedon Jun 13, 2017
I've finally realized what the problem is. When setting the
dpifigure property, it restores the figure manager window to the canvas height and width, not the original window's height and width. There is a fudge in the FigureManagerQT resize function that adds the toolbar height to the canvas height, which works within Matplotlib, but I would argue that it screws up any attempt to embed a Matplotlib canvas in another GUI as I am doing. It would be much cleaner to confine canvas resizes to the canvas widget, and let PyQt handle the window resizes.rayosborn commentedon Jun 13, 2017
As a follow-up, I had already subclassed FigureManagerQT for other reasons. If I add the following resize function to the class, then my problems disappear, i.e., there is no discernible resize of the plotting window, temporary or permanent. I don't think it is related to screen resolutions.
You could presumably do the same thing in FigureManagerQT, since
canvasis still its own widget, embedded in the main window.tacaswell commentedon Jun 13, 2017
that is a very experimentalist approach, I like it 👍
tacaswell commentedon Jun 13, 2017
exact work:
self._status_and_tool_heightFIX: prevent the canvas from jump sizes due to DPI changes
Datseris commentedon Apr 6, 2018
Hello! Can you please tell me how I can solve this issue? I have the exact same problem: I am saving a figure over and over again, so that I can animate it afterwards but the figure keeps shriniking in size after successive saves...
I have set a custom
dpi, which I though was the "fix" mentioned in #8805, but it did not make any difference.tacaswell commentedon Apr 6, 2018
What version of Matplotlib are you using? This should have been fixed in the 2.2 series.
Datseris commentedon Apr 6, 2018
Yes you are right, sorry for the spam. Turns out I wasn't up to date with the latest version. Now everything is working properly!
earnestt1234 commentedon Jun 4, 2020
I'm having the same issue as above, particularly like what @Datseris described.
I have a
tkinterGUI for doing some plotting which has a tab displaying a singleFigurewithAxesthat get cleared and updated when new plots are created/reselected. When saving one file, (usingsavefig), there is no issue, but when saving multiple plots iteratively (i.e. save the figure, clear axes, update, repeat...), the graph shrinks (both in the GUI and in the saved images). Here's a gif displaying the issue. TheFigureis rendered at 150 DPI in the application, but I am trying to save at 300 DPI (specified when callingsavefig, if I leave out thedpiargument I don't have the issue).I'm using
matplotlibv 3.2.1. Any ideas for a fix or workaround? I don't quite follow all of the thread above... but let me know if I can provide any other information. Thanks!earnestt1234 commentedon Jun 5, 2020
I added lines to explicitly update the canvas and the application every loop, and that seemed to fix the issue. NVM!