matplotlib:得到`bbox_inches = tight'的边界框

blu*_*e10 4 matplotlib

我经常使用matplotlib生成单独的图形,这些图形应该垂直或水平对齐,例如在LaTeX文档中.我的目标是:

  1. 在所有数字中避免过多的边距或削减.对于独立的数字,这是很容易通过解决bbox_inches='tight'savefig.
  2. 对所有图形使用完全相同的边界框,因为我希望我的轴元素在结果文档中很好地排列.

我目前的解决方案是一种非常不方便的试错方法:我手动尝试猜测合理的边距并设置它们plt.subplots_adjust().这通常需要很长时间,直到我得到满意的结果.

我想知道如果有可能的力量结合起来bbox_inches='tight'使用plt.subplots_adjust()?是否有可能以编程方式获得生成的边界框bbox_inches='tight'?这将允许我确定具有最大轴标签/标题的图形的边界框,并对所有其他图形使用此边界框.

blu*_*e10 5

感谢@Schorsch和@tcaswell指出ax.get_tightbbox几乎解决了这个问题.唯一棘手的部分是将渲染器相关的bbox转换为"英寸"bbox.一般的解决方案是:

tight_bbox_raw = ax.get_tightbbox(fig.canvas.get_renderer())
tight_bbox = TransformedBbox(tight_bbox_raw, Affine2D().scale(1./fig.dpi))
Run Code Online (Sandbox Code Playgroud)

我现在可以重复tight_bbox用于我的其他情节,从而产生漂亮的,相同的盒装数字.

我还写了一个小帮助类 - 不优雅,但很有用:我调用max_box_tracker.add_figure我创建的每个数字,它将在内部更新最大边界框.生成所有绘图后,我可以打印出生成的边界框(直接以代码的形式添加到我的脚本中).

class MaxBoxTracker:
  def __init__(self):
    self.box = None
  def add_figure(self, fig, ax):
    from matplotlib.transforms import TransformedBbox, Affine2D
    box_raw = ax.get_tightbbox(fig.canvas.get_renderer())
    box = TransformedBbox(box_raw, Affine2D().scale(1./fig.dpi)).get_points()
    if self.box is None:
      self.box = box
    else:
      self.box[0][0] = min(self.box[0][0], box[0][0])
      self.box[0][1] = min(self.box[0][1], box[0][1])
      self.box[1][0] = max(self.box[1][0], box[1][0])
      self.box[1][1] = max(self.box[1][1], box[1][1])
  def print_max(self):
    print 'Code to set maximum bbox:\nfrom matplotlib.transforms import Bbox\ntight_bbox = Bbox([[%f, %f], [%f, %f]])' % (
      self.box[0][0], self.box[0][1], self.box[1][0], self.box[1][1]
    )
Run Code Online (Sandbox Code Playgroud)

  • 对于阅读此线程的任何人:不确定是否有必要遍历每个轴;在 Matplotlib 2.x 中,我可以简单地调用 **`bbox = fig.get_tightbbox(fig.canvas.get_renderer())`** 结果是一个包围 **图中每个艺术家**的边界框,已经转换到单位英寸。根据描述:“它只考虑轴标题、轴标签和轴刻度标签”所以请注意。但大多数时候我只关心这些。 (3认同)