【问题标题】:matplotlib savefig bbox_inches = 'tight' does not ignore invisible axesmatplotlib savefig bbox_inches = 'tight' 不会忽略不可见的轴
【发布时间】:2013-10-20 03:38:39
【问题描述】:

当您在 Matplotlib 的 savefig() 函数中设置 bbox_inches = 'tight' 时,它会尝试找到封装图形窗口中所有内容的最紧密边界框。不幸的是,最紧密的边界框似乎包含不可见的轴。

例如,这里是一个 sn-p,其中设置 bbox_inches = 'tight' 可以按需要工作:

import matplotlib.pylab as plt
fig = plt.figure(figsize = (5,5))
data_ax = fig.add_axes([0.2, 0.2, 0.6, 0.6])
data_ax.plot([1,2], [1,2])
plt.savefig('Test1.pdf', bbox_inches = 'tight', pad_inches = 0)

产生:

保存的 pdf 的边界对应于内容的边界。这很好,除了我喜欢使用一组不可见的图形轴来放置注释。如果不可见轴延伸到可见内容的范围之外,那么 pdf 范围大于可见内容。例如:

import matplotlib.pylab as plt
fig = plt.figure(figsize = (5,5))
fig_ax = fig.add_axes([0, 0, 1, 1], frame_on = False)
fig_ax.xaxis.set_visible(False)
fig_ax.yaxis.set_visible(False)
data_ax = fig.add_axes([0.2, 0.2, 0.6, 0.6])
data_ax.plot([1,2], [1,2])
plt.savefig('Test2.pdf', bbox_inches = 'tight', pad_inches = 0)

生产

如何强制 savefig() 忽略图形窗口中的不可见项?我想出的唯一解决方案是自己计算边界框并明确指定 bbox 为 savefig()。

以防万一,我在 Mac OS X 10.8.5 上的 Python 2.7.3 下运行 Matplotlib 1.2.1。

【问题讨论】:

  • 我会指出轴是可见的,你只是让轴对象不可见。在保存图之前添加fig_ax.patch.set_color('r') 以查看此内容。
  • 为什么要把注释放在单独的轴上?
  • @tcaswell 我刚刚尝试在fig_ax.yaxis.set_visible(False) 之后插入fig_ax.patch.set_color('r') 并且pdf 看起来一样。还是)感谢你的建议。我将注释放在一组单独的轴上,以便注释可以延伸到数据轴之外,因此我可以以毫米单位而不是数据单位指定位置。也许有一种方法可以满足这些要求,而无需单独的一组轴...
  • 是的,annotate 将以各种单位进行定位。 matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.annotate
  • 啊,补丁没有显示,因为frameon=False 隐藏了它(对不起,我的错),但我的观点仍然成立。 fig_ax.get_visble() == Truefig_ax.get_window_extent() 将设置您的边界框

标签: python pdf matplotlib


【解决方案1】:

backend_bases.py中的相关函数(由canvas.print_figure调用,由figure.savefig调用生成边界框):

def get_tightbbox(self, renderer):
    """
    Return a (tight) bounding box of the figure in inches.

    It only accounts axes title, axis labels, and axis
    ticklabels. Needs improvement.
    """

    bb = []
    for ax in self.axes:
        if ax.get_visible():
            bb.append(ax.get_tightbbox(renderer))

    _bbox = Bbox.union([b for b in bb if b.width != 0 or b.height != 0])

    bbox_inches = TransformedBbox(_bbox,
                                  Affine2D().scale(1. / self.dpi))

    return bbox_inches

决定轴是否“可见”的唯一考虑因素是 ax.get_visible() 是否返回 true,即使轴中没有可见(artist.get_visible() == False 或简单透明)艺术家。

您观察到的边界框行为是正确的行为。

【讨论】:

    【解决方案2】:

    tcaswell,感谢您的帮助。我最初的问题是,“如何强制 savefig() 忽略图形窗口中的不可见项目?”当我输入fig_ax.set_visible(False) 时,savefig() 会忽略不可见的轴。不幸的是,当我设置fig_ax.set_visible(False) 时,放置在 fig_ax 中的任何艺术家也是不可见的。我回到我发布的原始情节,fig_ax 不存在。

    正如您在评论中暗示的那样,tcaswell,我认为正确的解决方案是避免创建 fig_ax。我目前正在将我的注释和数据轴标签放在默认图形对象fig 中。这有点烦人,因为fig 使用标准化图形单位而不是 mm 单位,但我可以处理。

    【讨论】:

    • @tcaswell 好点。 annotate 适用于文本,因为您可以指定 textcoords='figure points'。我不确定如何做任意补丁。也许ConnectionPatch 会起作用...
    • 另请参阅matplotlib.org/users/transforms_tutorial.html,您可以(大部分)轻松地从屏幕空间(以像素为单位,如果您控制 dpi 为您提供英寸)-> 使用逆变换来确定放置位置的数字分数任意补丁。
    猜你喜欢
    • 2012-10-12
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多