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()
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)
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()
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')
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:
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
Capture Arbitrary Path in Flask Route
How to Check If Directory Exists in Python
Can't Subtract Offset-Naive and Offset-Aware Datetimes
Extract Elements of List at Odd Positions
Use Python's String.Replace VS Re.Sub
Remove Non-Numeric Rows in One Column with Pandas
How to Write a File or Data to an S3 Object Using Boto3
Numpy: Find First Index of Value Fast
List of Dicts To/From Dict of Lists
Running a Process in Pythonw with Popen Without a Console
Wrapping a C Library in Python: C, Cython or Ctypes
How to Check If a Value Exists in a Dictionary