Skip to content

Figure resize when saving a plot #8736

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 Jun 9, 2017 · 12 comments · Fixed by #9131 or #10292
Closed

Figure resize when saving a plot #8736

rayosborn opened this issue Jun 9, 2017 · 12 comments · Fixed by #9131 or #10292
Labels
Good first issue Open a pull request against these issues if there are no active ones! GUI: Qt
Milestone

Comments

@rayosborn
Copy link

Bug report

Bug summary

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 FigureCanvasBase print_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.

Matplotlib version

  • Matplotlib Version: 2.0.2
  • Operating System: Mac OS 10.12.5
  • Python Version: 2.7.11
  • PyQt 4.8.7
@tacaswell
Copy link
Member

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
Copy link
Author

rayosborn commented 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 _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.

@tacaswell tacaswell added this to the 2.2 (next next feature release) milestone Jun 12, 2017
@tacaswell
Copy link
Member

Probably related to roughly related to #8717

@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Jun 12, 2017
@rayosborn
Copy link
Author

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.

@rayosborn
Copy link
Author

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.

def resize(self, width, height):
    extra_width = self.window.width() - self.canvas.width()
    extra_height = self.window.height() - self.canvas.height()
    self.window.resize(width+extra_width, height+extra_height)

You could presumably do the same thing in FigureManagerQT, since canvas is still its own widget, embedded in the main window.

@tacaswell
Copy link
Member

that is a very experimentalist approach, I like it 👍

@tacaswell
Copy link
Member

tacaswell commented Jun 13, 2017

exact work:

tacaswell added a commit to tacaswell/matplotlib that referenced this issue Aug 31, 2017
@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Sep 24, 2017
@tacaswell tacaswell added the Good first issue Open a pull request against these issues if there are no active ones! label Oct 16, 2017
@QuLogic QuLogic modified the milestones: needs sorting, v2.2.0 Feb 12, 2018
@Datseris
Copy link

Datseris commented 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
Copy link
Member

What version of Matplotlib are you using? This should have been fixed in the 2.2 series.

@Datseris
Copy link

Datseris commented 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
Copy link

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!

@earnestt1234
Copy link

I added lines to explicitly update the canvas and the application every loop, and that seemed to fix the issue. NVM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Good first issue Open a pull request against these issues if there are no active ones! GUI: Qt
Projects
None yet
5 participants