Matplotlib:获取子图以填充图形
Posted
技术标签:
【中文标题】Matplotlib:获取子图以填充图形【英文标题】:Matplotlib: Getting subplots to fill figure 【发布时间】:2014-08-23 11:55:12 【问题描述】:我希望获得有关在将图像绘制为子图时如何覆盖默认 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 值的比率,所以我想知道是否有一个好的通用方法来设置填充空间的子图宽度。可以以某种方式指定子图的物理大小吗?几个小时以来我一直在寻找解决方案,因此提前感谢您提供的任何帮助。
【问题讨论】:
【参考方案1】:您可以使用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
的坐标是相对坐标[左、下、宽、高],其中每个方向都按页面大小缩放。
正如其他答案中指出的那样,imshow
和 matshow
有时会尝试将像素保持在图片正方形中。轴比和imshow
之间存在相当特殊的相互作用。
extent=[...]
或 aspect='auto'
关键字参数的情况下调用 imshow
,它会按照本地默认设置的指示执行操作,通常会尝试保持像素为正方形
如果发生这种情况(或设置了aspect='equal'
),则轴的行为就像调用了plt.axis('scaled')
,即保持X 和Y 坐标等长(每单位像素)并更改轴大小以匹配范围
这可以通过设置 plt.axis('tight')
来覆盖(这使得 x 和 y 限制完全适合图像)
老技巧是使用axis('auto')
或axis('normal')
,但现在已弃用(使用scaled
、equal
或tight
)。
是的,有点乱。
【讨论】:
非常感谢您的回复。该解决方案在使用 plt.plot() 时似乎有效,但在使用 plt.imshow() 时无效,这是我正在使用的。我用它来绘制二维直方图,图中的每个正方形对应一个 bin,它的颜色对应于它包含的值的数量。您是否知道调整 imshow() 对象大小的方法,或者在您的方法适用的地方呈现 2D 直方图的更好方法? @user3798292,您可以尝试按照此处指定的方式设置 set_position,但随后不要使用 pyplot 命令,而是使用直接对象接口(@987654338@ 而不是plt.imshow(...)
)
@user3798292:您已经向您指出了一些解决方案,但我在此添加了一些 cmets。 imshow
在这个意义上有点奇怪。
plt.gca().set_position([0, 0, 1, 1])
正是我需要使用 .imshow()
和 Cartopy 来获取卫星图像图来填充整个图。对于我的用例,plt.axis('tight')
让它显示了地球的整个投影,这不是我想要的。感谢您提供非常有帮助的答案!
我喜欢使用“晦涩的单位”来指代英寸。也很对。【参考方案2】:
首先,当您有 Axes
对象作为您的处置对象时,您正在使用对 plt
的调用。那条路通向痛苦。其次,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)
在我的系统上,它看起来像这样:
【讨论】:
【参考方案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()
【讨论】:
以上是关于Matplotlib:获取子图以填充图形的主要内容,如果未能解决你的问题,请参考以下文章