web-dev-qa-db-ja.com

Python-凡例は円グラフと重なります

Pythonでmatplotlibを使用します。凡例は円グラフと重複しています。 「最高」、1、2、3 ...などの「loc」のさまざまなオプションを試しましたが、役に立ちませんでした。凡例の位置を正確に言及する方法(円グラフの境界からパディングを与えるなど)、または少なくとも重ならないようにする方法に関する提案はありますか?

17
cassandra

簡単な答えは: _plt.legend_ の引数loc、_bbox_to_anchor_、さらに_bbox_transform_およびmodeは、軸または図に凡例を配置します。


ステップ1:凡例が必要であることを確認します。

多くの場合、凡例はまったく必要なく、情報はコンテキストまたは色によって直接推測できます。

enter image description here

enter image description here

プロットが凡例なしでは生きられない場合、ステップ2に進みます。

ステップ2:円グラフが必要であることを確認してください。

多くの場合、円グラフは情報を伝えるのに最適な方法ではありません。

enter image description here

円グラフの必要性が明確に決定されている場合、凡例を配置します。

凡例を配置する

plt.legend()には、凡例の位置を決定する2つの主要な引数があります。最も重要でそれ自体で十分なのは、loc引数です。
例えば。 plt.legend(loc="upper left")は、境界ボックスの左上隅に収まるように凡例を配置しました。さらに引数が指定されていない場合、この境界ボックスは軸全体になります。

ただし、_bbox_to_anchor_引数を使用して独自の境界ボックスを指定できます。 _bbox_to_anchor_に2タプルが与えられている場合bbox_to_anchor=(1,1)これは、境界ボックスが軸の右上隅にあり、範囲がないことを意味します。次に、loc引数に基づいて凡例が配置される相対点として機能します。次に、サイズがゼロのバウンディングボックスから展開されます。例えば。 locが_"upper left"_の場合、凡例の左上隅は位置(1,1)にあり、凡例は右下に展開されます。

この概念は上記のプロットに使用され、ミスユニバース選挙のバイアスに関する衝撃的な真実を教えてくれます。

_import matplotlib.pyplot as plt
import matplotlib.patches

total = [100]
labels = ["Earth", "Mercury", "Venus", "Mars", "Jupiter",  "Saturn", 
           "Uranus", "Neptune", "Pluto *"]
plt.title('Origin of Miss Universe since 1952')
plt.gca().axis("equal")
pie = plt.pie(total, startangle=90, colors=[plt.cm.Set3(0)],
                            wedgeprops = { 'linewidth': 2, "edgecolor" :"k" })
handles = []
for i, l in enumerate(labels):
    handles.append(matplotlib.patches.Patch(color=plt.cm.Set3((i)/8.), label=l))
plt.legend(handles,labels, bbox_to_anchor=(0.85,1.025), loc="upper left")
plt.gcf().text(0.93,0.04,"* out of competition since 2006", ha="right")
plt.subplots_adjust(left=0.1, bottom=0.1, right=0.75)
_

凡例を図を超えないようにするために、_plt.subplots_adjust_を使用して、図のエッジと軸の間のスペースを増やし、これを凡例で使用できます。

_bbox_to_anchor_に4タプルを使用するオプションもあります。これを使用または解釈する方法は、この質問で詳しく説明されています: matplotlibでの 'bbox_to_anchor'の4要素のTuple引数の意味は何ですか?
そして_mode="expand"_引数を使用して、指定された境界ボックスに凡例を合わせることができます。

このアプローチにはいくつかの便利な代替手段があります。

フィギュア座標の使用

Axes座標で凡例の位置を指定する代わりに、Figure座標を使用できます。利点は、これにより、残りの多くを調整せずに、単に図の1つの隅に凡例を配置できることです。このために、_bbox_transform_引数を使用し、それに図形変換を提供します。 _bbox_to_anchor_に与えられた座標は、図の座標として解釈されます。

_plt.legend(pie[0],labels, bbox_to_anchor=(1,0), loc="lower right", 
                          bbox_transform=plt.gcf().transFigure)
_

ここで_(1,0)_は、図の右下隅です。軸とFigureのエッジ間のデフォルトの間隔のため、これは凡例がパイと重ならないように配置するのに十分です。

enter image description here

他の場合では、オーバーラップが見られないようにそれらの間隔を調整する必要があるかもしれません。

_title = plt.title('What slows down my computer')
title.set_ha("left")
plt.gca().axis("equal")
pie = plt.pie(total, startangle=0)
labels=["Trojans", "Viruses", "Too many open tabs", "The anti-virus software"]
plt.legend(pie[0],labels, bbox_to_anchor=(1,0.5), loc="center right", fontsize=10, 
           bbox_transform=plt.gcf().transFigure)
plt.subplots_adjust(left=0.0, bottom=0.1, right=0.45)
_

enter image description here

_bbox_inches="tight"_でファイルを保存する

現在、画面に表示されるものよりも保存された図に関心がある場合があります。次に、図の端に凡例を配置します。

enter image description here

ただし、_bbox_inches="tight"_を使用してsavefigに保存し、

_plt.savefig("output.png", bbox_inches="tight")
_

これにより、より大きな図が作成され、キャンバスのコンテンツの周囲にぴったりと収まります。

enter image description here

図のサイズを変更せずに、図の内側に凡例をしっかりと配置できる洗練されたアプローチをここに示します: 正確なサイズでパディングなしの図の作成(および軸の外側の凡例)

サブプロットの使用

別の方法は、サブプロットを使用して凡例用のスペースを確保することです。この場合、1つのサブプロットが円グラフを取得し、別のサブプロットが凡例を含みます。これを以下に示します。

_fig = plt.figure(4, figsize=(3,3))
ax = fig.add_subplot(211) 
total = [4,3,2,81]
labels = ["tough working conditions", "high risk of accident", 
              "harsh weather", "it's not allowed to watch DVDs"]
ax.set_title('What people know about oil rigs')
ax.axis("equal")
pie = ax.pie(total, startangle=0)
ax2 = fig.add_subplot(212)
ax2.axis("off") 
ax2.legend(pie[0],labels, loc="center")
_

enter image description here