Matplotlib 中文用戶指南 3.6 圖例指南

圖例指南

原文:Legend guide

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

此圖例指南是legend()中可用文檔的擴(kuò)展 - 請在繼續(xù)閱讀本指南之前確保你熟悉該文檔(見篇尾)的內(nèi)容。

本指南使用一些常見術(shù)語,為了清楚起見,這些術(shù)語在此處進(jìn)行說明:

圖例條目

圖例由一個或多個圖例條目組成。 一個條目由一個鍵和一個標(biāo)簽組成。

圖例鍵

每個圖例標(biāo)簽左側(cè)的彩色/圖案標(biāo)記。

圖例標(biāo)簽

描述由鍵表示的句柄的文本。

圖例句柄

用于在圖例中生成適當(dāng)條目的原始對象。

控制圖例條目

不帶參數(shù)調(diào)用legend()會自動獲取圖例句柄及其相關(guān)標(biāo)簽。 此函數(shù)等同于:

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

get_legend_handles_labels()函數(shù)返回軸域上存在的句柄/藝術(shù)家的列表,這些句柄/藝術(shù)家可以用于為結(jié)果圖例生成條目 - 但值得注意的是,并非所有藝術(shù)家都可以添加到圖例中, 這種情況下會創(chuàng)建『代理』(請參閱特地為添加到圖例創(chuàng)建藝術(shù)家(也稱為代理藝術(shù)家),來了解更多詳細(xì)信息)。

為了完全控制要添加到圖例的內(nèi)容,通常將適當(dāng)?shù)木浔苯觽鬟f給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])

在某些情況下,不可能設(shè)置句柄的標(biāo)簽,因此可以將標(biāo)簽列表傳遞給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'])

特地為添加到圖例創(chuàng)建藝術(shù)家(也稱為代理藝術(shù)家)

并非所有的句柄都可以自動轉(zhuǎn)換為圖例條目,因此通常需要創(chuàng)建一個可轉(zhuǎn)換的藝術(shù)家。 圖例句柄不必存在于被用到的圖像或軸域上。

假設(shè)我們想創(chuàng)建一個圖例,其中有一些數(shù)據(jù)表示為紅色:

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()

除了創(chuàng)建一個色塊之外,有許多受支持的圖例句柄,我們可以創(chuàng)建一個帶有標(biāo)記的線條:

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()

圖例位置

圖例的位置可以通過關(guān)鍵字參數(shù)loc指定。 詳細(xì)信息請參閱legend()的文檔。

bbox_to_anchor關(guān)鍵字可讓用戶手動控制圖例布局。 例如,如果你希望軸域圖例位于圖像的右上角而不是軸域的邊角,則只需指定角的位置以及該位置的坐標(biāo)系:

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")
# 將圖例放到這個子圖上方,
# 擴(kuò)展自身來完全利用提供的邊界框。
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")
# 將圖例放到這個小型子圖的右側(cè)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)

plt.show()

相同軸域內(nèi)的多個圖例

有時,在多個圖例之間分割圖例條目會更加清晰。 雖然直覺上的做法可能是多次調(diào)用legend()函數(shù),但你會發(fā)現(xiàn)軸域上只存在一個圖例。 這樣做是為了可以重復(fù)調(diào)用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)

# 為第一個線條創(chuàng)建圖例
first_legend = plt.legend(handles=[line1], loc=1)

# 手動將圖例添加到當(dāng)前軸域
ax = plt.gca().add_artist(first_legend)

# 為第二個線條創(chuàng)建另一個圖例
plt.legend(handles=[line2], loc=4)

plt.show()

圖例處理器

為了創(chuàng)建圖例條目,將句柄作為參數(shù)提供給適當(dāng)?shù)?code>HandlerBase子類。 處理器子類的選擇由以下規(guī)則確定:

  • 使用handler_map關(guān)鍵字中的值更新get_legend_handler_map()
  • 檢查句柄是否在新創(chuàng)建的handler_map中。
  • 檢查句柄的類型是否在新創(chuàng)建的handler_map中。
  • 檢查句柄的mro中的任何類型是否在新創(chuàng)建的handler_map中。

處于完整性,這個邏輯大多在get_legend_handler()中實現(xiàn)。

所有這些靈活性意味著我們可以使用一些必要的鉤子,為我們自己的圖例鍵類型實現(xiàn)自定義處理器。

使用自定義處理器的最簡單的例子是,實例化一個現(xiàn)有的HandlerBase子類。 為了簡單起見,讓我們選擇matplotlib.legend_handler.HandlerLine2D,它接受numpoints參數(shù)(出于便利,注意numpointslegend()函數(shù)上的一個關(guān)鍵字)。 然后我們可以將實例的字典作為關(guān)鍵字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)})

如你所見,Line 1現(xiàn)在有 4 個標(biāo)記點,Line 2有兩個(默認(rèn)值)。 嘗試上面的代碼,只需將字典的鍵從line1更改為type(line)。 注意現(xiàn)在兩個Line2D`實例都擁有了 4 個標(biāo)記。

除了用于復(fù)雜的繪圖類型的處理器,如誤差條,莖葉圖和直方圖,默認(rèn)的handler_map有一個特殊的元組處理器(HandlerTuple),它簡單地在頂部一一繪制給定元組中每個項目的句柄。 以下示例演示如何將兩個圖例的鍵相互疊加:

import matplotlib.pyplot as plt
from numpy.random import randn

z = randn(10)

red_dot, = plt.plot(z, "ro", markersize=15)
# 將白色十字放置在一些數(shù)據(jù)上
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

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

實現(xiàn)自定義圖例處理器

可以實現(xiàn)自定義處理器,將任何句柄轉(zhuǎn)換為圖例的鍵(句柄不必要是matplotlibartist)。 處理器必須實現(xiàn)legend_artist方法,該方法為要使用的圖例返回單個藝術(shù)家。 有關(guān)legend_artist的詳細(xì)信息,請參閱legend_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()})

或者,如果我們想要接受全局的AnyObject實例,而不想一直手動設(shè)置handler_map關(guān)鍵字,我們可以注冊新的處理器:

from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})

雖然這里的功能十分清楚,請記住,有很多已實現(xiàn)的處理器,你想實現(xiàn)的目標(biāo)可能易于使用現(xiàn)有的類實現(xiàn)。 例如,要生成橢圓的圖例鍵,而不是矩形鍵:

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()})

使用圖例的現(xiàn)有示例

這里是一個不太詳盡的示例列表,涉及以各種方式使用的圖例:

matplotlib.pyplot.legend(*args, **kwargs) 文檔

在軸域上放置一個圖例。

為了為軸域上已經(jīng)存在的線條(例如通過繪圖)制作圖例,只需使用字符串的可迭代對象(每個圖例條目對應(yīng)一個字符串)調(diào)用此函數(shù)。 例如:

ax.plot([1, 2, 3])
ax.legend(['A simple line'])

但是,為了使『標(biāo)簽』和圖例元素實例保持一致,最好在藝術(shù)家創(chuàng)建時指定標(biāo)簽,或者通過調(diào)用藝術(shù)家的set_label()方法:

line, = ax.plot([1, 2, 3], label='Inline label')
# 通過調(diào)用該方法覆寫標(biāo)簽
line.set_label('Label via method')
ax.legend()

通過定義以下劃線開頭的標(biāo)簽,可以從圖例元素自動選擇中排除特定線條。 這對于所有藝術(shù)家都是默認(rèn)的,因此不帶任何參數(shù)調(diào)用legend(),并且沒有手動設(shè)置標(biāo)簽會導(dǎo)致沒有繪制圖例。

為了完全控制哪些藝術(shù)家擁有圖例條目,可以傳遞擁有圖例的藝術(shù)家的可迭代對象,然后是相應(yīng)圖例標(biāo)簽的可迭代對象:

legend((line1, line2, line3), ('label1', 'label2', 'label3'))

參數(shù)

loc:整數(shù)、字符串或者浮點偶對,默認(rèn)為'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坐標(biāo)(在這種情況下,bbox_to_anchor將被忽略)。

bbox_to_anchormatplotlib.transforms.BboxBase示例或者浮點元組。

bbox_transform坐標(biāo)(默認(rèn)軸域坐標(biāo))中為圖例指定任意位置。

例如,要將圖例的右上角放在軸域中心,可以使用以下關(guān)鍵字:

loc='upper right', bbox_to_anchor=(0.5, 0.5)

ncol:整數(shù)。

圖例的列數(shù),默認(rèn)為 1。

propNone、matplotlib.font_manager.FontProperties或者字典。

圖例的字體屬性,如果為None(默認(rèn)),會使用當(dāng)前的matplotlib.rcParams。

fontsize:整數(shù)、浮點或者{‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’}

控制圖例的字體大小。 如果值為數(shù)字,則大小將為絕對字體大?。ㄒ园鯙閱挝唬?字符串值相對于當(dāng)前默認(rèn)字體大小。 此參數(shù)僅在未指定prop的情況下使用。

numpointsNone或者整數(shù)。

為線條/matplotlib.lines.Line2D創(chuàng)建圖例條目時,圖例中的標(biāo)記點數(shù)。 默認(rèn)值為None,它將從legend.numpoints rcParam中獲取值。

scatterpointsNone或者整數(shù)。

為散點圖/matplotlib.collections.PathCollection創(chuàng)建圖例條目時,圖例中的標(biāo)記點數(shù)。 默認(rèn)值為None,它將從legend.scatterpoints rcParam中獲取值。

scatteryoffsets:浮點的可迭代對象。

為散點圖圖例條目創(chuàng)建的標(biāo)記的垂直偏移量(相對于字體大?。?0.0 是在圖例文本的底部,1.0 是在頂部。 為了將所有標(biāo)記繪制在相同的高度,請設(shè)置為[0.5]。 默認(rèn)值為[0.375,0.5,0.3125]。

markerscaleNone、整數(shù)或者浮點。

圖例標(biāo)記對于原始繪制的標(biāo)記的相對大小。 默認(rèn)值為None,它將從legend.markerscale rcParam中獲取值。

markerfirst: [ True | False ]

如果為True,則圖例標(biāo)記位于圖例標(biāo)簽的左側(cè),如果為False,圖例標(biāo)記位于圖例標(biāo)簽的右側(cè)。

frameonNone或布爾值

控制是否應(yīng)在圖例周圍繪制框架。 默認(rèn)值為None,它將從legend.frameon rcParam中獲取值。

fancyboxNone或布爾值

控制是否應(yīng)在構(gòu)成圖例背景的FancyBboxPatch周圍啟用圓邊。 默認(rèn)值為None,它將從legend.fancybox rcParam中獲取值。

shadowNone或布爾值

控制是否在圖例后面畫一個陰影。 默認(rèn)值為None,它將從legend.shadow rcParam中獲取值。

framealphaNone或浮點

控制圖例框架的 Alpha 透明度。 默認(rèn)值為None,它將從legend.framealpha rcParam中獲取值。

mode{"expand", None}

如果mode設(shè)置為"expand",圖例將水平擴(kuò)展來填充軸域區(qū)域(如果定義圖例的大小,則為bbox_to_anchor)。

bbox_transformNone或者matplotlib.transforms.Transform

邊界框的變換(bbox_to_anchor)。 對于None值(默認(rèn)),將使用AxestransAxes變換。

title:字符串或者None

圖例的標(biāo)題,默認(rèn)沒有標(biāo)題(None)。

borderpad:浮點或None

圖例邊框的內(nèi)邊距。 以字體大小為單位度量。 默認(rèn)值為None,它將從legend.borderpad rcParam中獲取值。

labelspacing:浮點或None

圖例條目之間的垂直間距。 以字體大小為單位度量。 默認(rèn)值為None,它將從legend.labelspacing rcParam中獲取值。

handlelength:浮點或None

圖例句柄的長度。 以字體大小為單位度量。 默認(rèn)值為None,它將從legend.handlelength rcParam取值。

handletextpad:浮點或None

圖例句柄和文本之間的間距。 以字體大小為單位度量。 默認(rèn)值為None,它將從legend.handletextpad rcParam中獲取值。

borderaxespad:浮點或None

軸和圖例邊框之間的間距。 以字體大小為單位度量。 默認(rèn)值為None,它將從legend.borderaxespad rcParam中獲取值。

columnspacing:浮點或None

列間距。以字體大小為單位度量。 默認(rèn)值為None,它將從legend.columnspacing rcParam中獲取值。

handler_map:字典或None

自定義字典,用于將實例或類型映射到圖例處理器。 這個handler_map會更新在matplotlib.legend.Legend.get_legend_handler_map()中獲得的默認(rèn)處理器字典。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容