【问题标题】:Aspect ratio in subplots with various y-axes具有各种 y 轴的子图中的纵横比
【发布时间】:2013-02-16 04:47:01
【问题描述】:

我希望下面的代码能够生成 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 轴长度之间的纵横比。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    我不能完全说出你想从你的问题中得到什么。

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

    如果是这样,请使用共享轴(我在这里使用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()
    

    如果您希望他们都共享他们的坐标轴限制,但要拥有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()
    


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

    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()
    


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

    在 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()
    

    【讨论】:

    • 嗨乔!感谢您对我的问题的关注。我很抱歉造成混乱。您的 2 个选项都没有提供我正在寻找的内容。第一个选项是最接近的。如果每个子图都有自己的 y 轴限制,那将是完美的。这就是 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()
    • 我在原始问题中添加了这段代码生成的图片
    • 嗨乔,快到了!这是完美的,除了我希望所有 suplots 的 x 轴限制都在 0 到 3 之间。我在原始问题中包含的那张图片是我想要的一切,但轴之间的纵横比错误。所以现在它类似于 1/2,但我正在寻找 1/1。
    • 对不起,我还是很困惑...如果轴的限制或大小都没有改变,纵横比就不能保持不变。您似乎要求的是尺寸完全相同、纵横比相同、x 轴限制相同但 y 轴限制不同的图。根据定义,这是不可能的。我想我只是误解了你的问题......
    【解决方案2】:

    理论

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

    aspect = 1.0/dataRatio*dispRatio
    

    其中,aspect 是在 set_aspect 方法中使用的参数,dataRatio 是数据坐标中的纵横比,dispRatio您想要的纵横比在显示坐标中。

    实践

    有一个get_data_ratio 方法可以用来使我们的代码更简洁。工作代码sn-p如下图:

    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

    【讨论】:

    • 我已经尝试按照您的教程进行操作,这很清楚,但是,当 y 轴有对数刻度时,它不起作用,关于在保持 y 轴的同时加宽 x 轴的任何想法在对数尺度上?
    • 抱歉,我不确定。也许您可以根据该帖子在 Stack Overflow 上提出一个新问题。
    【解决方案3】:

    Joe Kington的答案与new pythonic style for shared axes square subplots in matplotlib?结合起来 还有一篇恐怕再也找不到的帖子,我做了一个代码,用于精确设置框与给定值的比率。

    让desired_box_ratioN 表示框的y 和x 边之间的期望比率。 temp_inverse_axis_ratioN 是当前绘图的 x 和 y 边之间的比率;因为'aspect'是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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-31
      • 1970-01-01
      • 2014-01-09
      • 1970-01-01
      • 2018-12-04
      • 2018-08-21
      • 2015-11-20
      • 2013-06-12
      相关资源
      最近更新 更多