让子图填满整个图形
我想请教一下,如何改变matplotlib默认的行为,特别是在绘制图像作为子图时,子图的大小似乎和整个图的大小不匹配。我希望能设置我的图的大小(比如说,和A4纸的宽度一致),然后让子图自动拉伸,填满可用的空间。在下面这个例子中,代码生成的图中,面板之间有很多空白区域:
import numpy as np
import matplotlib.pyplot as plt
data=np.random.rand(10,4)
#creating a wide figure with 2 subplots in 1 row
fig,ax=plt.subplots(1,2, figsize=(9,3))
ax=ax.reshape(1,len(ax))
for i in [0,1]:
plt.sca(ax[0,i])
plt.imshow(data,interpolation='nearest')
plt.colorbar()
我希望子图能够横向拉伸,填满整个图的空间。我会制作很多类似的图,每个轴上的数值数量不同,而图之间的空隙似乎又和x轴值与y轴值的比例有关。所以我想知道有没有什么好的通用方法,可以设置子图的宽度来填满空间。有没有办法指定子图的实际大小?我已经搜索了几个小时的解决方案,非常感谢你们能提供的任何帮助。
3 个回答
一个朋友想出了一个看起来效果不错的解决办法,我觉得可以分享给有类似问题的人。设置 imshow 的 aspect='auto' 似乎可以解决这个问题,无论你选择 nx、figsize、nplots_hori 和 nplots_vert 的值是什么,下面的代码都能正常工作。
import numpy as np
import matplotlib.pyplot as plt
nx=5
data=np.random.rand(10,nx)
figsize=[10,8]
nplots_hori=2
nplots_vert=2
fig,ax=plt.subplots(nplots_vert, nplots_hori, figsize=figsize)
if nplots_vert==1: ax=ax.reshape(1,len(ax))
plt.tight_layout()
for i in range(nplots_hori):
for j in range(nplots_vert):
plt.sca(ax[j,i])
plt.imshow(data, aspect='auto')
plt.tight_layout()
plt.show()
你可以通过使用 ax.set_position
方法来调整你的坐标区域。这个方法是用相对坐标来工作的,所以如果你想制作一个A4大小的图片,可以这样做:
import numpy as np
import matplotlib.pyplot as plt
# figsize keyword talks some obscure units which need a conversion from standard units
plt.figure(figsize=np.array([210,297]) / 25.4)
x = np.linspace(0,2*np.pi, 100)
plt.plot(x, np.sin(x))
plt.gca().set_position([0, 0, 1, 1])
plt.show()
现在坐标区域(绘图区域)就填满了整个页面。
传给 set_position
的坐标是相对坐标,格式是[left, lower, width, height],每个方向的大小都是根据页面的尺寸来缩放的。
正如其他回答中提到的,imshow
和 matshow
有时会尝试保持图片中的像素是正方形的。这和坐标比例以及 imshow
之间有一些特别的关系。
- 如果调用
imshow
时没有提供extent=[...]
或aspect='auto'
这些参数,它会按照本地默认设置来处理,通常会尝试保持像素为正方形。 - 如果发生这种情况(或者设置了
aspect='equal'
),坐标轴的表现就像调用了plt.axis('scaled')
,也就是说,X和Y坐标的长度会保持一致(每单位的像素数相同),并且会调整坐标轴的大小以匹配范围。 - 你可以通过设置
plt.axis('tight')
来覆盖这个设置(这样会让x和y的范围刚好适应图片)。
以前的一个小技巧是使用 axis('auto')
或 axis('normal')
,但现在这些已经不推荐使用了(应该用 scaled
、equal
或 tight
)。
是的,这确实有点复杂。
首先,你在使用plt
的时候,其实手上已经有了Axes
对象,这样做会让你很麻烦。其次,imshow
会把坐标轴的比例设置为1,这就是为什么你的坐标轴看起来那么窄。了解这些之后,你的例子就变成了:
import numpy as np
import matplotlib.pyplot as plt
data = np.random.rand(10,4)
#creating a wide figure with 2 subplots in 1 row
fig, axes = plt.subplots(1, 2, figsize=(9,3))
for ax in axes.flatten(): # flatten in case you have a second row at some point
img = ax.imshow(data, interpolation='nearest')
ax.set_aspect('auto')
plt.colorbar(img)
在我的系统上,效果是这样的:
