pythonmatplotlibaspect-ratio

How can I set the aspect ratio?


I'm trying to make a square plot (using imshow), i.e. aspect ratio of 1:1, but I can't. None of these work:

import matplotlib.pyplot as plt

ax = fig.add_subplot(111,aspect='equal')
ax = fig.add_subplot(111,aspect=1.0)
ax.set_aspect('equal')
plt.axes().set_aspect('equal')

It seems like the calls are just being ignored (a problem I often seem to have with matplotlib).


Solution

  • 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.