gpt4 book ai didi

python - 更改 matplotlib 中子图的纵横比

转载 作者:行者123 更新时间:2023-12-04 08:56:56 26 4
gpt4 key购买 nike

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

伪代码是

# 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 的布局模型
aspect在 matplotlib 中是指数据坐标中 xscale 和 yscale 的比例。它不直接控制轴的宽度和高度的比率。
有三件事可以控制 matplotlib 轴的“外框”的大小和形状:
  • 图形的大小/形状( 以红色显示 下图中)
  • 图坐标中轴的指定范围(例如子图位置, 以绿色显示 在下图中)
  • Axes 用于适应固定纵横比的机制(adjustable 参数)。

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

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

    固定纵横比, 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" .让我们看看会发生什么:
    enter image description here
    轴可以占用的最大空间由绿色框显示。但是,它必须保持相同的 x 和 y 比例。有两种方法可以实现这一点:更改 x 和 y 限制或更改 Axes 边界框的形状/大小。因为 adjustable Axes 的参数设置为默认值 "box" ,Axes 在其最大空间内收缩。
    当我们调整图形大小时,它会继续缩小,但通过使轴使用较少的分配给轴的最大空间(绿色框)来保持 x 和 y 比例:
    enter image description here
    两个快速旁注:
  • 如果您使用共享轴,并希望拥有 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 限制:
    enter image description here
    当我们调整图形大小时,纵横比表示相同,但​​数据限制发生变化(在这种情况下,不遵守 x 限制)。
    enter image description here

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

    这与 imshow有什么关系? ?

    imshow被调用,它调用 ax.set_aspect(1.0) ,默认。因为 adjustable="box"默认情况下,任何带有 imshow 的绘图将表现得像上面的第 3/4 张图片。
    例如:
    enter image description here
    但是,如果我们指定 imshow(..., aspect='auto') ,绘图的纵横比不会被覆盖,图像将“挤压”以占据分配给轴的全部空间:
    enter image description here
    另一方面,如果您希望像素保持“正方形”(注意:根据 extent kwarg 指定的内容,它们可能不是正方形),您可以省略 aspect='auto'并将轴的可调参数设置为 "datalim"相反。
    例如
    ax.imshow(data, cmap='gist_earth', interpolation='none')
    ax.set(adjustable="datalim")
    enter image description here
    轴形状由图形形状控制
    最后要记住的部分是轴形状/大小定义为图形形状/大小的百分比。
    因此,如果要保留轴的纵横比并在相邻子图之间具有固定间距,则需要定义图形的形状以匹配。 plt.figaspect对此非常方便。它只是生成一个元组 width, height基于指定的纵横比或二维数组(它将从数组的形状中获取纵横比,而不是内容)。
    对于您的子图网格示例,每个子图具有恒定的 2x1 纵横比,您可能会考虑以下内容(请注意,我没有在这里使用 aspect="auto",因为我们希望图像中的像素保持方形):
    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()
    enter image description here

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

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com