歡迎光臨
每天分享高質量文章

教程 | 如何優雅而高效地使用Matplotlib實現資料可視化


本文經機器之心(微信公眾號:almosthuman2014)授權轉載,禁止二次轉載”

參與:路雪、蔣思源

Matplotlib 能創建非常多的可視化圖表,它也有一個豐富的 Python 工具生態環境,很多更高級的可視化工具使用 Matplotlib 作為基礎庫。因此本文旨在提供一種高效的 Matplotlib 使用方法,並希望該方法可以幫助大家理解如何更有效地進行日常資料分析工作。

簡介

對新手來說 Python 可視化實在有些令人挫敗。有很多不同的選項,如何選擇正確的選項是一個挑戰。例如,兩年前這篇文章《Overview of Python Visualization Tools》仍然吸引了大量讀者。在那篇文章中,我否定了 Matplotlib。但是,在使用過 pandas、scikit-learn、seaborn 和其他 Python 資料科學包之後,我覺得之前否認 Matplotlib 的行為有點不成熟。坦白講,當時我不是很瞭解 Matplotlib,也不懂如何在我的工作流中高效使用 Matplotlib。

現在我學習了一些工具,瞭解瞭如何基於 Matplotlib 使用這些工具,Matplotlib 逐漸變成了可視化工具的核心。本文將展示如何使用 Matplotlib。我堅定地認為 Matplotlib 是 Python 資料科學包必不可少的一部分,希望這篇文章可以幫助大家瞭解如何使用 Matplotlib 進行 Python 可視化。

為什麼大家都在否定 Matplotlib?

我認為,Matplotlib 對於新手來說比較難存在幾個原因。首先,Matplotlib 有兩個界面。第一個界面基於 MATLAB,使用基於狀態的接口。第二個界面是面向物件的接口。本文就不展開介紹 Matplotlib 有兩個界面的原因,但瞭解這兩種方法在使用 Matplotlib 繪圖時會很重要。兩個界面會引起混淆的原因可以通過 Stack Overflow 和谷歌搜索查找一些信息。此外,新用戶將發現混淆問題有多個解決方案,但是這些問題看起來類似卻不完全相同。從我的個人經驗來講,我們從以前的代碼中可以看出有一些 Matplotlib 代碼的混雜。

關鍵點

Matplotlib 新手應該學習和使用面向物件的接口。

使用 Matplotlib 的另一個歷史性挑戰是一些預設的樣式缺乏吸引力。在 R 使用 ggplot 就可以生成相當不錯的圖,而 Matplotlib 相對來說有點醜。好訊息是 Matplotlib 2.0 中的樣式好看了很多,你可以用最小的努力生成可視化。

第三個挑戰是你不確定什麼時候該使用 Matplotlib,什麼時候該使用基於 Matplotlib 構建的工具,如 pandas 或 seaborn。大部分時候做一件事都有多種選擇,但是對於新手來說選擇正確的道路有些困難。

為什麼使用 Matplotlib?

儘管 Matplotlib 有這麼多問題,我還是喜歡用它。因為它很強大,這個庫允許你創建幾乎所有的可視化圖表。此外,圍繞 Matplotlib 有一個豐富的 Python 工具生態環境,很多更高級的可視化工具使用 Matplotlib 作為基礎庫。因此如果你想在 Python 資料科學工具包中進行任何操作,你需要對如何使用 Matplotlib 有一些基礎瞭解。這就是本文其餘部分的重點,提供一種高效使用 Matplotlib 的基礎方法。

前提

推薦以下步驟學習如何使用 Matplotlib:

1. 學習 Matplotlib 的基本術語,具體來說就是什麼是 Figure 和 Axes。

2. 一直使用面向物件的界面,養成習慣。

3. 用基礎的 pandas 繪圖開始可視化。

4. 使用 seaborn 進行稍微複雜的資料可視化。

5. 使用 Matplotlib 自定義 pandas 或 seaborn 可視化。

下圖非常重要,有助於理解圖的不同術語。


大部分術語很直接易懂,需要牢記的是 Figure 是可能包含一或多個 axes 的最終圖像。Axes 代表單個圖。一旦你理解這些是什麼以及如何通過面向物件的 API 評估它們,其餘步驟就很簡單了。

瞭解這個知識還有一個好處,就是當你在網絡上看東西的時候有一個出發點。如果你花時間瞭解了這個點,那麼其他的 Matplotlib API 才有意義。此外,很多高級 Python 包,如 seaborn 和 ggplot 依賴於 Matplotlib 構建,因此理解了基礎,學習更強大的框架才更加容易。

最後,我不是說你應該逃避其他優秀選項,如 ggplot(又名 ggpy)、bokeh、plotly 或 altair。我只是認為你需要對 matplotlib + pandas + seaborn 有一個基礎的瞭解。瞭解基礎可視化棧之後,你就可以探索其他優秀工具,根據需求做出合適的選擇。

開始

下麵主要介紹如何在 pandas 中創建基礎的可視化以及使用 Matplotlib 定製最常用的項。瞭解基礎流程有助於更直觀地進行自定義。

我主要關註最常見的繪圖任務,如標註軸、調整圖形界限(limit)、更新圖標題、儲存圖像和調整圖例。

開始,我打算設置輸入,讀取一些資料:

  1. import pandas as pdimport matplotlib.pyplot as pltfrom matplotlib.ticker import FuncFormatter

  2. df = pd.read_excel(“https://github.com/chris1610/pbpython/blob/master/data/sample-salesv3.xlsx?raw=true”)

  3. df.head()


資料包括 2014 年的銷售交易額。為簡短起見,我將總結這些資料,列出前十名客戶的採購次數和交易額。繪圖時我將對各列進行重命名。

  1. top_10 = (df.groupby(‘name’)[‘ext price’, ‘quantity’].agg({‘ext price’: ‘sum’, ‘quantity’: ‘count’})

  2.          .sort_values(by=’ext price’, ascending=False))[:10].reset_index()

  3. top_10.rename(columns={‘name’: ‘Name’, ‘ext price’: ‘Sales’, ‘quantity’: ‘Purchases’}, inplace=True)

下圖是資料。


現在資料以簡單的表格形式呈現,我們再來看一下如何將資料繪製成條形圖。如前所述,Matplotlib 具備多種不同風格,可用於渲染圖表。你可以使用 plt.style.available 查看你的系統可用的風格。

  1. plt.style.available

  2. [‘seaborn-dark’, ‘seaborn-dark-palette’, ‘fivethirtyeight’, ‘seaborn-whitegrid’, ‘seaborn-darkgrid’, ‘seaborn’, ‘bmh’, ‘classic’, ‘seaborn-colorblind’, ‘seaborn-muted’, ‘seaborn-white’, ‘seaborn-talk’, ‘grayscale’, ‘dark_background’, ‘seaborn-deep’, ‘seaborn-bright’, ‘ggplot’, ‘seaborn-paper’, ‘seaborn-notebook’, ‘seaborn-poster’, ‘seaborn-ticks’, ‘seaborn-pastel’]

使用如下簡單風格:

  1. plt.style.use(‘ggplot’)

現在我們有了好看的風格,第一步就是使用標準 pandas 繪圖函式繪製資料:

  1. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”)


推薦使用 pandas 繪圖的原因在於它是一種快速便捷地建立可視化原型的方式。

自定義圖表

如果你對該圖表的重要部分都很滿意,那麼下一步就是對它執行自定義。一些自定義(如添加標題和標簽)可以使用 pandas plot 函式輕鬆搞定。但是,你可能會發現自己需要在某個時刻跳出來。這就是我推薦你養成以下習慣的原因:

  1. fig, ax = plt.subplots()

  2. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax)

生成的圖表和原始圖表基本一樣,不過我們向 plt.subplots() 添加了一個額外的呼叫,並將 ax 傳輸至繪圖函式。因此,通過 ax 或 fig 物件可以執行任何自定義。

我們利用 pandas 實現快速繪圖,現在利用 Matplotlib 獲取所有功能。通過使用命名慣例,調整別人的解決方案適應自己的需求變得更加直接簡單了。

假設我們想調整一些軸標簽,且 ax 變數中有多個軸,可以進行一些操作:

  1. fig, ax = plt.subplots()

  2. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax)

  3. ax.set_xlim([-10000, 140000])

  4. ax.set_xlabel(‘Total Revenue’)

  5. ax.set_ylabel(‘Customer’);


這是另一種改變標題和標簽的簡單方式:

  1. fig, ax = plt.subplots()

  2. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax)

  3. ax.set_xlim([-10000, 140000])

  4. ax.set(title=’2014 Revenue’, xlabel=’Total Revenue’, ylabel=’Customer’)


為了進一步展示該方法,我們還可以使用 plt.subplots() 函式可以定義圖像尺寸,一般以英寸為單位。我們還可以使用 ax.legend().set_visible(False) 移除圖例。

  1. fig, ax = plt.subplots(figsize=(5, 6))

  2. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax)

  3. ax.set_xlim([-10000, 140000])

  4. ax.set(title=’2014 Revenue’, xlabel=’Total Revenue’)

  5. ax.legend().set_visible(False)


要想修改這個圖像,你可能需要執行很多操作。圖中最礙眼的可能是總收益額的格式。Matplotlib 可以使用 FuncFormatter 解決這一問題。該函式用途多樣,允許用戶定義的函式應用到值,並傳回格式美觀的字串。

以下是貨幣格式化函式,用於處理數十萬美元區間的數值:

  1. def currency(x, pos):

  2.    ‘The two args are the value and tick position’

  3.    if x >= 1000000:        return ‘${:1.1f}M’.format(x*1e-6)    return ‘${:1.0f}K’.format(x*1e-3)

現在我們有了格式化程式函式,就需要定義它,並將其應用到 x 軸。完整代碼如下:

  1. fig, ax = plt.subplots()

  2. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax)

  3. ax.set_xlim([-10000, 140000])

  4. ax.set(title=’2014 Revenue’, xlabel=’Total Revenue’, ylabel=’Customer’)

  5. formatter = FuncFormatter(currency)

  6. ax.xaxis.set_major_formatter(formatter)

  7. ax.legend().set_visible(False)


這張圖美觀多了,非常好地展示了自定義問題解決方案的靈活性。最後要說的自定義特征是向圖表添加註釋。你可以使用 ax.axvline() 畫垂直線,使用 ax.text() 添加自定義文本。就以上示例,我們可以畫一條表示平均值的線,包括代表 3 個新客戶的標簽。以下是完整代碼(包括註釋):

  1. # Create the figure and the axes

  2. fig, ax = plt.subplots()

  3. # Plot the data and get the averaged

  4. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax)

  5. avg = top_10[‘Sales’].mean()

  6. # Set limits and labels

  7. ax.set_xlim([-10000, 140000])

  8. ax.set(title=’2014 Revenue’, xlabel=’Total Revenue’, ylabel=’Customer’)

  9. # Add a line for the average

  10. ax.axvline(x=avg, color=’b’, label=’Average’, linestyle=’–‘, linewidth=1)

  11. # Annotate the new customers

  12. for cust in [3, 5, 8]:

  13.    ax.text(115000, cust, “New Customer”)

  14. # Format the currency

  15. formatter = FuncFormatter(currency)

  16. ax.xaxis.set_major_formatter(formatter)

  17. # Hide the legend

  18. ax.legend().set_visible(False)


圖表

目前,我們所做的所有改變都是針對單個圖表。我們還能夠在圖像上添加多個表,使用不同的選項儲存整個圖像。

如果我們確定要在同一個圖像上放置兩個表,那麼我們應該對如何做有一個基礎瞭解。首先,創建圖像,然後創建軸,再將它們繪製成圖表。使用 plt.subplots() 可以完成該操作:

  1. fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(7, 4))

