Matplotlib 中文用戶指南 3.6 圖例指南
3.6 圖例指南
此圖例指南是 legend() 中可用文檔的擴展 - 請在繼續閱讀本指南之前確保你熟悉該文檔(見篇尾)的內容。
本指南使用一些常見術語,為了清楚起見,這些術語在此處進行說明:
圖例條目
圖例由一個或多個圖例條目組成。 一個條目由一個鍵和一個標簽組成。
圖例鍵
每個圖例標簽左側的彩色/圖案標記。
圖例標簽
描述由鍵表示的句柄的文本。
圖例句柄
用于在圖例中生成適當條目的原始對象。
控制圖例條目
不帶參數調用 legend() 會自動獲取圖例句柄及其相關標簽。 此函數等同于:
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)
get_legend_handles_labels() 函數返回軸域上存在的句柄/artist 的列表,這些句柄/artist 可以用于為結果圖例生成條目 - 但值得注意的是,并非所有 artist 都可以添加到圖例中, 這種情況下會創建『代理』
為了完全控制要添加到圖例的內容,通常將適當的句柄直接傳遞給 legend() :
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])
在某些情況下,不可能設置句柄的標簽,因此可以將標簽列表傳遞給 legend() :
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
import matplotlib.pyplot as plt
red_patch = mpatches.Patch(color='red', label='The red data')
plt.legend(handles=[red_patch])
plt.show()</code></pre>

除了創建一個色塊之外,有許多受支持的圖例句柄,我們可以創建一個帶有標記的線條:
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
blue_line = mlines.Line2D([], [], color='blue', marker='*',
markersize=15, label='Blue stars')
plt.legend(handles=[blue_line])
plt.show()</code></pre>
圖例位置
圖例的位置可以通過關鍵字參數 loc 指定。 詳細信息請參閱 legend() 的文檔。
bbox_to_anchor 關鍵字可讓用戶手動控制圖例布局。 例如,如果你希望軸域圖例位于圖像的右上角而不是軸域的邊角,則只需指定角的位置以及該位置的坐標系:
plt.legend(bbox_to_anchor=(1, 1),
bbox_transform=plt.gcf().transFigure)
自定義圖例位置的更多示例:
import matplotlib.pyplot as plt
plt.subplot(211)
plt.plot([1,2,3], label="test1")
plt.plot([3,2,1], label="test2")
將圖例放到這個子圖上方,
擴展自身來完全利用提供的邊界框。
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
ncol=2, mode="expand", borderaxespad=0.)
plt.subplot(223)
plt.plot([1,2,3], label="test1")
plt.plot([3,2,1], label="test2")
將圖例放到這個小型子圖的右側
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
plt.show()</code></pre>

相同軸域內的多個圖例
有時,在多個圖例之間分割圖例條目會更加清晰。 雖然直覺上的做法可能是多次調用 legend() 函數,但你會發現軸域上只存在一個圖例。 這樣做是為了可以重復調用 legend() ,將圖例更新為軸域上的最新句柄,因此要保留舊的圖例實例,我們必須將它們手動添加到軸域中:
import matplotlib.pyplot as plt
line1, = plt.plot([1,2,3], label="Line 1", linestyle='--')
line2, = plt.plot([3,2,1], label="Line 2", linewidth=4)
為第一個線條創建圖例
first_legend = plt.legend(handles=[line1], loc=1)
手動將圖例添加到當前軸域
ax = plt.gca().add_artist(first_legend)
為第二個線條創建另一個圖例
plt.legend(handles=[line2], loc=4)
plt.show()</code></pre>

圖例處理器
為了創建圖例條目,將句柄作為參數提供給適當的 HandlerBase 子類。 處理器子類的選擇由以下規則確定:
- 使用 handler_map 關鍵字中的值更新 get_legend_handler_map() 。
- 檢查句柄是否在新創建的 handler_map 中。
- 檢查句柄的類型是否在新創建的 handler_map 中。
- 檢查句柄的 mro 中的任何類型是否在新創建的 handler_map 中。
處于完整性,這個邏輯大多在 get_legend_handler() 中實現。
所有這些靈活性意味著我們可以使用一些必要的鉤子,為我們自己的圖例鍵類型實現自定義處理器。
使用自定義處理器的最簡單的例子是,實例化一個現有的 HandlerBase 子類。 為了簡單起見,讓我們選擇 matplotlib.legend_handler.HandlerLine2D ,它接受 numpoints 參數(出于便利,注意 numpoints 是 legend() 函數上的一個關鍵字)。 然后我們可以將實例的字典作為關鍵字 handler_map 傳給 legend 。
import matplotlib.pyplot as plt
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)})</code></pre>

