Matplotlib:强制设置系列图的纵横比

0 投票
1 回答
839 浏览
提问于 2025-04-18 13:55

我有一系列图片,这些图片代表了物理空间中的区域,也就是说,它们是物体的图像。这些图片的像素数量不一样,但在每种情况下,所有图片在y轴上的分辨率都是相同的,x轴的长度也是一样的(具体来说:y轴的像素总是150微米,而x轴的图片宽度总是11毫米)。

我想生成一系列图表,这些图表的大小能够准确反映物体之间的空间大小关系。也就是说,行数更多的图片在y轴上空间上更大,但无论在x轴上有多少像素,每张图片的大小都是一样的(因为x轴的分辨率是不固定的)。

为了做到这一点,我的脚本会计算出每张图片在空间单位上的x和y尺寸(比如,11毫米 x 4.2毫米或11毫米 x 4.5毫米),然后在plt.imshow中使用aspect设置强制保持y轴大小与x轴大小的比例。

但不知为何,这个方法并没有奏效。而且,设置图形大小也没有效果。以下是我的代码和图片:

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

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')

这样会得到:

在这里输入图片描述

撰写回答