How can I set the aspect ratio in matplotlib?

Third times the charm. My guess is that this is a bug and Zhenya's answer suggests it's fixed in the latest version. I have version 0.99.1.1 and I've created the following solution:

import matplotlib.pyplot as plt
import numpy as np

def forceAspect(ax,aspect=1):
    im = ax.get_images()
    extent =  im[0].get_extent()
    ax.set_aspect(abs((extent[1]-extent[0])/(extent[3]-extent[2]))/aspect)

data = np.random.rand(10,20)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data)
ax.set_xlabel('xlabel')
ax.set_aspect(2)
fig.savefig('equal.png')
ax.set_aspect('auto')
fig.savefig('auto.png')
forceAspect(ax,aspect=1)
fig.savefig('force.png')

This is 'force.png': enter image description here

Below are my unsuccessful, yet hopefully informative attempts.

Second Answer:

My 'original answer' below is overkill, as it does something similar to axes.set_aspect(). I think you want to use axes.set_aspect('auto'). I don't understand why this is the case, but it produces a square image plot for me, for example this script:

import matplotlib.pyplot as plt
import numpy as np

data = np.random.rand(10,20)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data)
ax.set_aspect('equal')
fig.savefig('equal.png')
ax.set_aspect('auto')
fig.savefig('auto.png')

Produces an image plot with 'equal' aspect ratio: enter image description here and one with 'auto' aspect ratio: enter image description here

The code provided below in the 'original answer' provides a starting off point for an explicitly controlled aspect ratio, but it seems to be ignored once an imshow is called.

Original Answer:

Here's an example of a routine that will adjust the subplot parameters so that you get the desired aspect ratio:

import matplotlib.pyplot as plt

def adjustFigAspect(fig,aspect=1):
    '''
    Adjust the subplot parameters so that the figure has the correct
    aspect ratio.
    '''
    xsize,ysize = fig.get_size_inches()
    minsize = min(xsize,ysize)
    xlim = .4*minsize/xsize
    ylim = .4*minsize/ysize
    if aspect < 1:
        xlim *= aspect
    else:
        ylim /= aspect
    fig.subplots_adjust(left=.5-xlim,
                        right=.5+xlim,
                        bottom=.5-ylim,
                        top=.5+ylim)

fig = plt.figure()
adjustFigAspect(fig,aspect=.5)
ax = fig.add_subplot(111)
ax.plot(range(10),range(10))

fig.savefig('axAspect.png')

This produces a figure like so: enter image description here

I can imagine if your having multiple subplots within the figure, you would want to include the number of y and x subplots as keyword parameters (defaulting to 1 each) to the routine provided. Then using those numbers and the hspace and wspace keywords, you can make all the subplots have the correct aspect ratio.


What is the matplotlib version you are running? I have recently had to upgrade to 1.1.0, and with it, add_subplot(111,aspect='equal') works for me.


A simple option using plt.gca() to get current axes and set aspect

plt.gca().set_aspect('equal')

in place of your last line


After many years of success with the answers above, I have found this not to work again - but I did find a working solution for subplots at

https://jdhao.github.io/2017/06/03/change-aspect-ratio-in-mpl

With full credit of course to the author above (who can perhaps rather post here), the relevant lines are:

ratio = 1.0
xleft, xright = ax.get_xlim()
ybottom, ytop = ax.get_ylim()
ax.set_aspect(abs((xright-xleft)/(ybottom-ytop))*ratio)

The link also has a crystal clear explanation of the different coordinate systems used by matplotlib.

Thanks for all great answers received - especially @Yann's which will remain the winner.