让子图填满整个图形

10 投票
3 回答
31840 浏览
提问于 2025-04-18 11:53

我想请教一下,如何改变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 个回答

0

一个朋友想出了一个看起来效果不错的解决办法,我觉得可以分享给有类似问题的人。设置 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()
15

你可以通过使用 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],每个方向的大小都是根据页面的尺寸来缩放的。

正如其他回答中提到的,imshowmatshow 有时会尝试保持图片中的像素是正方形的。这和坐标比例以及 imshow 之间有一些特别的关系。

  • 如果调用 imshow 时没有提供 extent=[...]aspect='auto' 这些参数,它会按照本地默认设置来处理,通常会尝试保持像素为正方形。
  • 如果发生这种情况(或者设置了 aspect='equal'),坐标轴的表现就像调用了 plt.axis('scaled'),也就是说,X和Y坐标的长度会保持一致(每单位的像素数相同),并且会调整坐标轴的大小以匹配范围。
  • 你可以通过设置 plt.axis('tight') 来覆盖这个设置(这样会让x和y的范围刚好适应图片)。

以前的一个小技巧是使用 axis('auto')axis('normal'),但现在这些已经不推荐使用了(应该用 scaledequaltight)。

是的,这确实有点复杂。

7

首先,你在使用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)

在我的系统上,效果是这样的:

enter image description here

撰写回答