matplotlib:获取`bbox_inches=tight`的结果边界框
matplotlib: Get resulting bounding box of `bbox_inches=tight`
我经常使用 matplotlib 生成单个图形,这些图形应该垂直或水平对齐,例如在 LaTeX 文档中。我的目标是:
- 避免在所有图形中使用过多的边距或剪裁。对于独立图形,可以通过在
savefig
. 中使用 bbox_inches='tight'
轻松解决
- 对所有图形使用完全相同的边界框,因为我希望我的轴元素在生成的文档中很好地对齐。
我目前的解决方案是一种非常不方便的试错法:我手动尝试猜测合理的边距并通过 plt.subplots_adjust()
进行设置。这往往需要很长时间才能得到满意的结果。
我想知道是否可以将 bbox_inches='tight'
的力量与 plt.subplots_adjust()
结合起来?是否可以通过编程方式获取 bbox_inches='tight'
的结果边界框?这将允许我确定具有最大轴 labels/titles 的图形的边界框,并将此边界框用于所有其他图形。
感谢@Schorsch 和 @tcaswell 指出 ax.get_tightbbox
几乎解决了这个问题。唯一棘手的部分是将依赖于渲染器的 bbox 转换为 "inches" bbox。一般的解决方案是:
tight_bbox_raw = ax.get_tightbbox(fig.canvas.get_renderer())
tight_bbox = TransformedBbox(tight_bbox_raw, Affine2D().scale(1./fig.dpi))
我现在也可以将 tight_bbox
重复用于我的其他绘图,从而得到漂亮的、相同的盒装图形。
我还写了一个小帮手class——不优雅,但很有用:我为我创建的每个图形调用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]
)
我经常使用 matplotlib 生成单个图形,这些图形应该垂直或水平对齐,例如在 LaTeX 文档中。我的目标是:
- 避免在所有图形中使用过多的边距或剪裁。对于独立图形,可以通过在
savefig
. 中使用 - 对所有图形使用完全相同的边界框,因为我希望我的轴元素在生成的文档中很好地对齐。
bbox_inches='tight'
轻松解决
我目前的解决方案是一种非常不方便的试错法:我手动尝试猜测合理的边距并通过 plt.subplots_adjust()
进行设置。这往往需要很长时间才能得到满意的结果。
我想知道是否可以将 bbox_inches='tight'
的力量与 plt.subplots_adjust()
结合起来?是否可以通过编程方式获取 bbox_inches='tight'
的结果边界框?这将允许我确定具有最大轴 labels/titles 的图形的边界框,并将此边界框用于所有其他图形。
感谢@Schorsch 和 @tcaswell 指出 ax.get_tightbbox
几乎解决了这个问题。唯一棘手的部分是将依赖于渲染器的 bbox 转换为 "inches" bbox。一般的解决方案是:
tight_bbox_raw = ax.get_tightbbox(fig.canvas.get_renderer())
tight_bbox = TransformedBbox(tight_bbox_raw, Affine2D().scale(1./fig.dpi))
我现在也可以将 tight_bbox
重复用于我的其他绘图,从而得到漂亮的、相同的盒装图形。
我还写了一个小帮手class——不优雅,但很有用:我为我创建的每个图形调用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]
)