matplotlib 進階之Legend guide


import numpy as np
import matplotlib.pyplot as plt

matplotlib.pyplot.legend

在開始教程之前,我們必須先了解matplotlib.pyplot.legend(),該函數可以用以添加圖例。

方法1自動檢測

通過這種方式,lendgend()會從artist中獲取label屬性,並自動生成圖例,比如:

fig, ax = plt.subplots()
line, = ax.plot([1, 2, 3], label="Inline label")
ax.legend()
plt.show()

或者:

line.set_label("Inline label")
ax.legend()

在這里插入圖片描述

方法2為現有的Artist添加

我們也可以通過下列操作,為已經存在的Artist添加圖例,但是這種方式並不推薦,因為我們很容易混淆。

fig, ax = plt.subplots()
line, = ax.plot([1, 2, 3])
ax.legend(["A simple line"])

在這里插入圖片描述

方3顯示添加圖例

我們也可以顯示添加圖例:

fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3])
line2, = ax.plot([3, 2, 1])
ax.legend((line1, line2), ("line1", "line2"))

在這里插入圖片描述

參數:

handle: Artist
label: 標簽
loc:位置,比如"best":0, "upper right" 1 ...
fontsize
...

控制圖例的輸入

直接使用legend()命令,matplotlib會自動檢測並生成圖例,這種方式等價於:

handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)

需要注意的是,只有為Artist設置標簽了,通過get_legend_handles_labels()才有效。
有些時候,我們只需要為部分Artist設置圖例,這時只需手動傳入handles:

line_up, = plt.plot([1,2,3], label='Line 2')
line_down, = plt.plot([3,2,1], label='Line 1')
plt.legend(handles=[line_up, line_down])

當然了,相應的可以傳入標簽:

line_up, = plt.plot([1,2,3], label='Line 2')
line_down, = plt.plot([3,2,1], label='Line 1')
plt.legend([line_up, line_down], ['Line Up', 'Line Down'])

為一類Artist設置圖例

並不是所有的Artist都能被自動設置為圖例,也不是所有Artist都需要被設置為圖例。

假如我們想要為所有紅顏色的玩意兒設置圖例:

import matplotlib.patches as mpatches

x = np.arange(1, 4)
fig, ax = plt.subplots()
for i in range(1, 10):
    ax.plot(x, i * x, color = "red" if i % 2 else "blue")

red_patch = mpatches.Patch(color="red") 
# red_patch: <matplotlib.patches.Patch object at 0x00000228D0D4BF60>
plt.legend(handles=[red_patch], labels=["red line"])
plt.show()

如果沒理解錯,通過patches.Patch構造了一個顏色為紅色的Artist類,然后legend()就會對所有滿足條件的Artist的類進行處理(其實也用不了處理啊,只是加了圖例)。錯啦錯啦,實際上,就是簡單地造了一個顏色為紅色的片,價格red line標簽而已,跟已有的Artist沒啥關系。
在這里插入圖片描述
實際上,圖例並不十分依賴於現有的Artist,我們完全可以隨心所欲地添加:

import matplotlib.lines as mlines
blue_line = mlines.Line2D([], [], color='blue', marker='*',
                          markersize=15, label='Blue stars')
plt.legend(handles=[blue_line])

plt.show()

在這里插入圖片描述

Legend 的位置 loc, bbox_to_anchor

legend()提供了loc參數,可以處理一般的位置。而bbox_to_anchor參數可以更加有效強大地來定位:

x = np.arange(1, 4)
fig, ax = plt.subplots()
for i in range(1, 10):
    ax.plot(x, i * x, color = "red" if i % 2 else "blue", label="line{0}".format(i))

plt.legend(bbox_to_anchor=(1, 1),
           bbox_transform=plt.gcf().transFigure)
plt.show()

在這里插入圖片描述
bbox_to_anchor=(1,1)表示legend的位置在右上角,因為bbox_transform,我們將坐標轉換為了當前figure的坐標系,也就是圖例會放在整個圖片的右上角,如果我們去掉這個選項:

plt.legend(bbox_to_anchor=(1, 1))

在這里插入圖片描述
這個時候和下面是等價的:

