1338

一連の 20 個のプロット (サブプロットではない) を 1 つの図に作成します。凡例を枠の外に出してほしい。同時に、図のサイズが縮小されるため、軸を変更したくありません。次のクエリについて教えてください。

  1. プロット エリアの外に凡例ボックスを保持したい。(凡例をプロット領域の右側の外側にしたい)。
  2. とにかく、凡例ボックスのサイズが小さくなるように、凡例ボックス内のテキストのフォントサイズを小さくすることはありますか?
4

17 に答える 17

2172

あなたがやりたいことをする方法はたくさんあります。@inalisと@Naviがすでに言ったことに追加するには、bbox_to_anchorキーワード引数を使用して、凡例を軸の外側に部分的に配置したり、フォントサイズを小さくしたりできます。

フォントサイズを小さくすることを検討する前に(これにより、読みにくくなる可能性があります)、凡例をさまざまな場所に配置してみてください。

それでは、一般的な例から始めましょう。

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend()

plt.show()

代替テキスト

同じことを行うが、bbox_to_anchorキーワード引数を使用すると、凡例を軸の境界の少し外側にシフトできます。

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)
 
ax.legend(bbox_to_anchor=(1.1, 1.05))

plt.show()

代替テキスト

同様に、凡例をより水平にするか、図の上部に配置します(丸みを帯びた角と単純なドロップシャドウもオンにします)。

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
          ncol=3, fancybox=True, shadow=True)
plt.show()

代替テキスト

または、現在のプロットの幅を縮小し、凡例を図の軸の完全に外側に配置します(注:を使用する場合はtight_layout()、省略してax.set_position()ください:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])

# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.show()

代替テキスト

同様の方法で、プロットを垂直方向に縮小し、下部に水平方向の凡例を配置します。

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
                 box.width, box.height * 0.9])

# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
          fancybox=True, shadow=True, ncol=5)

plt.show()

代替テキスト

matplotlibの凡例ガイドをご覧ください。もご覧くださいplt.figlegend()

于 2011-01-15T18:12:27.613 に答える
1172

凡例の配置 ( bbox_to_anchor)

loc引数 toを使用して、軸の境界ボックス内に凡例を配置しplt.legendます。
たとえばloc="upper right"、凡例を境界ボックスの右上隅に配置します。デフォルトでは、軸座標 (または境界ボックスの表記法) で から(0,0)までの範囲になります。(1,1)(x0,y0, width, height)=(0,0,1,1)

凡例を軸境界ボックスの外側に配置するには(x0,y0)、凡例の左下隅の軸座標のタプルを指定できます。

plt.legend(loc=(1.04,0))

より用途の広いアプローチは、bbox_to_anchor引数を使用して、凡例を配置する境界ボックスを手動で指定することです。(x0, y0)bboxの一部のみを提供するように制限することができます。これによりゼロ スパン ボックスが作成され、そこから凡例がloc引数で指定された方向に拡張されます。例えば

plt.legend(bbox_to_anchor=(1.04,1), loc="左上")

凡例の左上隅が(1.04,1)軸座標の位置になるように、凡例を軸の外側に配置します。

さらなる例を以下に示します。さらに、modeとのような異なる引数間の相互作用ncolsが示されています。

ここに画像の説明を入力

l1 = plt.legend(bbox_to_anchor=(1.04,1), borderaxespad=0)
l2 = plt.legend(bbox_to_anchor=(1.04,0), loc="lower left", borderaxespad=0)
l3 = plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
l4 = plt.legend(bbox_to_anchor=(0,1.02,1,0.2), loc="lower left",
                mode="expand", borderaxespad=0, ncol=3)
l5 = plt.legend(bbox_to_anchor=(1,0), loc="lower right", 
                bbox_transform=fig.transFigure, ncol=3)
l6 = plt.legend(bbox_to_anchor=(0.4,0.8), loc="upper right")

のように への 4 タプル引数を解釈する方法の詳細についてはbbox_to_anchorl4この質問を参照してください。はmode="expand"、4 タプルで指定されたバウンディング ボックス内で凡例を水平方向に拡張します。縦に展開された凡例については、この質問を参照してください。

軸座標ではなく Figure 座標で境界ボックスを指定すると便利な場合があります。これはl5上の例に示されています。bbox_transform引数は、図の左下隅に凡例を配置するために使用されます。

後処理

凡例を軸の外側に配置すると、凡例が完全にまたは部分的に Figure キャンバスの外側にあるという望ましくない状況につながることがよくあります。

