Pynote

Python、機械学習、画像処理について

matplotlib - legend() を使った凡例のカスタマイズ方法 まとめ

legend

基本的な使い方

何も引数を指定しない場合、グラフを作成した際に label 引数で指定名前が凡例に表示される。

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

fig, ax = plt.subplots(figsize=(5, 5))
ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend()


凡例のラベルを指定する。

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

fig, ax = plt.subplots(figsize=(5, 5))
line1, = ax.plot(x, y1, label='sin')
line2, = ax.plot(x, y2, label='cos')
ax.legend(['A', 'B'])


指定した Artist オブジェクトに凡例をつける。

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

fig, ax = plt.subplots(figsize=(5, 5))
line1, = ax.plot(x, y1, label='sin')
line2, = ax.plot(x, y2, label='cos')
ax.legend([line1, line2], ['A', 'B'])


凡例の位置を指定する。

bbox_to_anchor=(x, y, width, height) と loc で指定した場合

(x, y, width, height) は Axes 座標系 (左下が (0, 0)、右上が (1, 1)) で bbox_to_anchor の位置及び大きさを指定する。
この矩形内の loc で指定した場所に凡例が配置される。
borderaxespad で矩形と凡例の間のパディングをフォントサイズ単位で指定する。


from matplotlib.patches import Rectangle

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(8, 15))
plt.subplots_adjust(hspace=0.5)

locs = ['upper left', 'upper right', 'lower left', 'lower right',
        'center left', 'center right', 'upper center', 'lower center',
        'center', 'best', 'right']

cols = 2
rows = np.ceil(len(locs) / cols)
for i, loc in enumerate(locs, 1):
    ax = fig.add_subplot(rows, cols, i)
    ax.plot(x, y1, label='sin')
    ax.plot(x, y2, label='cos')
    ax.set_title(loc)
    ax.legend(loc=loc, bbox_to_anchor=(0.5, 0, 0.5, 1))
    
    # わかりやすいように bbox_to_anchor を可視化する。
    rect = Rectangle(
        (0.5, 0), 0.5, 1, linewidth=1, edgecolor='r',
        facecolor='none', clip_on=False, zorder=10)
    rect.set_transform(ax.transAxes)  # axes 座標系
    ax.add_patch(rect)


loc=(x, y) を指定した場合

loc=(x, y) を指定した場合、凡例の左下がこの位置にくるように配置される。
(x, y) は Axes 座標系 (左下が (0, 0)、右上が (1, 1)) で位置を指定する。
この際、bbox_to_anchor、borderaxespad は無視される。

from matplotlib.patches import Circle

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

fig, ax = plt.subplots(figsize=(5, 3))
ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend(loc=(0.1, 0.1))

# わかりやすいように点 loc を可視化する。
circle = Circle((0.1, 0.1), 0.01, linewidth=1, facecolor='r')
circle.set_transform(ax.transAxes)  # axes 座標系
ax.add_patch(circle)


bbox_to_anchor=(x, y) を指定した場合

(x, y) は Axes 座標系 (左下が (0, 0)、右上が (1, 1)) で指定する。
凡例の loc で指定した場所が bbox_to_anchor で指定した点にくるように配置される。
borderaxespad で bbox_to_anchor で指定した点と凡例の間のパディングをフォントサイズ単位で指定する。

from matplotlib.patches import Circle

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(8, 15))
plt.subplots_adjust(hspace=0.5)

locs = ['upper left', 'upper right', 'lower left', 'lower right',
        'center left', 'center right', 'upper center', 'lower center',
        'center', 'best', 'right']

cols = 2
rows = np.ceil(len(locs) / cols)
for i, loc in enumerate(locs, 1):
    ax = fig.add_subplot(rows, cols, i)
    ax.plot(x, y1, label='sin')
    ax.plot(x, y2, label='cos')
    ax.set_title(loc)
    ax.legend(loc=loc, bbox_to_anchor=(0.5, 0.2), borderaxespad=0)

    # わかりやすいように bbox_to_anchor を可視化する。
    circle = Circle((0.5, 0.2), 0.02, linewidth=1,
                    facecolor='r', zorder=10, clip_on=False)
    circle.set_transform(ax.transAxes)  # axes 座標系
    ax.add_patch(circle)


凡例の列数を指定する。

ncol で凡例の列数を指定する。デフォルトは1。

fig, ax = plt.subplots(figsize=(5, 3))

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend(ncol=2)


点付きの折れ線グラフの場合

凡例の点の数を指定する。

