web-dev-qa-db-ja.com

プロット外の凡例付きの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()でファイルとして保存すると、凡例は切り捨てられます。

一部のグーグルでは、savefig()に_bbox_extra_artists=[leg.legendPatch]_または_bbox_extra_artists=[leg]_を追加するなどの回避策が示されていますが、どちらも機能していません。

それを行う正しい方法は何ですか? Matplotlibのバージョンは0.99.3です。

ありがとう。

34
niboshi

この方法は凡例で機能しますが、複数のサブプロットがあり、1つの全体的な凡例が必要な場合、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])
11
Ning

他のすべてが失敗した場合、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}
0
CPBL