如你所見, Line 1 現在有 4 個標記點, Line 2 有兩個(默認值)。 嘗試上面的代碼,只需將字典的鍵從 line1 更改為type(line) 。 注意現在兩個 Line2D`實例都擁有了 4 個標記。
除了用于復雜的繪圖類型的處理器,如誤差條,莖葉圖和直方圖,默認的 handler_map 有一個特殊的元組處理器( HandlerTuple ),它簡單地在頂部一一繪制給定元組中每個項目的句柄。 以下示例演示如何將兩個圖例的鍵相互疊加:
import matplotlib.pyplot as plt
from numpy.random import randn
z = randn(10)
red_dot, = plt.plot(z, "ro", markersize=15)
將白色十字放置在一些數據上
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15)
plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])</code></pre>

實現自定義圖例處理器
可以實現自定義處理器,將任何句柄轉換為圖例的鍵(句柄不必要是 matplotlib artist)。 處理器必須實現 legend_artist 方法,該方法為要使用的圖例返回單個 artist。
import matplotlib.pyplot as plt
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()})</code></pre>

或者,如果我們想要接受全局的 AnyObject 實例,而不想一直手動設置 handler_map 關鍵字,我們可以注冊新的處理器:
from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})
雖然這里的功能十分清楚,請記住,有很多已實現的處理器,你想實現的目標可能易于使用現有的類實現。 例如,要生成橢圓的圖例鍵,而不是矩形鍵:
from matplotlib.legend_handler import HandlerPatch
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
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()})</code></pre>

使用圖例的現有示例
這里是一個不太詳盡的示例列表,涉及以各種方式使用的圖例:
- lines_bars_and_markers 示例代碼: scatter_with_legend.py
- API 示例代碼: legend_demo.py
- pylab_examples 示例代碼: contourf_hatching.py
- pylab_examples 示例代碼: figlegend_demo.py
- pylab_examples 示例代碼: finance_work2.py
- pylab_examples 示例代碼: scatter_symbol.py
matplotlib.pyplot.legend(*args, **kwargs) 文檔
在軸域上放置一個圖例。
為了為軸域上已經存在的線條(例如通過繪圖)制作圖例,只需使用字符串的可迭代對象(每個圖例條目對應一個字符串)調用此函數。 例如:
ax.plot([1, 2, 3])
ax.legend(['A simple line'])
但是,為了使『標簽』和圖例元素實例保持一致,最好在 artist 創建時指定標簽,或者通過調用 artist 的 set_label() 方法:
line, = ax.plot([1, 2, 3], label='Inline label')
通過調用該方法覆寫標簽
line.set_label('Label via method')
ax.legend()</code></pre>
通過定義以下劃線開頭的標簽,可以從圖例元素自動選擇中排除特定線條。 這對于所有 artist 都是默認的,因此不帶任何參數調用 legend() ,并且沒有手動設置標簽會導致沒有繪制圖例。
為了完全控制哪些 artist 擁有圖例條目,可以傳遞擁有圖例的 artist 的可迭代對象,然后是相應圖例標簽的可迭代對象:
legend((line1, line2, line3), ('label1', 'label2', 'label3'))
參數
loc :整數、字符串或者浮點偶對,默認為 'upper right' 。
圖例的位置。 可能的代碼是:
位置字符串
位置代碼
'best'
0
'upper right'
1
'upper left'
2
'lower left'
3
'lower right'
4
'right'
5
'center left'
6
'center right'
7
'lower center'
8
'upper center'
9
'center'
10
或者,可以是一個二元組,提供圖例的距離左下角的 x, y 坐標(在這種情況下, bbox_to_anchor 將被忽略)。
bbox_to_anchor : matplotlib.transforms.BboxBase 示例或者浮點元組。
在 bbox_transform 坐標(默認軸域坐標)中為圖例指定任意位置。
例如,要將圖例的右上角放在軸域中心,可以使用以下關鍵字:
loc='upper right', bbox_to_anchor=(0.5, 0.5)
ncol :整數。
圖例的列數,默認為 1。
prop : None 、 matplotlib.font_manager.FontProperties 或者字典。
圖例的字體屬性,如果為 None (默認),會使用當前的 matplotlib.rcParams 。
fontsize :整數、浮點或者 {‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’} 。
控制圖例的字體大小。 如果值為數字,則大小將為絕對字體大小(以磅為單位)。 字符串值相對于當前默認字體大小。 此參數僅在未指定 prop 的情況下使用。
numpoints : None 或者整數。
為線條/ matplotlib.lines.Line2D 創建圖例條目時,圖例中的標記點數。 默認值為 None ,它將從 legend.numpoints rcParam 中獲取值。
scatterpoints : None 或者整數。
為散點圖/ matplotlib.collections.PathCollection 創建圖例條目時,圖例中的標記點數。 默認值為 None ,它將從 legend.scatterpoints rcParam 中獲取值。
scatteryoffsets :浮點的可迭代對象。
為散點圖圖例條目創建的標記的垂直偏移量(相對于字體大小)。 0.0 是在圖例文本的底部,1.0 是在頂部。 為了將所有標記繪制在相同的高度,請設置為 [0.5] 。 默認值為 [0.375,0.5,0.3125] 。
markerscale : None 、整數或者浮點。
圖例標記對于原始繪制的標記的相對大小。 默認值為 None ,它將從 legend.markerscale rcParam 中獲取值。
markerfirst : [ True | False ]
如果為 True ,則圖例標記位于圖例標簽的左側,如果為 False ,圖例標記位于圖例標簽的右側。
frameon : None 或布爾值
控制是否應在圖例周圍繪制框架。 默認值為 None ,它將從 legend.frameon rcParam 中獲取值。
fancybox : None 或布爾值
控制是否應在構成圖例背景的 FancyBboxPatch 周圍啟用圓邊。 默認值為 None ,它將從 legend.fancybox rcParam 中獲取值。
shadow : None 或布爾值
控制是否在圖例后面畫一個陰影。 默認值為 None ,它將從 legend.shadow rcParam 中獲取值。
framealpha : None 或浮點
控制圖例框架的 Alpha 透明度。 默認值為 None ,它將從 legend.framealpha rcParam 中獲取值。
mode : {"expand", None}
如果 mode 設置為 "expand" ,圖例將水平擴展來填充軸域區域(如果定義圖例的大小,則為 bbox_to_anchor )。
bbox_transform : None 或者 matplotlib.transforms.Transform
邊界框的變換( bbox_to_anchor )。 對于 None 值(默認),將使用 Axes 的 transAxes 變換。
title :字符串或者 None
圖例的標題,默認沒有標題( None )。
borderpad :浮點或 None
圖例邊框的內邊距。 以字體大小為單位度量。 默認值為 None ,它將從 legend.borderpad rcParam 中獲取值。
labelspacing :浮點或 None
圖例條目之間的垂直間距。 以字體大小為單位度量。 默認值為 None ,它將從 legend.labelspacing rcParam 中獲取值。
handlelength :浮點或 None
圖例句柄的長度。 以字體大小為單位度量。 默認值為 None ,它將從 legend.handlelength rcParam 取值。
handletextpad :浮點或 None
圖例句柄和文本之間的間距。 以字體大小為單位度量。 默認值為 None ,它將從 legend.handletextpad rcParam 中獲取值。
borderaxespad :浮點或 None
軸和圖例邊框之間的間距。 以字體大小為單位度量。 默認值為 None ,它將從 legend.borderaxespad rcParam 中獲取值。
columnspacing :浮點或 None
列間距。以字體大小為單位度量。 默認值為 None ,它將從 legend.columnspacing rcParam 中獲取值。
handler_map :字典或 None
自定義字典,用于將實例或類型映射到圖例處理器。 這個 handler_map 會更新在 matplotlib.legend.Legend.get_legend_handler_map() 中獲得的默認處理器字典。