圖例可以為可視化賦予實際含義,為不同的圖標元素附上明確說明。我們前面看到了一些簡單的圖例創建例子;本小節中我們來介紹一下在 Matplotlib 中自定義圖例的位置和進行美化的方法。
可以使用plt.legend()函數來創建最簡單的圖例,這個函數能自動創建任何帶有標簽屬性的圖表元素的圖例:
import matplotlib.pyplot as plt plt.style.use('classic') import numpy as np x = np.linspace(0, 10, 1000) fig, ax = plt.subplots() ax.plot(x, np.sin(x), '-b', label='Sine') ax.plot(x, np.cos(x), '--r', label='Cosine') ax.axis('equal') leg = ax.legend(); plt.show()

但除此之外還有很多能自定義圖例的方法。例如,我們可以指定圖例位置並且去除邊框:
ax.legend(loc='upper left', frameon=False) fig

我們可以使用ncol屬性設置圖例中每行的列數:
ax.legend(frameon=False, loc='lower center', ncol=2) fig

還可以使用圓角方框(fancybox)或者增加陰影,設置方框的透明度(alpha 值)或修改文字的邊距:
ax.legend(fancybox=True, framealpha=1, shadow=True, borderpad=1) fig

要獲取更多 legend 函數的可用選項信息,請參考plt.legend的文檔字符串。
選擇設置圖例的元素
正如我們前面例子所示,繪制的圖例默認包括所有帶標簽的元素。如果這不是想要的效果,我們可以調整哪些元素和標簽會出現在圖例當中,這可以通過設置 plot 函數或方法返回的對象實現。plt.plot函數能夠同時產生多條折線,然后將這些線條的實例列表返回。將其中的部分實例傳遞到plt.legend()函數就能設置哪些線條會出現在圖例中,再通過一個標簽的列表指定圖例的名稱:
y = np.sin(x[:, np.newaxis] + np.pi * np.arange(0, 2, 0.5)) lines = plt.plot(x, y) # lines是一個線條實例的列表 plt.legend(lines[:2], ['first', 'second']);

作者更加傾向於使用第一種方式,因為更加清晰。通過將標簽應用在圖表元素上,然后繪制到圖例中:
plt.plot(x, y[:, 0], label='first') plt.plot(x, y[:, 1], label='second') plt.plot(x, y[:, 2:]) plt.legend(framealpha=1, frameon=True);

請注意默認情況下,legend 會忽略所有不帶標簽的元素。
散點大小的圖例
某些情況下默認的圖例不足以滿足特定的可視化需求。例如,你在使用散點的大小來標記數據的某個特征,然后希望創建一個相應的圖例。下面的例子是加州城市人口的散點圖(你們可以用自己文件替換),我們使用散點的大小表現該城市的面積,散點的顏色來表現城市的人口數量(自然對數值)。我們希望使用一個圖例來指明散點尺寸的比例,同時用一個顏色條來說明人口數量,我們可以通過自定義繪制一些標簽數據來實現尺寸圖例:
譯者注:新版 Matplotlib 已經取消 aspect 參數,此處改為使用新的'scaled'參數調用 axis 函數。
import pandas as pd cities = pd.read_csv(r'D:\python\Github學習材料\Python數據科學手冊\data\california_cities.csv') # 提取我們感興趣的數據 lat, lon = cities['latd'], cities['longd'] population, area = cities['population_total'], cities['area_total_km2'] # 繪制散點圖,使用尺寸代表面積,顏色代表人口,不帶標簽 plt.scatter(lon, lat, label=None, c=np.log10(population), cmap='viridis', s=area, linewidth=0, alpha=0.5) plt.axis('scaled') plt.xlabel('longitude') plt.ylabel('latitude') plt.colorbar(label='log$_{10}$(population)') plt.clim(3, 7) # 下面我們創建圖例: # 使用空列表繪制圖例中的散點,使用不同面積和標簽,帶透明度 for area in [100, 300, 500]: plt.scatter([], [], c='k', alpha=0.3, s=area, label=str(area) + ' km$^2$') plt.legend(scatterpoints=1, frameon=False, labelspacing=1, title='City Area') plt.title('California Cities: Area and Population');

之前的圖例都關聯着圖表上的一些對象,因此如果我們需要展示圖例的話我們首先需要繪制圖表元素。在上例中,我們需要的圖例對象(灰色圓圈)不在圖表上,因此我們采用繪制空列表的方式將它們仿造在圖表上(實際上圖上沒有點),但是還是需要注意,只有那些帶標簽的元素才會出現在圖例中。
通過繪制空列表,我們創建了三個帶標簽的對象,然后就可以出現在圖例當中,這個圖例就能表示出有關城市面積的相關信息。這個策略在很多復雜可視化圖表構建過程中都被用到。
最后我們注意到這個圖表實際上是一個地理位置圖表,如果我們能在上面繪制州界線或其他地圖相關的元素的話,會更加清晰。Matplotlib 提供了一個 Basemap 額外工具集來實現這個目標。
多重圖例
有時候我們可能需要在同一個圖表維度中設計多個圖例。不幸的是,Matplotlib 並沒有提供很簡單的方式實現:通過標准的legend接口,只能在整張圖表上創建一個圖例。如果你試圖使用plt.legend()或ax.legend()創建第二個圖例,那么第二條語句創建的圖例會覆蓋第一條語句創建的。我們只能通過從底層開始來創建一個新的圖例 artist 這種方法來解決這個問題,然后使用ax.add_artist()的底層方法手動將第二個作者加到圖表上:
fig, ax = plt.subplots() lines = [] styles = ['-', '--', '-.', ':'] x = np.linspace(0, 10, 1000) for i in range(4): lines += ax.plot(x, np.sin(x - i * np.pi / 2), styles[i], color='black') ax.axis('equal') # 指定第一個圖例的線條和標簽 ax.legend(lines[:2], ['line A', 'line B'], loc='upper right', frameon=False) # 手動創建第二個圖例,並將作者添加到圖表中 from matplotlib.legend import Legend leg = Legend(ax, lines[2:], ['line C', 'line D'], loc='lower right', frameon=False) ax.add_artist(leg); plt.show()

上例展示了用來組成任何 Matplotlib 圖表的底層 artist 對象的簡單說明。如果你去查看ax.legend()的源代碼(你可以通過 IPython 的ax.legend?幫助工具做到),你可以看到這個方法包含了用來構建合適Legend的 artist 對象的邏輯,構建的對象被保存在legend_屬性當中,當繪制時被添加到圖表上進行展示.
