我创建了一系列简单的灰度图像,并将它们绘制在网格中(不幸的是,无法上传图像,因为我的声誉不够高:()。
伪代码是
# Define matplotlib PyPlot object
nrow = 8
ncol = 12
fig, axes = plt.subplots(nrow, ncol, subplot_kw={'xticks': [], 'yticks': []})
fig.subplots_adjust(hspace=0.05, wspace=0.05)
# Sample the fine scale model at random well locations
for ax in axes.flat:
plot_data = # some Python code here to create 2D grey scale array...
# ... create sub-plot
img = ax.imshow(plot_data, interpolation='none')
img.set_cmap('gray')
# Display the plot
plt.show()
我想更改纵横比,以便将图垂直压缩并水平拉伸(stretch)。我曾尝试使用 ax.set_aspect 并将“aspect”作为 subplot_kw 参数传递,但无济于事。我也关闭了“自动缩放”,但我只能看到少数像素。欢迎所有建议!
提前致谢!!
@JoeKington - 谢谢!这是一个很棒的回复!!仍然试图让我的头脑围绕这一切。也感谢其他海报的建议。所以,原来的情节是这样的:http://imgur.com/Wi6v4cs
当我设置'aspect='auto'' 时,情节如下所示:http://imgur.com/eRBO6MZ
这是一个很大的改进。我现在需要做的就是调整子图的大小,以便以例如 2:1 的纵向纵横比绘制子图,但该图填充整个子图。我猜'colspan'会这样做吗?
最佳答案
简短的回答
您可能想致电:
ax.imshow(..., aspect='auto')
默认情况下,imshow
将在调用时将轴的纵横比设置为 1。这将覆盖您在创建轴时指定的任何方面。然而,这是 matplotlib 中常见的混淆来源。让我备份并详细解释发生了什么。
Matplotlib 的布局模型
matplotlib中的
aspect
是指数据坐标中xscale和yscale的比例。它不直接控制轴的宽度和高度的比率。有三件事可以控制 matplotlib 轴的“外框”的大小和形状:
adjustable
参数)。 轴总是放置在图形坐标中,换句话说,它们的形状/大小始终是图形形状/大小的比率。 (注意:诸如
axes_grid
之类的某些内容会在绘制时更改此设置以绕过此限制。)但是,给定轴的范围(从其子图位置或明确设置的范围)不一定是它将占用的大小。根据
aspect
和 adjustable
参数,轴将在其给定范围内缩小。要了解一切如何相互作用,让我们在许多不同的情况下绘制一个圆圈。
没有固定的方面
在基本情况下(没有为轴设置固定的纵横比),轴将填满在图形坐标中分配给它的整个空间(由绿色框显示)。
x 和 y 比例(由
aspect
设置)将可以独立更改,从而扭曲圆圈:当我们调整图形大小时(交互地或在图形创建时),轴将随之“挤压”:
固定纵横比,
adjustable='box'
但是,如果设置了绘图的纵横比(默认情况下 imshow
将强制纵横比为 1),轴将调整轴外侧的大小以将 x 和 y 数据比率保持在指定的纵横。不过,这里要理解的一个关键点是,绘图的
aspect
是 x 和 y 数据比例的方面。这不是情节的宽度和高度的方面。因此,如果 aspect
是 1
,则圆将始终是圆。举个例子,假设我们做了这样的事情:
fig, ax = plt.subplots()
# Plot circle, etc, then:
ax.set(xlim=[0, 10], ylim=[0, 20], aspect=1)
默认情况下, adjustable
将是 "box"
。让我们看看发生了什么:轴可以占用的最大空间由绿色框显示。但是,它必须保持相同的 x 和 y 比例。有两种方法可以实现这一点:更改 x 和 y 限制或更改 Axes 边界框的形状/大小。由于 Axes 的
adjustable
参数设置为默认值 "box"
,因此 Axes 在其最大空间内收缩。当我们调整图形大小时,它会继续缩小,但通过使轴使用较少的分配给轴的最大空间(绿色框)来保持 x 和 y 比例:
两个快速旁注:
adjustable="box"
,请改用 adjustable="box-forced"
。 anchor
。例如。 ax.set_anchor('NE')
使其在调整其大小以保持纵横比时保持“固定”到“绿色框”的右上角。 固定方面,
adjustable="datalim"
adjustable
的另一个主要选项是 "datalim"
。在这种情况下,matplotlib 将通过更改轴限制之一来保持数据空间中的 x 和 y 比例。 Axes 将填满分配给它的整个空间。但是,如果您手动设置 x 或 y 限制,它们可能会被覆盖,以允许轴既填满分配给它的全部空间,又将 x/y 比例保持在指定的
aspect
。在这种情况下,x 限制设置为 0-10,y 限制设置为 0-20,其中
aspect=1, adjustable='datalim'
。请注意,不遵守 y 限制:当我们调整图形大小时,纵横比表示相同,但数据限制发生变化(在这种情况下,不遵守 x 限制)。
附带说明一下,生成上述所有数字的代码位于:https://gist.github.com/joferkington/4fe0d9164b5e4fe1e247
这与
imshow
有什么关系?当
imshow
被调用时,它默认调用 ax.set_aspect(1.0)
。由于默认为 adjustable="box"
,任何带有 imshow
的图都将表现得像上面的第 3/4 张图像。例如:
但是,如果我们指定
imshow(..., aspect='auto')
,则不会覆盖绘图的纵横比,并且图像将“挤压”以占用分配给轴的全部空间:另一方面,如果您希望像素保持“正方形”(注意:根据
extent
kwarg 指定的内容,它们可能不是正方形),您可以省略 aspect='auto'
并将轴的可调参数设置为 0x25181314211 .例如。
ax.imshow(data, cmap='gist_earth', interpolation='none')
ax.set(adjustable="datalim")
轴形状由图形形状控制
要记住的最后一部分是轴形状/大小定义为图形形状/大小的百分比。
因此,如果要保留轴的纵横比并在相邻子图之间具有固定间距,则需要定义图形的形状以匹配。
"datalim"
对此非常方便。它只是根据指定的纵横比或二维数组(它将从数组的形状而不是内容中获取纵横比)生成一个 plt.figaspect
元组。对于您的子图网格示例,每个子图具有恒定的 2x1 纵横比,您可能会考虑以下内容(请注意,我在这里没有使用
width, height
,因为我们希望图像中的像素保持方形):import numpy as np
import matplotlib.pyplot as plt
nrows, ncols = 8, 12
dx, dy = 1, 2
figsize = plt.figaspect(float(dy * nrows) / float(dx * ncols))
fig, axes = plt.subplots(nrows, ncols, figsize=figsize)
for ax in axes.flat:
data = np.random.random((10*dy, 10*dx))
ax.imshow(data, interpolation='none', cmap='gray')
ax.set(xticks=[], yticks=[])
pad = 0.05 # Padding around the edge of the figure
xpad, ypad = dx * pad, dy * pad
fig.subplots_adjust(left=xpad, right=1-xpad, top=1-ypad, bottom=ypad)
plt.show()
关于python - 更改 matplotlib 中子图的纵横比,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32633322/