2012-01-23 107 views
27

阅读下面的文章,我设法将一个图例放在绘图外。Matplotlib savefig与绘图外的图例

代码:

import matplotlib.pyplot as pyplot 

x = [0, 1, 2, 3, 4] 
y = [xx*xx for xx in x] 

fig = pyplot.figure() 
ax = fig.add_subplot(111) 

box = ax.get_position() 
ax.set_position([box.x0, box.y0, box.width*0.8, box.height]) 

ax.plot(x, y) 
leg = ax.legend(['abc'], loc = 'center left', bbox_to_anchor = (1.0, 0.5)) 
#pyplot.show() 

fig.savefig('aaa.png', bbox_inches='tight') 

pyplot.show()显示正确的情节与外部它的图例。但是当我将它保存为fig.savefig()的文件时,图例将被截断。

一些使用Google搜索显示的解决方法,例如将bbox_extra_artists=[leg.legendPatch]bbox_extra_artists=[leg]添加到savefig(),但都不起作用。

什么是正确的做法? Matplotlib版本是0.99.3。

谢谢。

+1

(我看到这是旧的线程,但它是谷歌第一)有一个通过包含演员savefig更好的解决方案:http://stackoverflow.com/questions/10101700/moving-matplotlib-legend-outside-of-the-axis-makes-it-cutoff-by-the-figure-box – Alleo

回答

22

问题是,当您动态绘图时,matplotlib自动确定边界以适合所有对象。 当你保存一个文件时,事情不会自动完成,所以你需要指定 图形的大小,然后指定轴对象的边界框。 这里是如何纠正你的代码:

import matplotlib.pyplot as pyplot 

x = [0, 1, 2, 3, 4] 
y = [xx*xx for xx in x] 

fig = pyplot.figure(figsize=(3,3)) 
ax = fig.add_subplot(111) 

#box = ax.get_position() 
#ax.set_position([0.3, 0.4, box.width*0.3, box.height]) 
# you can set the position manually, with setting left,buttom, witdh, hight of the axis 
# object 
ax.set_position([0.1,0.1,0.5,0.8]) 
ax.plot(x, y) 
leg = ax.legend(['abc'], loc = 'center left', bbox_to_anchor = (1.0, 0.5)) 

fig.savefig('aaa.png') 
+0

谢谢, 有效。我希望savefig()的未来版本将支持类似于pyplot.show()的边界计算。 – niboshi

+1

你可以添加它作为功能要求,顺便说一句,你正在使用一个非常旧的版本... – Oz123

+0

嗯,你是对的。我会考虑将其升级到更新的版本。 – niboshi

10

尽管这种方法与传说的作品,似乎不能与figlegend当有多个分支情节,我们希望有一个单一的整体传奇运作良好。当savefig时,figlegend仍然会被裁剪。我刚贴上了我的临时解决方案,以防有人遇到这种情况。

import matplotlib.pyplot as plt 

para = { 
    ## this parameter will indicate the position of 
    ## subplot within figure, but will not be shown 
    ## if using bbox_inches='tight' when saving 
    'figure.subplot.top': 0.5 
} 
#plt.rcParams.update(para) 

fig = plt.figure() 

ax=fig.add_subplot(221) 
## only needed when what to manually control 
## subplot ration 
#ax.set_position([0.1,0.6,0.5, 0.4]) 
ax.plot([1,1,1]) 


ax=fig.add_subplot(222) 
#ax.set_position([0.7,0.6,0.5, 0.4]) 
ax.plot([2,2,2]) 

ax=fig.add_subplot(223) 
#ax.set_position([0.1,0.1,0.5, 0.4]) 
ax.plot([3,3,3]) 


ax=fig.add_subplot(224) 
#ax.set_position([0.7,0.1,0.5, 0.4]) 
p1, = ax.plot([4,4,4]) 
p2, = ax.plot([2,3,2]) 

## figlegend does not work fine with tight bbox 
## the legend always get cropped by this option 
## even add bbox extra will not help 
## had to use legend, and manually adjust it to 
## arbitary position such as (0.3, 2.5) 

## http://matplotlib.org/users/tight_layout_guide.html 
## according to this link, tight layout is only 
## an experimental feature, might not support figlegend 

#lgd = plt.figlend(
lgd = plt.legend(
    [p1,p2], 
    ['a', 'b'], 
    ## by default, legend anchor to axis, but can 
    ## also be anchored to arbitary position 
    ## positions within [1,1] would be within the figure 
    ## all numbers are ratio by default 

    bbox_to_anchor=(-0.1, 2.5), 

    ## loc indicates the position within the figure 
    ## it is defined consistent to the same Matlab function 
    loc='center', 

    ncol=2 
    #mode="expand", 
    #borderaxespad=0. 
    ) 



#plt.show() 

plt.savefig('temp.png', bbox_inches='tight')#, bbox_extra_artist=[lgd]) 
+0

非常感谢。你提交了一个错误报告(bbox_extra_artists?)吗?我有和你一样的问题,带有多轴图形和轴外图形。我无法将您的解决方法应用于我的情况。 – CPBL

+0

我还没有发布任何错误报告。我不确定这是一个错误还是它是这样设计的。 – Ning

0

如果一切都失败了,我用Inkscape中的边界框的功能来处理我所说的持久性缺陷在matplotlib的输出。如果你正在运行GNU/Linux,只需保存任何Matplotlib给你的PDF格式,然后将它发送到下面的地址

def tightBoundingBoxInkscape(pdffile,use_xvfb=True): 
    """Makes POSIX-specific OS calls. Preferably, have xvfb installed, to avoid any GUI popping up in the background. If it fails anyway, could always resort to use_xvfb=False, which will allow some GUIs to show as they carry out the task 
     pdffile: the path for a PDF file, without its extension 
    """ 
    usexvfb='xvfb-run '*use_xvfb 
    import os 
    assert not pdffile.endswith('.pdf') 
    os.system(""" 
     inkscape -f %(FN)s.pdf -l %(FN)s_tmp.svg 
     inkscape -f %(FN)s_tmp.svg --verb=FitCanvasToDrawing \ 
            --verb=FileSave \ 
            --verb=FileQuit 
     inkscape -f %(FN)s_tmp.svg -A %(FN)s-tightbb.pdf 
"""%{'FN':pdffile}