Matplotlib:强制设置系列图的纵横比
我有一系列图片,这些图片代表了物理空间中的区域,也就是说,它们是物体的图像。这些图片的像素数量不一样,但在每种情况下,所有图片在y轴上的分辨率都是相同的,x轴的长度也是一样的(具体来说:y轴的像素总是150微米,而x轴的图片宽度总是11毫米)。
我想生成一系列图表,这些图表的大小能够准确反映物体之间的空间大小关系。也就是说,行数更多的图片在y轴上空间上更大,但无论在x轴上有多少像素,每张图片的大小都是一样的(因为x轴的分辨率是不固定的)。
为了做到这一点,我的脚本会计算出每张图片在空间单位上的x和y尺寸(比如,11毫米 x 4.2毫米或11毫米 x 4.5毫米),然后在plt.imshow
中使用aspect
设置强制保持y轴大小与x轴大小的比例。
但不知为何,这个方法并没有奏效。而且,设置图形大小也没有效果。以下是我的代码和图片:



for f in mats: # 分离文件名和扩展名 name, ext = os.path.splitext(f)
# Get the age of the sample lens
age = int(name.split('_', 1)[0])
bshiftm = io.loadmat(f)['bshiftm'] # Un-interpolated image
bshiftm2 = io.loadmat(f)['bshiftm2'] # Interpolated image
# Load the data about the physical dimensions of images
xscan = int(io.loadmat(f)['xscan']) # in mm
zscan = int(io.loadmat(f)['zscan']) # in mm
zframes = int(io.loadmat(f)['zframes'])
# Determine resolution data so we can scale plot axes
xres = float(xscan)/bshiftm.shape[1] # x dim. is the number of columns
zres = float(zscan)/zframes # In mm/pixel
# All images have same x dimensions, but z dimensions are all different,
# meaning we have to figure them out based on the resolution of the image
# in the z direction and the number of rows in the raw image
xsize = xscan # In mm
zsize = zres*bshiftm.shape[0] # In mm
# Using the physical dimensions of the image, find the resolutions of the
# interpolated images so we can scale the plot axes
xresi = float(xsize)/bshiftm2.shape[1]
zresi = float(zsize)/bshiftm2.shape[0]
# Aspect ratio of image
ar = float(zsize)/xsize
# Start plotting
fig = plt.figure()
# Locations and labels for x tics
xlocs = np.arange(0, bshiftm.shape[1], bshiftm.shape[1]/5)
xlabs = map(str, np.round(xlocs*xres, 1))
plt.xticks(xlocs, xlabs)
plt.xlabel('x (mm)').set_weight('bold')
# Locations and labels for z tics
zlocs = np.arange(0, bshiftm.shape[0], bshiftm.shape[0]/2)
zlabs = map(str, np.round(zlocs*zres, 1))
plt.yticks(zlocs, zlabs)
plt.ylabel('z (mm)').set_weight('bold')
# Set the title
#plt.title(str(age) + ' year old lens, XZ').set_weight('bold')
# Plot the uninterpolated data
plt.imshow(bshiftm,
cmap='spectral',
aspect=ar,
vmin=8,
vmax=9.6,
origin='upper',
interpolation='none')
# Set up colorbar
cbar = plt.colorbar()
#cbar.set_label('Brillouin Shift (GHz)', rotation=270)
plt.savefig(os.path.join(raw, name))
plt.close()
我觉得这个方法应该是可行的,我已经确认这个脚本能够正确计算每张图片的空间尺寸,以及它们应该有的比例。我还想指出,第三张图片在x方向上有110个像素,而另外两张只有55个。
另外,如果有人有关于如何更稳妥地放置刻度的建议,那就太好了。
1 个回答
4
一种比较可靠的方法是使用 extent
这个关键词来进行图像缩放。
ax.imshow(image, extent=[0, 10.4, 0, 4.2], aspect=1)
这样应该能满足你所有的需求。(当然,你需要把10.4和4.2改成实际的尺寸)。需要注意的是,在这种情况下, aspect=1
并不一定会让像素变成正方形,而是让两个轴的单位保持相同的比例,这似乎正是你想要的效果。
这里有一个小例子:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(np.random.random((20, 20)), extent=(0, 10.5, 2, 4.7), aspect=1, interpolation='nearest')
这样会得到: