【问题标题】:Axes class - set explicitly size (width/height) of axes in given units轴类 - 以给定单位明确设置轴的大小(宽度/高度)
【发布时间】:2017-12-11 16:57:39
【问题描述】:

我想使用 matplotlib 创建一个图形,我可以在其中明确指定轴的大小,即我想设置轴 bbox 的宽度和高度。

我环顾四周,找不到解决办法。我通常会发现如何调整完整图形的大小(包括刻度和标签),例如使用fig, ax = plt.subplots(figsize=(w, h))

这对我来说非常重要,因为我希望轴的比例为 1:1,即纸上的 1 个单位等于现实中的 1 个单位。例如,如果 xrange 为 0 到 10,主要刻度 = 1,x 轴为 10cm,则 1 个主要刻度 = 1cm。我将此图保存为 pdf 以将其导入到 Latex 文档中。

This question 提出了类似的话题,但答案并没有解决我的问题(使用plt.gca().set_aspect('equal', adjustable='box') 代码)

从另一个question 我看到可以获取轴大小,但不能明确修改它们。

关于如何设置轴框大小而不仅仅是图形大小的任何想法。图形大小应适应轴大小。

谢谢!

对于那些熟悉乳胶中的pgfplots 的人来说,它希望有类似于scale only axis 选项的东西(例如,参见here)。

【问题讨论】:

    标签: python matplotlib plot axis axes


    【解决方案1】:

    坐标轴大小由图形大小和图形间距决定,可以使用figure.subplots_adjust() 设置。相反,这意味着您可以通过设置图形大小来设置轴大小,同时考虑图形间距:

    import matplotlib.pyplot as plt
    
    def set_size(w,h, ax=None):
        """ w, h: width, height in inches """
        if not ax: ax=plt.gca()
        l = ax.figure.subplotpars.left
        r = ax.figure.subplotpars.right
        t = ax.figure.subplotpars.top
        b = ax.figure.subplotpars.bottom
        figw = float(w)/(r-l)
        figh = float(h)/(t-b)
        ax.figure.set_size_inches(figw, figh)
    
    fig, ax=plt.subplots()
    
    ax.plot([1,3,2])
    
    set_size(5,5)
    
    plt.show()
    

    【讨论】:

    • 非常感谢@ImportanceOfBeingErnest 的帮助!!!这似乎在生成的 pdf 中效果很好(就像魔术一样!)。一个重要的注意事项是set_size 应该在保存图形之前执行,以考虑标签和刻度的所有更改。但是我注意到两个问题:(1)如果图形的尺寸太小,标签会被剪裁;(2)当我打印 pdf 时,尺寸与实际比例不符。这是为什么?请注意,我将乳胶文档中的 pdf 称为带有 \includegraphics 的图形,然后打印生成的 pdf。
    • (1) 这是意料之中的。您可能希望使用fig.subplots_adjust() 设置更大的间距。 (2) 打印是指使用墨水或激光打印机打印到纸上?那可能有完全不同的原因。首先检查pdf本身的大小是否正确。我假设是这种情况,接下来检查乳胶中的尺寸是否正确。这可能是也可能不是。最后,打印的纸张可能有不同的比例,具体取决于打印机设置。
    • 我使用 pdf 测量工具检查了乳胶 pdf 的大小,它是正确的,但在用激光打印机打印后不在纸上。
    • 我明白了。但由于乳胶 pdf 的大小正确,我认为我们无法在 StackOverflow 上为打印问题提供支持。检查您的打印机设置,在其他页面上查找类似问题,可能在 superuser.stackexchange 上或在那里提问。
    • 您可以为颜色条添加一个轴 (add_axes) 并使用subplots_adjust为其腾出一些空间。
    【解决方案2】:

    Matplotlib 似乎有帮助类,允许您定义固定大小的轴Demo fixed size axes

    【讨论】:

      【解决方案3】:

      我发现 ImportanceofBeingErnests 的答案修改了图形大小以调整轴大小,这与我用来生成可发布图的特定 matplotlib 设置提供了不一致的结果。最终的图形大小出现了轻微的错误,我无法用他的方法找到解决问题的方法。对于大多数用例,我认为这不是问题,但是在合并多个 pdf 文件进行发布时,这些错误很明显。

      我没有开发一个最小的工作示例来找到我在使用图形调整大小方法时遇到的真正问题,而是找到了一个解决方法,它使用除法器类使用固定轴大小。

      from mpl_toolkits.axes_grid1 import Divider, Size
      def fix_axes_size_incm(axew, axeh):
          axew = axew/2.54
          axeh = axeh/2.54
      
          #lets use the tight layout function to get a good padding size for our axes labels.
          fig = plt.gcf()
          ax = plt.gca()
          fig.tight_layout()
          #obtain the current ratio values for padding and fix size
          oldw, oldh = fig.get_size_inches()
          l = ax.figure.subplotpars.left
          r = ax.figure.subplotpars.right
          t = ax.figure.subplotpars.top
          b = ax.figure.subplotpars.bottom
      
          #work out what the new  ratio values for padding are, and the new fig size.
          neww = axew+oldw*(1-r+l)
          newh = axeh+oldh*(1-t+b)
          newr = r*oldw/neww
          newl = l*oldw/neww
          newt = t*oldh/newh
          newb = b*oldh/newh
      
          #right(top) padding, fixed axes size, left(bottom) pading
          hori = [Size.Scaled(newr), Size.Fixed(axew), Size.Scaled(newl)]
          vert = [Size.Scaled(newt), Size.Fixed(axeh), Size.Scaled(newb)]
      
          divider = Divider(fig, (0.0, 0.0, 1., 1.), hori, vert, aspect=False)
          # the width and height of the rectangle is ignored.
      
          ax.set_axes_locator(divider.new_locator(nx=1, ny=1))
      
          #we need to resize the figure now, as we have may have made our axes bigger than in.
          fig.set_size_inches(neww,newh)
      

      注意事项:

      • 在轴实例上调用 set_axes_locator() 后,您将破坏 tight_layout() 函数。
      • 您选择的原始图形大小将无关紧要,最终图形大小由您选择的轴大小和标签/刻度标签/向外刻度的大小决定。
      • 此方法不适用于颜色比例尺。
      • 这是我第一次发布堆栈溢出帖子。

      【讨论】:

      • 我的回答不会给出不准确的结果。但当然你可以举个例子来证明你的主张。
      • 好的,经过进一步测试,我可以看到使用基本 rcParams 后,您的代码可以正常工作,输出 pdf 文件不准确(交互式绘图至少 1x1 英寸是错误的)。我怀疑我是否会花更多时间来找出导致问题的特定参数,因为我有一个适用于我的用例的解决方案,但如果我猜测它是'text.usetex = True'。我编辑了我的答案以反映这一点。
      【解决方案4】:

      另一种使用 fig.add_axes 的方法非常准确。我也包括了 1 厘米的网格

      import matplotlib.pyplot as plt
      import matplotlib as mpl
      
      # This example fits a4 paper with 5mm margin printers
      
      # figure settings
      figure_width = 28.7 # cm
      figure_height = 20 # cm
      left_right_magrin = 1 # cm
      top_bottom_margin = 1 # cm
      
      # Don't change
      left   = left_right_magrin / figure_width # Percentage from height
      bottom = top_bottom_margin / figure_height # Percentage from height
      width  = 1 - left*2
      height = 1 - bottom*2
      cm2inch = 1/2.54 # inch per cm
      
      # specifying the width and the height of the box in inches
      fig = plt.figure(figsize=(figure_width*cm2inch,figure_height*cm2inch))
      ax = fig.add_axes((left, bottom, width, height))
      
      # limits settings (important)
      plt.xlim(0, figure_width * width)
      plt.ylim(0, figure_height * height)
      
      # Ticks settings
      ax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(5))
      ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(1))
      ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(5))
      ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(1))
      
      # Grid settings
      ax.grid(color="gray", which="both", linestyle=':', linewidth=0.5)
      
      # your Plot (consider above limits)
      ax.plot([1,2,3,5,6,7,8,9,10,12,13,14,15,17])
      
      # save figure ( printing png file had better resolution, pdf was lighter and better on screen)
      plt.show()
      fig.savefig('A4_grid_cm.png', dpi=1000)
      fig.savefig('tA4_grid_cm.pdf')
      

      结果:

      【讨论】:

      • 请参阅here 了解如何写出好的答案。
      猜你喜欢
      • 2015-01-01
      • 1970-01-01
      • 2016-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多