点付きの折れ線グラフの場合、numpoints で凡例の点の数を指定する。
デフォルトは None で、rcParams["legend.numpoints"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([1, 2, 3], 1):
    ax = fig.add_subplot(3, 1, i)
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('numpoints={}'.format(param))
    ax.legend(numpoints=param)


凡例の点の大きさを指定する。

点付きの折れ線グラフの場合、markerscale で凡例の点の大きさを指定する。
デフォルトは None で、rcParams["legend.markerscale"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([1, 2, 3], 1):
    ax = fig.add_subplot(3, 1, i)
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('markerscale={}'.format(param))
    ax.legend(markerscale=param)


マーカーをラベルの前に持ってくるかどうか

markerfirst=True の場合、左からマーカー、ラベルの順に配置する (デフォルト)。
markerfirst=False の場合、左からラベル、マーカーの順に配置する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([True, False], 1):
    ax = fig.add_subplot(2, 1, i)
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('markerfirst={}'.format(param))
    ax.legend(markerfirst=param)


凡例の枠

凡例の枠を付けるかどうか

frameon で凡例の枠を付けるかどうかを指定できる。
デフォルトは None で、rcParams["legend.frameon"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([True, False], 1):
    ax = fig.add_subplot(2, 1, i)
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('frameon={}'.format(param))
    ax.legend(frameon=param)


凡例の枠の角を丸めるかどうか

fancybox で凡例の枠の角を丸めるかどうかを指定できる。
デフォルトは None で、rcParams["legend.fancybox"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([True, False], 1):
    ax = fig.add_subplot(2, 1, i)
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('fancybox={}'.format(param))
    ax.legend(fancybox=param)


凡例の枠に影をつけるかどうか

shadow で凡例の枠に影をつけるかどうかを指定できる。
デフォルトは None で、rcParams["legend.shadow"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([True, False], 1):
    ax = fig.add_subplot(2, 1, i)
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('shadow={}'.format(param))
    ax.legend(shadow=param)


凡例を透過するかどうか

framealpha で凡例の透過度を指定できる。
デフォルトは None で、rcParams["legend.framealpha"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate([0.3, 0.5, 1], 1):
    ax = fig.add_subplot(3, 1, i, facecolor='lightgray')
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('framealpha={}'.format(param))
    ax.legend(framealpha=param)


凡例の色を指定する。

facecolor で凡例の色を指定できる。
デフォルトは None で、rcParams["legend.facecolor"] の値を使用する。
'inherit' を指定した場合、rcParams["axes.facecolor"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate(['pink', 'lightgreen', 'lightblue'], 1):
    ax = fig.add_subplot(3, 1, i, facecolor='lightgray')
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('facecolor={}'.format(param))
    ax.legend(facecolor=param)


凡例の枠の色を指定する。

edgecolor で凡例の色を指定できる。
デフォルトは None で、rcParams["legend.edgecolor"] の値を使用する。
'inherit' を指定した場合、rcParams["axes.edgecolor"] の値を使用する。

x = np.linspace(0, 10, 10)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(5, 8))
for i, param in enumerate(['pink', 'lightgreen', 'lightblue'], 1):
    ax = fig.add_subplot(3, 1, i, facecolor='lightgray')
    ax.plot(x, y1, 'ro-', ms=3, label='sin')
    ax.plot(x, y2, 'bo-', ms=3, label='cos')
    ax.set_title('edgecolor={}'.format(param))
    ax.legend(edgecolor=param)


凡例の枠を Axes の横幅に広げる。

mode='expand' を指定した場合、凡例を Axes の横幅に広げる。
bbox_to_anchor を指定している場合、凡例をその横幅に広げる。

fig, ax = plt.subplots(figsize=(5, 3))

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend(mode='expand', loc='lower center')


凡例にタイトルをつける。

fig, ax = plt.subplots(figsize=(5, 3))

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend(title='title', title_fontsize=12)


凡例内のラベル、マーカーの配置を指定する。

  • borderpad: 凡例の枠とラベルのスペース。デフォルトは None で、rcParams["legend.borderpad"] の値を使用する。
  • labelspacing: ラベル間のスペース。デフォルトは None で、rcParams["legend.labelspacing"] の値を使用する。単位はフォントサイズ。
  • handlelength: ハンドルの長さ。デフォルトは None で、rcParams["legend.handlelength"] の値を使用する。単位はフォントサイズ。
  • handletextpad: ハンドルとラベルのスペース。デフォルトは None で、rcParams["legend.handletextpad"] の値を使用する。
  • columnspacing: 列が2列以上のとき、列の間のスペース。デフォルトは None で、rcParams["legend.columnspacing"] の値を使用する。


fig, ax = plt.subplots(figsize=(5, 3))

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend(borderpad=1, labelspacing=1, handlelength=4, handletextpad=1)


fig, ax = plt.subplots(figsize=(5, 3))

x = np.linspace(0, 10, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

ax.plot(x, y1, label='sin')
ax.plot(x, y2, label='cos')
ax.legend(ncol=2, columnspacing=1)