为什么我的matplotlib图的图例总是被裁剪?

时间:2018-10-24 18:52:16

标签: python python-2.7 matplotlib

我正在寻找一种编程方式,以将图例添加到matplotlib图的外部中,以便在将图形保存到svg文件时不会被裁剪。在以下示例中,您将看到在生成的svg图片中裁剪了x轴标签和图例:

import matplotlib
import matplotlib.backends.backend_svg

fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],loc='upper right',borderpad=0.06,handletextpad=0.1,handlelength=1.5,bbox_to_anchor=(1.0, 1.235),frameon=False,columnspacing=1.0,ncol=2)

fig.set_canvas(matplotlib.backends.backend_svg.FigureCanvasSVG(fig))
fig.savefig('C:\plot.svg')
fig.clear()

enter image description here

理想情况下,我想创建图,然后通过某种方法扩展画布以裁剪现有的空白,以使图更紧凑。仅应扩展画布的那些区域,否则将导致裁剪的元素(如外部图例或轴标签)。 我唯一的限制是我无法使用pyplot

当然,我可以对图例属性进行调整,直到找到一个可能适用于该图的配置。但是我希望对于任何一种情节,都有一种通用的解决方案。

任何答案都值得赞赏。

2 个答案:

答案 0 :(得分:1)

bbox_inches='tight'传递到savefig()无效吗?

import matplotlib
import matplotlib.backends.backend_svg

fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],loc='upper right',borderpad=0.06,handletextpad=0.1,handlelength=1.5,bbox_to_anchor=(1.0, 1.235),frameon=False,columnspacing=1.0,ncol=2)

fig.set_canvas(matplotlib.backends.backend_svg.FigureCanvasSVG(fig))
fig.savefig('C:\plot.jpg', bbox_inches='tight')
fig.clear()

答案 1 :(得分:1)

如果我正确理解,您想限制"tight"选项仅扩展图形,而不裁剪图形。由于没有这样的预定义选项,因此您需要首先计算紧密框并仅使用其中小于或大于图形范围的值。

import matplotlib.figure
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.transforms import Bbox

fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],
                        loc='upper right',borderpad=0.06,handletextpad=0.1,
                        handlelength=1.5,bbox_to_anchor=(1.0, 1.235),
                        frameon=False,columnspacing=1.0,ncol=2)

canvas = FigureCanvasAgg(fig)

fig.canvas.draw()
renderer = fig._cachedRenderer
tightbox = fig.get_tightbbox(renderer)
w,h = fig.get_size_inches()
bbox = Bbox.from_extents(min(tightbox.x0,0), min(tightbox.y0,0),
                         max(tightbox.x1,w), max(tightbox.y1,h))

fig.savefig('cropplot.png', bbox_inches=bbox, facecolor="#fff9e3")

enter image description here

在这里,我使图的背景色彩丰富,可以很好地看到边界。 还要注意,我用普通的agg画布替换了svg画布,因为否则没有可用的渲染器。

以下代码应适用于matplotlib的旧版本。它将使图形宽度保持不变,仅在垂直方向上扩展图形。

import matplotlib.figure
from matplotlib.backends.backend_agg import FigureCanvasAgg

def CreateTightBbox(fig):
    from matplotlib.transforms import Affine2D, Bbox, TransformedBbox
    from matplotlib import rcParams

    w,h = fig.get_size_inches()
    renderer = fig._cachedRenderer
    bbox_artists = fig.get_default_bbox_extra_artists()
    bbox_filtered = []

    for a in bbox_artists:
        bbox = a.get_window_extent(renderer)
        if a.get_clip_on():
            clip_box = a.get_clip_box()
            if clip_box is not None:
                bbox = Bbox.intersection(bbox, clip_box)
            clip_path = a.get_clip_path()
            if clip_path is not None and bbox is not None:
                clip_path = clip_path.get_fully_transformed_path()
                bbox = Bbox.intersection(bbox, clip_path.get_extents())
        if bbox is not None and (bbox.width != 0 or bbox.height != 0):
            bbox_filtered.append(bbox)

    if bbox_filtered:
        _bbox = Bbox.union(bbox_filtered)
        trans = Affine2D().scale(1.0 / fig.dpi)
        bbox_extra = TransformedBbox(_bbox, trans)
        bbox_inches = Bbox.union([fig.bbox_inches, bbox_extra])

    pad = rcParams['savefig.pad_inches']
    bbox_inches = bbox_inches.padded(pad)
    bbox = Bbox.from_extents(0, min(bbox_inches.y0,0), w, max(bbox_inches.y1,h))

    return bbox


#create the figure
fig = matplotlib.figure.Figure(figsize=(8,2))
subplot = fig.add_axes([0.1, 0.2, 0.8, 0.75], xlabel='x_label')

Sig_1, = subplot.plot([1,2,3], [1,2,3])
Sig_2, = subplot.plot([1,2,3], [4,5,6])

legend = subplot.legend([Sig_1, Sig_2], ['y_label_1', 'y_label_2'],
                        loc='upper right',borderpad=0.06,handletextpad=0.1,
                        handlelength=1.5,bbox_to_anchor=(1.0, 1.235),
                        frameon=False,columnspacing=1.0,ncol=2)

#set the canvas
canvas = FigureCanvasAgg(fig)
fig.canvas.draw()
w,h = fig.get_size_inches()

#create tight bbox
bbox = CreateTightBbox(fig)

#print bbox
fig.savefig('cropplot.png', bbox_inches=bbox, facecolor="#fff9e3")