ImageGrid changes aspect ratio

I’m not sure if this is a bug, but I want to bring it to light because it surprised me.

I’m following the tutorial here to use ImageGrid. I’m using all squared images but with different resolutions. I was surprised to find out that ImageGrid changes the aspect ratio of my images:

image

The following is a simple reproducer, adapted from the tutorial.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import numpy as np

im1 = np.arange(22*22).reshape((22, 22))
im2 = np.arange(16*16).reshape((16, 16))

fig = plt.figure(figsize=(4., 4.))
grid = ImageGrid(fig, 111, nrows_ncols=(1, 2), axes_pad=0.1)

for ax, im in zip(grid, [im1, im2]):
    ax.imshow(im)

plt.show()

I actually think the image on the left is being cut, which creates the impression the aspect ratio changed.

The issue is that ImageGrid shares the y-axis (and limits) along a row and the x-axis (and limits) down a column. Because your two images are different sizes I think the what is happening is:

  1. you plot the first image and it sets the limits to (-.5, 21.5) (-.5, 21.5) for both axes
  2. you plot the second image and it sets the limits of the second axes to (-.5, 15.5) (-.5, 15.5) and because the y-axis is shared the first axes also has its limits set to (-.5, 15.5) which crops your first image to 15
  3. because the aspect ratio is set to 1 the size of the both axes is adjusted so that they match the limits (making your left image looks like a rectangle).

ImageGrid needs to share limits like this because

If you want to use the ImageGrid you will either have to manually set the limits to be the biggest you would need (and accept white space around your smaller images) or use the extent keyword on imshow to make all of your images the same size in data coordinates (see origin and extent in imshow — Matplotlib 3.5.3 documentation)

I would also consider using the share_all=True keyword argument (mpl_toolkits.axes_grid1.axes_grid.ImageGrid — Matplotlib 3.5.3 documentation) .

1 Like

Thank you! It does make sense why this is happening now.

In my case I actually want to highlight images of different sizes, so I’ll go with setting the limits to the biggest I need. Is this the way to achieve it?

for ax, im in zip(grid, [im1, im2]):
    ax.imshow(im)
    ax.set_xlim([0, 22]) #hardcoded for illustratory purposes
    ax.set_ylim([22, 0])

Sorry for the very late reply, but yes that is exactly what I would do.