ノート
完全なサンプルコードをダウンロードするには、ここをクリックしてください
凡例ガイド#
Matplotlib で柔軟に凡例を生成します。
このレジェンド ガイドは、次のサイトで入手できるドキュメントの拡張版です
legend()
。このガイドを読み進める前に、そのドキュメントの内容を十分に理解しておいてください。
このガイドでは、明確にするためにいくつかの一般的な用語を使用しています。
- 凡例のエントリ#
凡例は、1 つ以上の凡例エントリで構成されます。エントリは、1 つのキーと 1 つのラベルだけで構成されます。
- 凡例キー#
各凡例ラベルの左側にある色付き/パターン化されたマーカー。
- 凡例ラベル#
キーによって表されるハンドルを説明するテキスト。
- 凡例ハンドル#
凡例に適切なエントリを生成するために使用される元のオブジェクト。
凡例エントリの制御#
引数なしで呼び出すlegend()
と、凡例ハンドルとそれに関連付けられたラベルが自動的にフェッチされます。この機能は次と同等です。
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)
このget_legend_handles_labels()
関数は、結果の凡例のエントリを生成するために使用できる、Axes に存在するハンドル/アーティストのリストを返します。ただし、すべてのアーティストを凡例に追加できるわけではないことに注意してください。を作成する必要があります (詳細については、凡例に追加するための特別なアーティストの作成 (別名、プロキシ アーティスト)を参照してください)。
ノート
ラベルとして空の文字列を持つアーティスト、またはアンダースコア (_) で始まるラベルを持つアーティストは無視されます。
凡例に追加されるものを完全に制御するには、適切なハンドルを直接 に渡すのが一般的legend()
です。
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles=[line_up, line_down])
場合によっては、ハンドルのラベルを設定できないため、ラベルのリストを次のように渡すことができますlegend()
。
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend([line_up, line_down], ['Line Up', 'Line Down'])
伝説に追加するための特別なアーティストを作成する (別名. プロキシ アーティスト) #
すべてのハンドルを自動的に凡例エントリに変換できるわけではないため、多くの場合、変換できるアーティストを作成する必要があります。凡例ハンドルは、使用するために Figure または Axes に存在する必要はありません。
赤色で表されるいくつかのデータのエントリを持つ凡例を作成したいとします。
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
red_patch = mpatches.Patch(color='red', label='The red data')
ax.legend(handles=[red_patch])
plt.show()
サポートされている凡例ハンドルは多数あります。色のパッチを作成する代わりに、マーカーで線を作成することもできます。
import matplotlib.lines as mlines
fig, ax = plt.subplots()
blue_line = mlines.Line2D([], [], color='blue', marker='*',
markersize=15, label='Blue stars')
ax.legend(handles=[blue_line])
plt.show()
凡例の場所#
凡例の位置は、キーワード引数locで指定できます
。詳細については、ドキュメントを参照してlegend()
ください。
このbbox_to_anchor
キーワードにより、手動での凡例の配置を大幅に制御できます。たとえば、Axes の角ではなく、Figure の右上隅に Axes の凡例を配置する場合は、角の位置とその位置の座標系を指定するだけです。
カスタムの凡例の配置のその他の例:
fig, ax_dict = plt.subplot_mosaic([['top', 'top'], ['bottom', 'BLANK']],
empty_sentinel="BLANK")
ax_dict['top'].plot([1, 2, 3], label="test1")
ax_dict['top'].plot([3, 2, 1], label="test2")
# Place a legend above this subplot, expanding itself to
# fully use the given bounding box.
ax_dict['top'].legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
ncol=2, mode="expand", borderaxespad=0.)
ax_dict['bottom'].plot([1, 2, 3], label="test1")
ax_dict['bottom'].plot([3, 2, 1], label="test2")
# Place a legend to the right of this smaller subplot.
ax_dict['bottom'].legend(bbox_to_anchor=(1.05, 1),
loc='upper left', borderaxespad=0.)
plt.show()
同じ軸上の複数の凡例#
凡例エントリを複数の凡例に分割する方が明確な場合があります。これを行うための本能的なアプローチは、legend()
関数を複数回呼び出すことかもしれませんが、Axes に存在する凡例は 1 つだけであることがわかります。これはlegend()
、凡例を Axes の最新のハンドルに更新するために繰り返し呼び出すことができるようにするために行われました。古い凡例のインスタンスを保持するには、手動で Axes に追加する必要があります。
fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3], label="Line 1", linestyle='--')
line2, = ax.plot([3, 2, 1], label="Line 2", linewidth=4)
# Create a legend for the first line.
first_legend = ax.legend(handles=[line1], loc='upper right')
# Add the legend manually to the Axes.
ax.add_artist(first_legend)
# Create another legend for the second line.
ax.legend(handles=[line2], loc='lower right')
plt.show()
レジェンドハンドラー#
HandlerBase
凡例エントリを作成するために、適切なサブクラスへの引数としてハンドルが与えられます。ハンドラー サブクラスの選択は、次の規則によって決定されます。
キーワード
get_legend_handler_map()
の値で更新します。handler_map
handle
が新しく作成された にあるかどうかを確認しhandler_map
ます。のタイプが
handle
新しく作成された にあるかどうかを確認しhandler_map
ます。handle
の mro内のタイプのいずれかが新しく作成された にあるかどうかを確認しhandler_map
ます。
完全を期すために、このロジックは主に に実装されてい
get_legend_handler()
ます。
このすべての柔軟性は、独自のタイプの凡例キーのカスタム ハンドラーを実装するために必要なフックがあることを意味します。
カスタム ハンドラーを使用する最も簡単な例は、既存のlegend_handler.HandlerBase
サブクラスの 1 つをインスタンス化することです。簡単にするために、 numpointslegend_handler.HandlerLine2D
引数
を受け入れるものを選択しましょう(numpoints は便宜上、関数のキーワードでもあります)。次に、インスタンスのマッピングを Handler へのキーワードとして、legend へ渡すことができます。legend()
from matplotlib.legend_handler import HandlerLine2D
fig, ax = plt.subplots()
line1, = ax.plot([3, 2, 1], marker='o', label='Line 1')
line2, = ax.plot([1, 2, 3], marker='o', label='Line 2')
ax.legend(handler_map={line1: HandlerLine2D(numpoints=4)})
<matplotlib.legend.Legend object at 0x7f2cf9a16ef0>
ご覧のとおり、"Line 1" には 4 つのマーカー ポイントがあり、"Line 2" には 2 つ (デフォルト) があります。上記のコードを試してみてください。マップのキーを からline1
に
変更するだけtype(line1)
です。両方のLine2D
インスタンスが 4 つのマーカーを取得する方法に注目してください。
エラーバー、ステム プロット、ヒストグラムなどの複雑なプロット タイプのハンドラーに加えて、デフォルトhandler_map
には特別なtuple
ハンドラー ( legend_handler.HandlerTuple
) があり、指定されたタプルの各項目のハンドルを単純に重ねてプロットします。次の例は、2 つの凡例キーを重ねて結合する方法を示しています。
from numpy.random import randn
z = randn(10)
fig, ax = plt.subplots()
red_dot, = ax.plot(z, "ro", markersize=15)
# Put a white cross over some of the data.
white_cross, = ax.plot(z[:5], "w+", markeredgewidth=3, markersize=15)
ax.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])
<matplotlib.legend.Legend object at 0x7f2cfb693760>
このlegend_handler.HandlerTuple
クラスを使用して、複数の凡例キーを同じエントリに割り当てることもできます。
from matplotlib.legend_handler import HandlerLine2D, HandlerTuple
fig, ax = plt.subplots()
p1, = ax.plot([1, 2.5, 3], 'r-d')
p2, = ax.plot([3, 2, 1], 'k-o')
l = ax.legend([(p1, p2)], ['Two keys'], numpoints=1,
handler_map={tuple: HandlerTuple(ndivide=None)})
カスタム凡例ハンドラーの実装#
カスタム ハンドラーを実装して、任意のハンドルを凡例キーに変えることができます (ハンドルは必ずしも matplotlib アーティストである必要はありません)。ハンドラーはlegend_artist
、凡例が使用する単一のアーティストを返すメソッドを実装する必要があります。に必要な署名legend_artist
は、 に記載されてい
legend_artist
ます。
import matplotlib.patches as mpatches
class AnyObject:
pass
class AnyObjectHandler:
def legend_artist(self, legend, orig_handle, fontsize, handlebox):
x0, y0 = handlebox.xdescent, handlebox.ydescent
width, height = handlebox.width, handlebox.height
patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red',
edgecolor='black', hatch='xx', lw=3,
transform=handlebox.get_transform())
handlebox.add_artist(patch)
return patch
fig, ax = plt.subplots()
ax.legend([AnyObject()], ['My first handler'],
handler_map={AnyObject: AnyObjectHandler()})
<matplotlib.legend.Legend object at 0x7f2cddb26a10>
または、 handler_mapキーワードを常にAnyObject
手動で設定する必要なく、インスタンスをグローバルに受け入れたい場合は、新しいハンドラーを次のように登録できます。
from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})
ここでの力は明らかですが、すでに多くのハンドラーが実装されており、達成したいことは既存のクラスで簡単に実現できる可能性があることを覚えておいてください。たとえば、長方形ではなく楕円形の凡例キーを作成するには、次のようにします。
from matplotlib.legend_handler import HandlerPatch
class HandlerEllipse(HandlerPatch):
def create_artists(self, legend, orig_handle,
xdescent, ydescent, width, height, fontsize, trans):
center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
p = mpatches.Ellipse(xy=center, width=width + xdescent,
height=height + ydescent)
self.update_prop(p, orig_handle, legend)
p.set_transform(trans)
return [p]
c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green",
edgecolor="red", linewidth=3)
fig, ax = plt.subplots()
ax.add_patch(c)
ax.legend([c], ["An ellipse, not a rectangle"],
handler_map={mpatches.Circle: HandlerEllipse()})
<matplotlib.legend.Legend object at 0x7f2d00dde710>
スクリプトの合計実行時間: ( 0 分 3.053 秒)