この問題の解決策は次のとおりです。

  • サブプロット パラメータ
    を調整する を使用して、軸が Figure 内のスペースを少なくする (したがって、凡例により多くのスペースを残す) ように、サブプロット パラメータを調整できますplt.subplots_adjust。例えば

    plt.subplots_adjust(right=0.7)
    

    図の右側に凡例を配置できる 30% のスペースを残します。

  • タイト レイアウト
    使用法plt.tight_layoutサブプロット パラメーターを自動的に調整して、Figure 内の要素が Figure の端に密着するようにします。残念ながら、この自動化では凡例は考慮されていませんが、サブプロット領域全体 (ラベルを含む) が収まる長方形のボックスを提供できます。

    plt.tight_layout(rect=[0,0,0.75,1])
    
  • bbox_inches = "tight"
    引数bbox_inches = "tight"toを使用してplt.savefigを保存すると、キャンバス上のすべてのアーティスト (凡例を含む) が保存領域に収まるように図を保存できます。必要に応じて、Figure のサイズが自動的に調整されます。

    plt.savefig("output.png", bbox_inches="tight")
    
  • サブプロット パラメータを自動的に調整する 図のサイズを変更せず
    に凡例がキャンバスの内側に収まるようにサブプロットの位置を自動的に調整する方法は、この回答にあります。

上記のケースの比較:

ここに画像の説明を入力

代替案

フィギュア伝説

軸の代わりに図に凡例を使用することができますmatplotlib.figure.Figure.legend。これは、特別な引数が不要な matplotlib バージョン >=2.1 で特に便利になりました。

fig.legend(loc=7) 

図のさまざまな軸ですべてのアーティストの凡例を作成します。凡例は、loc引数を使用して配置されます。これは、軸の内側に配置する方法と同様ですが、図全体を参照するため、自動的に軸の外側になります。残っているのは、凡例と軸の間に重複がないようにサブプロットを調整することです。ここで、上記の「サブプロットパラメーターを調整する」というポイント が役立ちます。例:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi)
colors=["#7aa0c4","#ca82e1" ,"#8bcd50","#e18882"]
fig, axes = plt.subplots(ncols=2)
for i in range(4):
    axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))

fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)   
plt.show()

ここに画像の説明を入力

専用サブプロット軸内の凡例

を使用bbox_to_anchorする代わりに、凡例を専用のサブプロット軸 ( lax) に配置することもできます。凡例のサブプロットはプロットよりも小さくする必要があるためgridspec_kw={"width_ratios":[4,1]}、軸の作成時に使用できます。軸を非表示にできますがlax.axis("off")、凡例を入れます。凡例のハンドルとラベルは、 を介して実際のプロットから取得する必要があり、サブプロットh,l = ax.get_legend_handles_labels()の凡例に提供できます。完全な例を以下に示します。laxlax.legend(h,l)

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 6,2

