具有不同y轴的子图中的纵横比

时间:2013-02-16 04:47:02

标签: python matplotlib

我希望以下代码生成4个相同大小的子图,其中我设置的x轴和y轴的大小之间具有相同的纵横比。参考下面的例子,我希望所有的子图看起来都像第一个(左上角)。现在的错误是y轴的大小与其最大值相关。这是我想避免的行为。

import matplotlib.pyplot as plt
import numpy as np

def main(): 

    fig = plt.figure(1, [5.5, 3])
    for i in range(1,5):
        fig.add_subplot(221+i-1, adjustable='box', aspect=1) 
        plt.plot(np.arange(0,(i)*4,i))

    plt.show()

if __name__ == "__main__": 
    main()

令人惊讶的是,matplotlib默认生成正确的东西(下图):

   import  matplotlib.pyplot as plt 
   import numpy as np 

   def main(): 
       fig = plt.figure(1, [5.5, 3]) 
       for i in range(1,5): 
           fig.add_subplot(221+i-1) 
            plt.plot(np.arange(0,(i)*4,i)) 
       plt.show() 

我只想添加一个控制x轴和y轴长度比的功能。

Here is what I am looking for:

3 个答案:

答案 0 :(得分:9)

我无法从你的问题中说出你想要的东西。

您是否希望所有图表都具有相同的数据限制?

如果是这样,请使用共享轴(我在这里使用subplots,但如果你想坚持使用matlab风格的代码,你可以避免使用它):

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=2, ncols=2, sharey=True, sharex=True)
for i, ax in enumerate(axes.flat, start=1):
    ax.set(aspect=1)
    ax.plot(np.arange(0, i * 4, i))

plt.show()

enter image description here

如果您希望所有人共享他们的轴限制,但要拥有adjustable='box'(即非方轴边界),请使用adjustable='box-forced'

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=2, ncols=2, sharey=True, sharex=True)
for i, ax in enumerate(axes.flat, start=1):
    ax.set(aspect=1, adjustable='box-forced', xticks=range(i))
    ax.plot(np.arange(0, i * 4, i))

plt.show()

enter image description here


编辑:对不起,我还是有点困惑。你想要这样的东西吗?

import matplotlib.pyplot as plt 
import numpy as np 

fig, axes = plt.subplots(nrows=2, ncols=2)
for i, ax in enumerate(axes.flat, start=1):
    ax.set(adjustable='datalim', aspect=1)
    ax.plot(np.arange(0, i * 4, i))

plt.show()

enter image description here


好的,我想我终于理解了你的问题。我们都用“纵横比”来表示完全不同的东西。

在matplotlib中,图的纵横比是指数据限制的相对比例。换句话说,如果绘图的纵横比为1,则斜率为1的直线将出现在45度。您假设纵横比应用于轴的轮廓而不是轴上绘制的数据。

您只希望子图的轮廓为方形。 (在这种情况下,它们都有不同的宽高比,由matplotlib定义。)

在这种情况下,你需要一个方形图。 (还有其他方法,但只是制作一个正方形图形要简单得多.Matplotlib轴填充的空间与它们所在的图形大小成正比。)

import matplotlib.pyplot as plt 
import numpy as np 

# The key here is the figsize (it needs to be square). The position and size of
# axes in matplotlib are defined relative to the size of the figure.
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8,8))

for i, ax in enumerate(axes.flat, start=1):
    ax.plot(np.arange(0, i * 4, i))

# By default, subplots leave a bit of room for tick labels on the left.
# We'll remove it so that the axes are perfectly square.
fig.subplots_adjust(left=0.1)

plt.show()

enter image description here

答案 1 :(得分:2)

Joe Kington的答案与new pythonic style for shared axes square subplots in matplotlib?结合起来 另一篇文章,我恐怕再也找不到了,我制作了一个代码,用于精确设置框的比例为给定值。

让desired_box_ratioN指示框的y和x边之间的所需比率。 temp_inverse_axis_ratioN是当前图的x和y边之间的比率;因为'方面'是y和x比例(而不是轴)之间的比率,我们需要将aspect设置为desired_box_ratioN * temp_inverse_axis_ratioN。

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=2, ncols=2)

desired_box_ratioN = 1
for i, ax in enumerate(axes.flat, start=1):
    ax.plot(np.arange(0, i * 4, i))
    temp_inverse_axis_ratioN = abs( (ax.get_xlim()[1] - ax.get_xlim()[0])/(ax.get_ylim()[1] - ax.get_ylim()[0]) )
    ax.set(aspect = desired_box_ratioN * temp_inverse_axis_ratioN, adjustable='box-forced')

plt.show()

答案 2 :(得分:1)

理论

matplotlib中的

Different coordinate systems exists。不同坐标系之间的差异确实会让很多人感到困惑。 OP想要的是显示坐标中的宽高比,但ax.set_aspect()是在数据坐标中设置宽高比。他们的关系可以表述为:

aspect = 1.0/dataRatio*dispRatio

其中,aspectset_aspect方法中使用的参数,dataRatio是数据坐标中的宽高比,dispRatio您想要的宽高比在显示坐标中。

练习

我们可以使用get_data_ratio方法使代码更简洁。工作代码段如下所示:

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=2, ncols=2)

dispRatio = 0.5
for i, ax in enumerate(axes.flat, start=1):
    ax.plot(np.arange(0, i * 4, i))
    ax.set(aspect=1.0/ax.get_data_ratio()*dispRatio, adjustable='box-forced')

plt.show()

我还写了一篇关于所有这些内容的详细帖子here