【问题标题】:Matplotlib: Getting subplots to fill figureMatplotlib:获取子图以填充图形
【发布时间】:2014-08-23 11:55:12
【问题描述】:

我希望获得有关在将图像绘制为子图时如何覆盖默认 matplotlib 行为的建议,其中子图大小似乎与图形大小不匹配。我想设置我的图形大小(例如,匹配 A4 页面的宽度)并让子图自动拉伸以填充可用空间。在下面的例子中,下面的代码给出了一个面板之间有很多空白的图形:

import numpy as np
import matplotlib.pyplot as plt

data=np.random.rand(10,4)

#creating a wide figure with 2 subplots in 1 row
fig,ax=plt.subplots(1,2, figsize=(9,3))  
ax=ax.reshape(1,len(ax))

for i in [0,1]:
    plt.sca(ax[0,i])
    plt.imshow(data,interpolation='nearest')
    plt.colorbar()

我希望将子图水平拉伸以填充图形空间。我将制作许多沿每个轴具有不同数量值的相似图,并且图之间的空间似乎取决于 x 值与 y 值的比率,所以我想知道是否有一个好的通用方法来设置填充空间的子图宽度。可以以某种方式指定子图的物理大小吗?几个小时以来我一直在寻找解决方案,因此提前感谢您提供的任何帮助。

【问题讨论】:

    标签: python matplotlib subplot


    【解决方案1】:

    您可以使用ax.set_position 方法调整您的轴区域。它适用于相对坐标,所以如果你想制作 A4 图像,那么:

    import numpy as np
    import matplotlib.pyplot as plt
    
    # figsize keyword talks some obscure units which need a conversion from standard units
    plt.figure(figsize=np.array([210,297]) / 25.4)
    
    x = np.linspace(0,2*np.pi, 100)
    plt.plot(x, np.sin(x))
    
    plt.gca().set_position([0, 0, 1, 1])
    
    plt.show()
    

    现在轴区域(绘图区域)填满了整个页面。

    set_position 的坐标是相对坐标[左、下、宽、高],其中每个方向都按页面大小缩放。

    正如其他答案中指出的那样,imshowmatshow 有时会尝试将像素保持在图片正方形中。轴比和imshow 之间存在相当特殊的相互作用。

    • 如果在没有 extent=[...]aspect='auto' 关键字参数的情况下调用 imshow,它会按照本地默认设置的指示执行操作,通常会尝试保持像素为正方形
    • 如果发生这种情况(或设置了aspect='equal'),则轴的行为就像调用了plt.axis('scaled'),即保持X 和Y 坐标等长(每单位像素)并更改轴大小以匹配范围
    • 这可以通过设置 plt.axis('tight') 来覆盖(这使得 x 和 y 限制完全适合图像)

    老技巧是使用axis('auto')axis('normal'),但现在已弃用(使用scaledequaltight)。

    是的,有点乱。

    【讨论】:

    • 非常感谢您的回复。该解决方案在使用 plt.plot() 时似乎有效,但在使用 plt.imshow() 时无效,这是我正在使用的。我用它来绘制二维直方图,图中的每个正方形对应一个 bin,它的颜色对应于它包含的值的数量。您是否知道调整 imshow() 对象大小的方法,或者在您的方法适用的地方呈现 2D 直方图的更好方法?
    • @user3798292,您可以尝试按照此处指定的方式设置 set_position,但随后不要使用 pyplot 命令,而是使用直接对象接口(@98​​7654338@ 而不是 plt.imshow(...)
    • @user3798292:您已经向您指出了一些解决方案,但我在此添加了一些 cmets。 imshow 在这个意义上有点奇怪。
    • plt.gca().set_position([0, 0, 1, 1]) 正是我需要使用 .imshow() 和 Cartopy 来获取卫星图像图来填充整个图。对于我的用例,plt.axis('tight') 让它显示了地球的整个投影,这不是我想要的。感谢您提供非常有帮助的答案!
    • 我喜欢使用“晦涩的单位”来指代英寸。也很对。
    【解决方案2】:

    首先,当您有 Axes 对象作为您的处置对象时,您正在使用对 plt 的调用。那条路通向痛苦。其次,imshow 将坐标轴比例的纵横比设置为 1。这就是坐标轴如此窄的原因。知道了这一切,你的例子就变成了:

    import numpy as np
    import matplotlib.pyplot as plt
    
    data = np.random.rand(10,4)
    
    #creating a wide figure with 2 subplots in 1 row
    fig, axes = plt.subplots(1, 2, figsize=(9,3))  
    
    for ax in axes.flatten():  # flatten in case you have a second row at some point
        img = ax.imshow(data, interpolation='nearest')
        ax.set_aspect('auto')
    
    plt.colorbar(img)
    

    在我的系统上,它看起来像这样:

    【讨论】:

      【解决方案3】:

      一位朋友提出了一个似乎运作良好的解决方案,我想我会为遇到类似问题的任何人发布该解决方案 - 在 imshow 中设置 aspect='auto' 似乎可以解决问题,对于任何 nx 选择, figsize、nplots_hori 和 nplots_vert 下面。

      import numpy as np
      import matplotlib.pyplot as plt
      
      nx=5
      data=np.random.rand(10,nx)
      
      figsize=[10,8]
      nplots_hori=2
      nplots_vert=2
      
      fig,ax=plt.subplots(nplots_vert, nplots_hori, figsize=figsize)
      if nplots_vert==1: ax=ax.reshape(1,len(ax))
      
      plt.tight_layout()
      for i in range(nplots_hori):
          for j in range(nplots_vert):
              plt.sca(ax[j,i])
              plt.imshow(data, aspect='auto')
      
      plt.tight_layout()
      plt.show()
      

      【讨论】:

        猜你喜欢
        • 2018-12-25
        • 2012-08-07
        • 1970-01-01
        • 2015-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-24
        • 2018-05-14
        相关资源
        最近更新 更多