在這個例子中,我使用 nrows 和 ncols 指定大小,這對新用戶來說比較清晰易懂。我還使用 sharey=True 以使 y 軸共享相同的標簽。

該示例很靈活,因為不同的軸可以解壓成 ax0 和 ax1。現在我們有了這些軸,就可以像上述示例中那樣繪圖,然後把一個圖放在 ax0 上,另一個圖放在 ax1。

  1. # Get the figure and the axes

  2. fig, (ax0, ax1) = plt.subplots(nrows=1,ncols=2, sharey=True, figsize=(7, 4))

  3. top_10.plot(kind=’barh’, y=”Sales”, x=”Name”, ax=ax0)

  4. ax0.set_xlim([-10000, 140000])

  5. ax0.set(title=’Revenue’, xlabel=’Total Revenue’, ylabel=’Customers’)

  6. # Plot the average as a vertical line

  7. avg = top_10[‘Sales’].mean()

  8. ax0.axvline(x=avg, color=’b’, label=’Average’, linestyle=’–‘, linewidth=1)

  9. # Repeat for the unit plot

  10. top_10.plot(kind=’barh’, y=”Purchases”, x=”Name”, ax=ax1)

  11. avg = top_10[‘Purchases’].mean()

  12. ax1.set(title=’Units’, xlabel=’Total Units’, ylabel=”)

  13. ax1.axvline(x=avg, color=’b’, label=’Average’, linestyle=’–‘, linewidth=1)

  14. # Title the figure

  15. fig.suptitle(‘2014 Sales Analysis’, fontsize=14, fontweight=’bold’);

  16. # Hide the legends

  17. ax1.legend().set_visible(False)

  18. ax0.legend().set_visible(False)


現在,我已經在 jupyter notebook 中用 %matplotlib inline 展示了很多圖像。但是,在很多情況下你需要以特定格式儲存圖像,將其和其他呈現方式整合在一起。

Matplotlib 支持多種不同檔案儲存格式。你可以使用 fig.canvas.get_supported_filetypes() 查看系統支持的檔案格式:

  1. fig.canvas.get_supported_filetypes()

  2. {‘eps’: ‘Encapsulated Postscript’, ‘jpeg’: ‘Joint Photographic Experts Group’, ‘jpg’: ‘Joint Photographic Experts Group’, ‘pdf’: ‘Portable Document Format’, ‘pgf’: ‘PGF code for LaTeX’, ‘png’: ‘Portable Network Graphics’, ‘ps’: ‘Postscript’, ‘raw’: ‘Raw RGBA bitmap’, ‘rgba’: ‘Raw RGBA bitmap’, ‘svg’: ‘Scalable Vector Graphics’, ‘svgz’: ‘Scalable Vector Graphics’, ‘tif’: ‘Tagged Image File Format’, ‘tiff’: ‘Tagged Image File Format’}

我們有 fig 物件,因此我們可以將圖像儲存成多種格式:

  1. fig.savefig(‘sales.png’, transparent=False, dpi=80, bbox_inches=”tight”)

結論

該版本將圖表儲存為不透明背景的 png 檔案。我還指定 dpi 和 bbox_inches=”tight” 以最小化多餘空白。最後,希望該方法可以幫助大家理解如何更有效地使用 Matplotlib 進行日常資料分析。


原文鏈接:http://pbpython.com/effective-matplotlib.html

精彩活動

福利 · 閱讀 | 免費申請讀大資料新書 第23期

推薦閱讀

2017年資料可視化的七大趨勢! 

全球100款大資料工具彙總(前50款) 

論大資料的十大局限

大資料時代的10個重大變革

大資料七大趨勢 第一個趨勢是物聯網

Q: 你還知道哪些實現資料可視化的方法和工具?

歡迎留言與大家分享

請把這篇文章分享給你的朋友

轉載 / 投稿請聯繫:[email protected]

更多精彩文章,請在公眾號後臺點擊“歷史文章”查看

赞(0)

分享創造快樂