drammock
drammock

Reputation: 2543

how to control subplot location within figure

I'm plotting multiple figures with imshow and aspect='equal', where the axis dimensions vary between figures. It's for a presentation, so I want the figures to end up left-aligned with respect to the figure edge (so the left axis lands in the same spot on each slide). Instead, what happens is that the axes get centered within the space alloted by subplots_adjust. Here's an example:

import numpy as np
import matplotlib.pyplot as plt

for width in [7, 10, 13]:
    data = np.random.rand(10 * width).reshape(10, width)
    fig, ax = plt.subplots(figsize=(3, 2))
    fig.subplots_adjust(left=0.1, right=0.9, bottom=0.2, top=0.8)
    ax.imshow(data)
    ax.set_title('10 × {}'.format(width))
    fig.savefig('10_rows_x_{}_columns.png'.format(width), facecolor='0.7',
                edgecolor='none')

example figure, narrow grid

example figure, medium grid

example figure, wide grid

How can I get the y-axis of all three axes to end up the same distance from the left edge of each figure?

Upvotes: 1

Views: 2158

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339230

Since the axes change their size due to the fixed aspect of the image, they are repositioned such that they are in the center of the figure, even if the subplot parameters specify a larger space.

Shrink the available space

You may draw the figure such the position of the axes is fixed, obtain the actual width of the axes, and set the right subplot parameter as the sum of the left and the width.

import numpy as np
import matplotlib.pyplot as plt

for width in [7, 10, 13]:
    data = np.random.rand(10 * width).reshape(10, width)
    fig, ax = plt.subplots(figsize=(6, 4))
    fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)
    ax.imshow(data)
    ax.set_title(u'10 × {}'.format(width))
    
    fig.canvas.draw()
    pos=ax.get_position()
    fig.subplots_adjust(right=0.1+pos.width)
    
    fig.savefig('10_rows_x_{}_columns.png'.format(width), facecolor='0.7',
                edgecolor='none')
plt.show()

Iteratively change position

A hack would be to iteratively set the axes left position to 0.1 draw the figure, let the axes rescale itself, then again set the axes position etc. such that evenually it will end up at the x=0.1 position.

import numpy as np
import matplotlib.pyplot as plt

for width in [7, 10, 13]:
    data = np.random.rand(10 * width).reshape(10, width)
    fig, ax = plt.subplots(figsize=(6, 4))
    fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)
    ax.imshow(data)
    ax.set_title(u'10 × {}'.format(width))
    fig.canvas.draw()
    while ax.get_position().x0 > 0.1:
        pos=ax.get_position()
        pos.x0=0.1
        ax.set_position(pos)
        fig.canvas.draw()
    fig.savefig('10_rows_x_{}_columns.png'.format(width), facecolor='0.7',
                edgecolor='none')
plt.show()

Note that this redraws the figure ~ 50 times or so. So depending on the accuracy needed, one may opt for a slightly larger condition, like while ax.get_position().x0 > 0.105: or so.

Both methods result in the following pictures.

enter image description here
enter image description here
enter image description here

Upvotes: 1

Related Questions