2012-01-23 135 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}