fig, (ax,lax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios":[4,1]})
ax.plot(x,y, label="y=sin(x)")
....

h,l = ax.get_legend_handles_labels()
lax.legend(h,l, borderaxespad=0)
lax.axis("off")

plt.tight_layout()
plt.show()

これにより、上のプロットと視覚的に非常によく似たプロットが生成されます。

ここに画像の説明を入力

最初の軸を使用して凡例を配置することもできますがbbox_transform、凡例の軸の を使用します。

ax.legend(bbox_to_anchor=(0,0,1,1), bbox_transform=lax.transAxes)
lax.axis("off")

このアプローチでは、凡例ハンドルを外部から取得する必要はありませんが、bbox_to_anchor引数を指定する必要があります。

参考資料と注意事項:

  • 凡例でやりたいことのいくつかの例を含むmatplotlibの凡例ガイドを検討してください。
  • 円グラフの凡例を配置するためのいくつかのサンプル コードは、この質問への回答として直接見つけることができます: Python - 凡例が円グラフと重なっています。
  • 引数は文字列のloc代わりに数値を取ることができるため、呼び出しが短くなりますが、相互に直感的にマッピングされるわけではありません。参照用のマッピングは次のとおりです。

ここに画像の説明を入力

于 2017-04-16T16:04:28.197 に答える
176
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

fontP = FontProperties()
fontP.set_size('xx-small')

p1, = plt.plot([1, 2, 3], label='Line 1')
p2, = plt.plot([3, 2, 1], label='Line 2')
plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', prop=fontP)

ここに画像の説明を入力

  • Mateen Ulhaqが指摘したように、fontsize='xx-small'インポートせずに動作しFontPropertiesます。
plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', fontsize='xx-small')
于 2011-01-15T16:21:37.470 に答える
98

凡例をプロット エリアの外に配置するには、 と のキーワードを使用locbbox_to_anchorますlegend()。たとえば、次のコードは凡例をプロット エリアの右側に配置します。

legend(loc="upper left", bbox_to_anchor=(1,1))

詳細については、凡例ガイドを参照してください

于 2011-01-15T16:41:50.900 に答える
70

ここでのすべての優れた回答に加えて、新しいバージョンのmatplotlibとは、可能であれば、プロットに干渉することなく凡例を配置する場所を自動的に決定pylabできます。

pylab.legend(loc='best')

これにより、可能であれば凡例が自動的にデータから離れた場所に配置されます。 loc='best' の使用を比較する

ただし、データをオーバーラップせずに凡例を配置する場所がない場合は、他の回答のいずれかを試してください。を使用loc="best"すると、凡例がプロットの外に出ることはありません。

于 2014-12-08T09:46:40.633 に答える
57

簡単な回答:凡例でドラッグ可能なものを呼び出して、好きな場所にインタラクティブに移動します。

ax.legend().draggable()

長い回答:プログラムではなくインタラクティブ/手動で凡例を配置したい場合は、凡例のドラッグ可能なモードを切り替えて、好きな場所にドラッグできるようにすることができます。以下の例を確認してください。

import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)
#plot the data
x = np.arange(-5, 6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()
于 2013-02-20T19:41:10.750 に答える
13

Matplotlib の新しいバージョンでは、凡例をプロットの外に配置することがはるかに簡単になったため、この質問を更新する価値があります。この例は Matplotlib version で作成し3.1.1ました。

ユーザーはloc、境界ボックス内の任意の場所に凡例を配置するために、パラメーターに座標の 2 タプルを渡すことができます。plt.tight_layout()唯一の落とし穴は、matplotlib を実行してプロットの次元を再計算し、凡例が表示されるようにする必要があることです。

import matplotlib.pyplot as plt

plt.plot([0, 1], [0, 1], label="Label 1")
plt.plot([0, 1], [0, 2], label='Label 2')

plt.legend(loc=(1.05, 0.5))
plt.tight_layout()

これにより、次のプロットが得られます。

凡例を外側にプロット

参考文献:

于 2020-04-05T22:16:21.147 に答える
11

前述のように、凡例をプロットに配置することも、端まで少しずらして配置することもできます。これは、 IPython Notebookで作成されたPlotly Python APIを使用した例です。私はチームにいます。

まず、必要なパッケージをインストールします。

import plotly
import math
import random
import numpy as np

次に、Plotly をインストールします。

un='IPython.Demo'
k='1fw3zw2o13'
py = plotly.plotly(username=un, key=k)


def sin(x,n):
sine = 0
for i in range(n):
    sign = (-1)**i
    sine = sine + ((x**(2.0*i+1))/math.factorial(2*i+1))*sign
return sine

x = np.arange(-12,12,0.1)

anno = {
'text': '$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$',
'x': 0.3, 'y': 0.6,'xref': "paper", 'yref': "paper",'showarrow': False,
'font':{'size':24}
}

l = {
'annotations': [anno], 
'title': 'Taylor series of sine',
'xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}
}

py.iplot([{'x':x, 'y':sin(x,1), 'line':{'color':'#e377c2'}, 'name':'$x\\\\$'},\
      {'x':x, 'y':sin(x,2), 'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
      {'x':x, 'y':sin(x,3), 'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
      {'x':x, 'y':sin(x,4), 'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)

これによりグラフが作成され、凡例をプロット自体に保持することができます。設定されていない場合の凡例のデフォルトは、ここに示すようにプロットに配置することです。

ここに画像の説明を入力

別の配置として、グラフの端と凡例の境界線をぴったりと揃えて、境界線を削除してぴったり合わせることができます。

ここに画像の説明を入力

コードまたは GUI を使用して、凡例とグラフの移動とスタイル変更を行うことができます。凡例をシフトするには、x と y の値に <= 1 を割り当てることで凡例をグラフ内に配置する次のオプションがあります。例:

  • {"x" : 0,"y" : 0}- 左下の
  • {"x" : 1, "y" : 0}- 右下
  • {"x" : 1, "y" : 1}- 右上
  • {"x" : 0, "y" : 1}- 左上
  • {"x" :.5, "y" : 0}-- 下中央
  • {"x": .5, "y" : 1}-- トップセンター

この場合、ドキュメントlegendstyle = {"x" : 1, "y" : 1}にも記載されている右上の を選択します。

ここに画像の説明を入力

于 2014-02-09T13:55:14.413 に答える
3

これらの線に沿った何かが私にとってうまくいきました。Joe から取った少しのコードから始めて、このメソッドはウィンドウの幅を変更して、図の右側に凡例が自動的に収まるようにします。

import matplotlib.pyplot as plt
import numpy as np

plt.ion()

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Put a legend to the right of the current axis
leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.draw()

# Get the ax dimensions.
box = ax.get_position()
xlocs = (box.x0,box.x1)
ylocs = (box.y0,box.y1)

# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()

# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)

# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))

# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])

plt.draw()
于 2013-12-21T00:38:27.157 に答える
2

試すこともできますfiglegend。Axesオブジェクトから独立して凡例を作成することができます。ただし、オブジェクトのフォーマットが正しく渡されるように、いくつかの「ダミー」パスを作成する必要がある場合があります。

于 2011-01-17T07:06:56.943 に答える