天天看點

Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

圖例指南

原文: Legend guide 譯者: 飛龍 協定: CC BY-NC-SA 4.0

此圖例指南是

legend()

中可用文檔的擴充 - 請在繼續閱讀本指南之前確定你熟悉該文檔(見篇尾)的内容。

本指南使用一些常見術語,為了清楚起見,這些術語在此處進行說明:

圖例條目

圖例由一個或多個圖例條目組成。 一個條目由一個鍵和一個标簽組成。

圖例鍵

每個圖例标簽左側的彩色/圖案标記。

圖例标簽

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

圖例句柄

用于在圖例中生成适當條目的原始對象。

控制圖例條目

不帶參數調用

legend()

會自動擷取圖例句柄及其相關标簽。 此函數等同于:

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

get_legend_handles_labels()

函數傳回軸域上存在的句柄/藝術家的清單,這些句柄/藝術家可以用于為結果圖例生成條目 - 但值得注意的是,并非所有藝術家都可以添加到圖例中, 這種情況下會建立『代理』(請參閱

特地為添加到圖例建立藝術家(也稱為代理藝術家)

,來了解更多詳細資訊)。

為了完全控制要添加到圖例的内容,通常将适當的句柄直接傳遞給

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'])           

并非所有的句柄都可以自動轉換為圖例條目,是以通常需要建立一個可轉換的藝術家。 圖例句柄不必存在于被用到的圖像或軸域上。

假設我們想建立一個圖例,其中有一些資料表示為紅色:

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()           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

除了建立一個色塊之外,有許多受支援的圖例句柄,我們可以建立一個帶有标記的線條:

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

圖例位置

圖例的位置可以通過關鍵字參數

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()           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

相同軸域内的多個圖例

有時,在多個圖例之間分割圖例條目會更加清晰。 雖然直覺上的做法可能是多次調用

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()           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

圖例處理器

為了建立圖例條目,将句柄作為參數提供給适當的

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)})           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

如你所見,

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"])           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

實作自定義圖例處理器

可以實作自定義處理器,将任何句柄轉換為圖例的鍵(句柄不必要是

matplotlib

artist)。 處理器必須實作

legend_artist

方法,該方法為要使用的圖例傳回單個藝術家。 有關

legend_artist

的詳細資訊,請參閱

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()})           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

或者,如果我們想要接受全局的

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()})           
Matplotlib 中文使用者指南 3.6 圖例指南圖例指南

使用圖例的現有示例

這裡是一個不太詳盡的示例清單,涉及以各種方式使用的圖例:

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

文檔

在軸域上放置一個圖例。

為了為軸域上已經存在的線條(例如通過繪圖)制作圖例,隻需使用字元串的可疊代對象(每個圖例條目對應一個字元串)調用此函數。 例如:

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

但是,為了使『标簽』和圖例元素執行個體保持一緻,最好在藝術家建立時指定标簽,或者通過調用藝術家的

set_label()

方法:

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

通過定義以下劃線開頭的标簽,可以從圖例元素自動選擇中排除特定線條。 這對于所有藝術家都是預設的,是以不帶任何參數調用

legend()

,并且沒有手動設定标簽會導緻沒有繪制圖例。

為了完全控制哪些藝術家擁有圖例條目,可以傳遞擁有圖例的藝術家的可疊代對象,然後是相應圖例标簽的可疊代對象:

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

參數

loc

:整數、字元串或者浮點偶對,預設為

'upper right'

圖例的位置。 可能的代碼是:

位置字元串 位置代碼

'best'

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

中獲得的預設處理器字典。