更改matplotlib中子图的纵横比

Pet*_*fin 7 python matplotlib

我已经创建了一系列简单的灰度图像,我已经在网格中绘制(遗憾的是,由于我没有足够高的声誉,所以无法上传图像:().

伪代码是

# 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()        
Run Code Online (Sandbox Code Playgroud)

我想改变纵横比,以便绘图垂直压扁并水平拉伸.我尝试过使用ax.set_aspect并将'aspect'作为subplot_kw参数传递,但无济于事.我也关闭了'autoscale',但我只能看到一些像素.欢迎所有建议!

提前致谢!!

@JoeKington - 谢谢!那是一个很棒的回复!! 仍然试图让我全神贯注.还要感谢其他海报的建议.因此,原始情节看起来像这样:http://imgur.com/Wi6v4cs 当我设置'aspect ='auto'时,情节看起来像这样:http://imgur.com/eRBO6MZ 这是一个很大的改进.我现在需要做的就是调整子图大小,以便以2:1的纵向纵横比绘制子图,但是图中填充整个子图.我想'colspan'会这样做吗?

Joe*_*ton 47

简答

你可能想打电话:

ax.imshow(..., aspect='auto')
Run Code Online (Sandbox Code Playgroud)

imshow默认情况下,在调用轴时,会将轴的纵横比设置为1.这将覆盖您在创建轴时指定的任何方面.

但是,这是matplotlib中常见的混淆源.让我备份并详细解释正在发生的事情.


Matplotlib的布局模型


aspect在matplotlib中,是指数据坐标中xscale和yscale的比率.它不直接控制轴的宽度和高度的比率.

有三件事可以控制matplotlib轴的"外框"的大小和形状:

  1. 图的大小/形状(下图中以红色显示)
  2. 图坐标中指定的Axes范围(例如子图位置,如下图中的绿色所示)
  3. Axes用于适应固定宽高比(adjustable参数)的机制.

换句话说,轴总是放在图形坐标中,它们的形状/大小始终是图形的形状/大小的比例.(注意:有些事情axes_grid会在抽奖时改变这一点以解决这个限制.)

但是,给定轴的范围(从其子图位置或显式设置范围)不一定是它将占用的大小.根据aspectadjustable参数,轴将在给定范围内收缩.


为了理解一切如何相互作用,让我们在很多不同的情况下绘制一个圆圈.

没有固定方面

在基本情况下(没有为轴设置固定的纵横比),轴将填充图形坐标中分配给它的整个空间(由绿色框显示).

x和y比例(由设定aspect)可以自由改变,扭曲圆圈:

在此输入图像描述

当我们调整图形的大小(交互式或图形创建)时,轴将"挤压"它:

在此输入图像描述


固定纵横比, 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)
Run Code Online (Sandbox Code Playgroud)

默认情况下,adjustable将是"box".让我们看看发生了什么:

在此输入图像描述

轴可以占用的最大空间由绿色框显示.但是,它必须保持相同的x和y标度.有两种方法可以实现:更改x和y限制或更改Axes边界框的形状/大小.由于adjustableAxes 的参数设置为默认值"box",因此Axes在其最大空间内缩小.

当我们调整图形的大小时,它将继续缩小,但是通过使轴消耗分配给轴的最大空间(绿色框)来保持x和y比例:

在此输入图像描述

两个快速侧面说明:

  1. 如果您正在使用共享轴,并希望拥有adjustable="box",请adjustable="box-forced"改用.
  2. 如果您想控制轴在"绿色框"内的位置,请设置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'),则不会覆盖绘图的宽高比,并且图像将"挤压"以占用分配给轴的完整空间:

在此输入图像描述

另一方面,如果你想让像素保持"方形"(注意:它们可能不是正方形,具体取决于extentkwarg 指定的内容),你可以省略aspect='auto'并设置轴的可调参数"datalim".

例如

ax.imshow(data, cmap='gist_earth', interpolation='none')
ax.set(adjustable="datalim")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

轴形状由图形控制

要记住的最后一部分是轴的形状/尺寸定义为图形的形状/尺寸的百分比.

因此,如果要保留轴的纵横比并在相邻子图之间具有固定的间距,则需要定义要匹配的图形的形状. plt.figaspect对此非常方便.它只是width, height根据指定的宽高比或2D数组生成一个元组(它将采用数组形状的宽高比,而不是内容).

对于子图的网格示例,每个子图具有恒定的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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 我花了很多时间寻找最后一个例子,一张赞成票不足以感谢您最终向我展示了光明。很好的解释! (4认同)