plt.legend(bbox_to_anchor=(1,1),
		bbox_transform=ax.transAxes)

即,此時的(1,1)表示的是Axes的右上角。

當我們這么做的時候:

plt.legend(bbox_to_anchor=(1, 1),
           bbox_transform=ax.transData)

這個時候以數據,也就是我們看到的坐標為依據:
在這里插入圖片描述

一個具體的例子

下面會用到的一些參數分析:
bbox_to_anchor: (x, y, width, height) 說實話,我並沒有搞懂width, height的含義,有的時候能調正寬度,有的時候又不能
ncol: 圖例的列數,有些時候圖例太多,讓他分成倆列三列啊
boderraxespad: axes與圖例邊界的距離。


plt.subplot(211)
plt.plot([1, 2, 3], label="test1")
plt.plot([3, 2, 1], label="test2")

# Place a legend above this subplot, expanding itself to
# fully use the given bounding box.
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
           ncol=2, mode="expand", borderaxespad=0.)

plt.subplot(223)
plt.plot([1, 2, 3], label="test1")
plt.plot([3, 2, 1], label="test2")
# Place a legend to the right of this smaller subplot.
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=1.)

plt.show()

在這里插入圖片描述

同一個Axes多個legend

如果我們多次使用legend(),實際上並不會生成多個圖例:

fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3])
line2, = ax.plot([3, 2, 1])
ax.legend([line1], ["line1"])
ax.legend([line2], ["line2"])

plt.show()

在這里插入圖片描述
為此,我們需要手動添加圖例:

fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3])
line2, = ax.plot([3, 2, 1])
legend1 = ax.legend([line1], ["line1"], loc="upper right")
ax.add_artist(legend1)
ax.legend([line2], ["line2"])

plt.show()

在這里插入圖片描述

Legend Handlers

沒看懂啥意思。

from matplotlib.legend_handler import HandlerLine2D

line1, = plt.plot([3, 2, 1], marker='o', label='Line 1')
line2, = plt.plot([1, 2, 3], marker='o', label='Line 2')

plt.legend(handler_map={line1: HandlerLine2D(numpoints=4)})

在這里插入圖片描述


from numpy.random import randn

z = randn(10)

red_dot, = plt.plot(z, "ro", markersize=15)
# Put a white cross over some of the data.
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])

在這里插入圖片描述
從這例子中感覺,就是legend_handler里面有一些現成,稀奇古怪的圖例供我們使用?

from matplotlib.legend_handler import HandlerLine2D, HandlerTuple

p1, = plt.plot([1, 2.5, 3], 'r-d')
p2, = plt.plot([3, 2, 1], 'k-o')

l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1,
               handler_map={tuple: HandlerTuple(ndivide=None)})

在這里插入圖片描述

自定義圖例處理程序

這一節呢,主要就是告訴我們,如何通過handler_map這個參數,傳入一個映射,可以構造任意?奇形怪狀的圖例?不過參數也忒多了吧,不過感覺蠻有用的。

import matplotlib.patches as mpatches


class AnyObject(object):
    pass


class AnyObjectHandler(object):
    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


plt.legend([AnyObject()], ['My first handler'],
           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)
plt.gca().add_patch(c)

plt.legend([c], ["An ellipse, not a rectangle"],
           handler_map={mpatches.Circle: HandlerEllipse()})

在這里插入圖片描述

"""都是啥和啥啊。。。"""
class AnyObject(object):
    pass


class AnyObjectHandler(object):
    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        width, height = handlebox.width, handlebox.height
        patch = mlines.Line2D([1, 2, 3, 4, 6], [1, 2, 3, 4, 6], linewidth=width/2, color='red',
                                   transform=handlebox.get_transform())
        handlebox.add_artist(patch)
        return patch


plt.legend([AnyObject()], ['My first handler'],
           handler_map={AnyObject: AnyObjectHandler()})

在這里插入圖片描述

函數鏈接

plt.lengend()-添加圖例
get_legend_handles_labels()-獲取圖例處理對象和對應的標簽
matplotlib.patches-包括向量,圓,矩形,多邊形等等
legend_artist


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM