Imshow: Extent and Aspect

Imshow: extent and aspect

You can do it by setting the aspect of the image manually (or by letting it auto-scale to fill up the extent of the figure).

By default, imshow sets the aspect of the plot to 1, as this is often what people want for image data.

In your case, you can do something like:

import matplotlib.pyplot as plt
import numpy as np

grid = np.random.random((10,10))

fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, figsize=(6,10))

ax1.imshow(grid, extent=[0,100,0,1])
ax1.set_title('Default')

ax2.imshow(grid, extent=[0,100,0,1], aspect='auto')
ax2.set_title('Auto-scaled Aspect')

ax3.imshow(grid, extent=[0,100,0,1], aspect=100)
ax3.set_title('Manually Set Aspect')

plt.tight_layout()
plt.show()

Sample Image

What does extent really do in matplotlib?

I suppose you are inquiring about the imshow's extent keyword argument here.

This is used to define the units of the image in the axes. By default, i.e. without setting the extent, the units are exactly the pixels of the array. E.g. if you have an image with 10x10 pixels, the extent is (-0.5, 9.5, 9.5, -0.5)

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)

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

fig, ax = plt.subplots()

im = ax.imshow(data)
print(im.get_extent()) # prints (-0.5, 9.5, 9.5, -0.5)

Sample Image

Each pixel is one unit large and integers are the pixel center.

It may however happen that you want to use different units for your image. Possibly you have a calibration made on the data or the data is the result of a calculation where different units are used. In such case the extent can be set to determine where in the 2D space of the axes units the image will reside. E.g. if you want your image to extent from -300 to 300 in x direction and from 50 to 450 in y direction, you may use extent=[-300,300,450,50].

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)

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

fig, ax2 = plt.subplots()

ax2.imshow(data, extent=[-300,300,450,50])

plt.show()

Sample Image

Due to the default equal aspect (aspect="equal") not only the axes coordinates change to range from -300 to 300 and 50 to 450 now, but also the shape of the image has now become non-quadratic, i.e. has an aspect of (450-50)/(300+300)=0.666.

There is a tutorial on origin and extent available, which explains this as well and in addition clarifies how the direction of axes with respect to the image data is determined and manipulated.

Imshow aspect doesn’t work well

You also need to account for the difference in resolution along both axis. For your y-axis you have 640 data points for 6 micrometers and for the x-axis 1024 data points for 35 micrometers. Matplotlib assumes both to be equal.

data = np.random.rand(640,1024)

fig, axs = plt.subplots(2,1, figsize=(10, 4))

aspect = 6 / 35

axs[0].set_title('aspect: %1.2f' % aspect)
axs[0].imshow(data, aspect=aspect, interpolation='none')

aspect = (6/35.) * (1024 / 640)

axs[1].set_title('aspect: %1.2f' % aspect)
axs[1].imshow(data, aspect=aspect, interpolation='none')

Sample Image

Pyplot imshow not showing square pixels when setting aspect ratio

If you use ax.imshow(data) you will automatically get square pixels. If instead you set the aspect to something other than 1/ "equal", then you will not get square pixels. This is however independent of the effect observed in the question.

The problem in the "zoomed image" is that the size of the data pixels is of the order of actual screen pixels. Hence the size of an image pixels might vary by as much as a screen pixel. The solution to this is to save on a figure such that one image pixels is exactly one screen pixel, or any multiple of that.

In this case this would be as simple as

data = np.random.random_sample((2182, 112))
plt.imsave("filename.png", data)

Is it possible to change the width of an imshow matplotlib visualization?

The default behavior of imshow is to set the aspect ratio of the host axes to be 'equal' (that is squares in data-units are squares in screen space). If you do not care about this, just set the aspect to 'auto'.

import matplotlib.pyplot as plt
import numpy as np

N = 100
width = 20
height = 20
Z = np.random.random((width, height))

G = np.zeros((width, height, 3))

# Here we set the RGB for each pixel
G[Z > 0.5] = [1, 1, 1]
G[Z < 0.5] = [0, 0, 0]

fig, ax = plt.subplots(figsize=(2, 5))
ax.imshow(G, interpolation='nearest')
ax.set_aspect('auto')
plt.show()

imshow when you are plotting data, not images. Realtion between aspect and extent?

I'm guessing that you're wanting "square" pixels in the final plot?

For example, if we plot random data similar to yours:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.random((30, 1295))

fig, ax = plt.subplots()
ax.imshow(data, extent=[-130,130,0,77])
plt.show()

We'll get an image with "stretched" pixels:

Sample Image

So, first off, "aspect" in matplotlib refers to the aspect in data coordinates. This means we have to jump through a couple of hoops to get what you want.

import numpy as np
import matplotlib.pyplot as plt

def main():
shape = (30, 1295)
extent = [-130,130,0,77]

data = np.random.random(shape)

fig, ax = plt.subplots()
ax.imshow(data, extent=extent, aspect=calculate_aspect(shape, extent))
plt.show()

def calculate_aspect(shape, extent):
dx = (extent[1] - extent[0]) / float(shape[1])
dy = (extent[3] - extent[2]) / float(shape[0])
return dx / dy

main()


Related Topics



Leave a reply



Submit