我创建了一系列简单的灰度图像,并将它们绘制在网格中(不幸的是,无法上传图像,因为我的声誉不够高:()。

伪代码是

# 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 轴的“外框”的大小和形状:
  • 图形的大小/形状( 在下图中以红色显示 )
  • 图形坐标中轴的指定范围(例如,子图位置, 在下图中显示为绿色 ) 0x29191224123411
  • 轴用于适应固定纵横比的机制(adjustable 参数)。

  • 轴总是放置在图形坐标中,换句话说,它们的形状/大小始终是图形形状/大小的比率。 (注意:诸如 axes_grid 之类的某些内容会在绘制时更改此设置以绕过此限制。)
    但是,给定轴的范围(从其子图位置或明确设置的范围)不一定是它将占用的大小。根据 aspectadjustable 参数,轴将在其给定范围内缩小。

    要了解一切如何相互作用,让我们在许多不同的情况下绘制一个圆圈。
    没有固定的方面
    在基本情况下(没有为轴设置固定的纵横比),轴将填满在图形坐标中分配给它的整个空间(由绿色框显示)。
    x 和 y 比例(由 aspect 设置)将可以独立更改,从而扭曲圆圈:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    当我们调整图形大小时(交互地或在图形创建时),轴将随之“挤压”:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP

    固定纵横比,adjustable='box'但是,如果设置了绘图的纵横比(默认情况下 imshow 将强制纵横比为 1),轴将调整轴外侧的大小以将 x 和 y 数据比率保持在指定的纵横。
    不过,这里要理解的一个关键点是,绘图的 aspect 是 x 和 y 数据比例的方面。这不是情节的宽度和高度的方面。因此,如果 aspect1 ,则圆将始终是圆。
    举个例子,假设我们做了这样的事情:
    fig, ax = plt.subplots()
    # Plot circle, etc, then:
    ax.set(xlim=[0, 10], ylim=[0, 20], aspect=1)
    
    默认情况下, adjustable 将是 "box" 。让我们看看发生了什么:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    轴可以占用的最大空间由绿色框显示。但是,它必须保持相同的 x 和 y 比例。有两种方法可以实现这一点:更改 x 和 y 限制或更改 Axes 边界框的形状/大小。由于 Axes 的 adjustable 参数设置为默认值 "box" ,因此 Axes 在其最大空间内收缩。
    当我们调整图形大小时,它会继续缩小,但通过使轴使用较少的分配给轴的最大空间(绿色框)来保持 x 和 y 比例:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    两个快速旁注:
  • 如果您使用共享轴,并且想要 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 限制:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    当我们调整图形大小时,纵横比表示相同,但​​数据限制发生变化(在这种情况下,不遵守 x 限制)。
    python - 更改 matplotlib 中子图的纵横比-LMLPHP

    附带说明一下,生成上述所有数字的代码位于:https://gist.github.com/joferkington/4fe0d9164b5e4fe1e247

    这与 imshow 有什么关系?

    imshow 被调用时,它默认调用 ax.set_aspect(1.0) 。由于默认为 adjustable="box",任何带有 imshow 的图都将表现得像上面的第 3/4 张图像。
    例如:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    但是,如果我们指定 imshow(..., aspect='auto') ,则不会覆盖绘图的纵横比,并且图像将“挤压”以占用分配给轴的全部空间:
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    另一方面,如果您希望像素保持“正方形”(注意:根据 extent kwarg 指定的内容,它们可能不是正方形),您可以省略 aspect='auto' 并将轴的可调参数设置为 0x25181314211 .
    例如。
    ax.imshow(data, cmap='gist_earth', interpolation='none')
    ax.set(adjustable="datalim")
    
    python - 更改 matplotlib 中子图的纵横比-LMLPHP
    轴形状由图形形状控制
    要记住的最后一部分是轴形状/大小定义为图形形状/大小的百分比。
    因此,如果要保留轴的纵横比并在相邻子图之间具有固定间距,则需要定义图形的形状以匹配。 "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 中子图的纵横比-LMLPHP

    关于python - 更改 matplotlib 中子图的纵横比,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32633322/

    10-12 18:19