Skip to content

savefig() saves different aspect ratio than show() #3139

Closed

Description

@a6073758

The following script (using matplotlib 1.3.1) should create a 1-row, 3 column subplot with only one panel. The figure is displayed with show (which looks as desired) and also saved as a pdf using savefig. However, savefig has squeezed the wide figure into the normal aspect ratio, which it should not do.

#!/usr/bin/env python
import matplotlib
matplotlib.use('Qt4Agg')
from matplotlib.pyplot import *
from numpy import *

figure()
mgr = get_current_fig_manager()
mgr.window.setGeometry(0,0,800,200)
subplot(1,3,1)
x=linspace(0,2*pi,100)
plot(x,sin(x))
savefig('test.pdf')
show()

Activity

  1. efiring commented on Jun 16, 2014

    @efiring
    Member

    Does it do what you intend if you insert plt.draw() before the savefig?

  2. a6073758 commented on Jun 16, 2014

    @a6073758
    Author

    Tried it - didn't help.

    Somehow the call to setGeometry is not realized by matplotlib. My only workaround right now is to first set the position and size with setGeometry and then to set the size again with set_size_inches like so

    f=gcf()
    f.set_size_inches(800./f.dpi,200./f.dpi)
    

    This works fine, but I still need the call to setGeometry because I want to specify where on the screen the figure appears.

  3. Tillsten commented on Jun 16, 2014

    @Tillsten
    Contributor

    Could you try calling the repaint method()?

  4. a6073758 commented on Jun 17, 2014

    @a6073758
    Author

    where do I find that repaint method?

  5. pelson commented on Jun 17, 2014

    @pelson
    Member

    This is a documented "feature" of savefig: http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure.savefig

    dpi: [ None | scalar > 0 ]
        The resolution in dots per inch. If None it will default to the value savefig.dpi in the matplotlibrc file.
    

    Which essentially is saying, savefig ignores figure.dpi and instead uses the global rc param. I don't like it (I have a reputation for not liking much when it comes to rcParams) but it is documented so I'm going to go ahead and close the issue. It might be worth sparking a discussion on the mailing list about the behaviour if we want to change it, though the breakage that it may cause might make that a hard sell.

    Thanks for raising the issue @a6073758.

  6. tacaswell commented on Jun 17, 2014

    @tacaswell
    Member

    @pelson not sure I agree. I think the problem is the use of the qt geometry calls which rdint get propagate back to mpl from the gui layer.

  7. efiring commented on Jun 17, 2014

    @efiring
    Member

    @tacaswell is correct, this is not a question of dpi at all.
    If the example is run using ipython --pylab=qt, then it works for me on 1.3.1. Or, even without the --pylab, using a call to ion() is enough. When the figure is rendered on the screen, the geometry does change the output of fig.get_size_inches(), and savefig uses the modified dimensions.
    It's not clear that there is anything we should change here.

  8. pelson commented on Jun 18, 2014

    @pelson
    Member

    My apologies.

  9. reopened this on Jun 18, 2014
  10. tacaswell commented on Jun 25, 2014

    @tacaswell
    Member

    I would also add that fig.set_size_inches(forward=True) will resize the figure on-screen as well. Another alternative is to set the figure size when you create the figure ex

    fig, ax = plt.subplots(1, 3, figsize=(3, 6))
    

    I think that this should be closed as the problem is the OP doing and end-run around the mpl gui management layer but there are already ways for the management layer to push back down to the gui.

    There is also a call-back already in place (I only tested Qt) that updates the figure size in inches if you resize the window with the mouse. Interestingly, if you run this as a script, it does not work, but if you run the same commands in ipython (with their matplotlib magic), the change in size does propagate back up. This smells like another case of gui/interactive stuff barely working out side of ipython/interactive session.

  11. solarjoe commented on Jan 18, 2016

    @solarjoe

    I also came across this issue, but for a much simpler case.

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    
    fig = plt.figure(figsize=(11.7,  8.3), dpi=72.0)
    ax = fig.add_subplot(111, projection='3d')
    
    data = np.array([[0.0, 0.0, 0.0],
                     [0.0, 0.0, 1.0],
                     [1.0, 0.0, 1.0],
                     [1.0, 1.0, 1.0],
                     [1.0, 1.0, 0.0]])
    
    cs = ax.plot(data[:,0], data[:,1], data[:,2], 'b-')
    
    ax.set_aspect('equal')
    ax.auto_scale_xyz([0.0, 1.0], [0.0, 1.0], [0.0, 1.0])
    
    #plt.draw()
    #ax.apply_aspect()
    
    plt.savefig('c:/temptemp/test_aspect.png')
    plt.show()
    

    The workaround plt.draw() suggested by @efiring worked for me.
    Also is calling the Axes method ax.apply_aspect()

    I am pretty sure that this issue it related to #1104,
    maybe some callback function is not triggered correctly.

  12. nikosT commented on Nov 1, 2017

    @nikosT

    Any solution to this?

  13. jklymak commented on Nov 1, 2017

    @jklymak
    Member

    @nikosT Its a closed issue. Were you arguing it should be re-opened for some reason?

  14. BugCheck141 commented on Apr 23, 2020

    @BugCheck141

    Any solution to this?

    found it: call fig.tight_layout() before plt.savefig
    maybe plt.show triggers it automatically but savefig does not

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions