解決 Matplotlib 的中文顯示問題

Photo by Fabrizio Verrecchia on Unsplash
Photo by Fabrizio Verrecchia on Unsplash
Matplotlib 是一個常用的資料視覺化工具。但是在使用之前,若是沒有先做設定的話,Matplotlib 無法正確地顯示中文。本文章將一步一步地講解如何解決 Matplotlib 的顯示問題。

Matplotlib 是一個常用的資料視覺化工具。但是在使用之前,若是沒有先做設定的話,Matplotlib 無法正確地顯示中文。本文章將一步一步地講解如何解決 Matplotlib 的顯示問題。

由於我只有 Mac OS 系統,所以接下來只會講解如何在 Mac OS 上做設定。

首先,我們來執行下面這一段 Matplotlib 的程式碼。

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame([
    [2015, 23_462_914],
    [2016, 23_515_945],
    [2017, 23_555_522],
    [2018, 23_580_080],
    [2019, 23_596_027],
    [2020, 23_582_179],
], columns=['年份', '人口'])
plt.plot('年份', '人口', data=df)
plt.legend()
plt.xlabel('年份')
plt.ylabel('人口')
plt.title('台灣歷年人口')
無法正確地顯示中文
無法正確地顯示中文

如果你執行的結果也是像上圖一樣,中文字都變成了框框,那表示你必須要繼續往下閱讀。。。。。

首先我們要先準備好中文字型檔。請到 Google Noto Fonts 網頁下,下載 Noto Sans CJK TC 和 Noto Serif CJK TC 這兩個中文字型。下載下來後會是兩個 ZIP 檔,請先將它們解壓縮好放著。可以看到,NotoSansCJKtc 包含 Sans 和 SansMono 字型,而 NotoSerifCJKtc 包含 Serif 字型。

~ % ls
NotoSansCJKtc-hinted NotoSansCJKtc-hinted.zip
NotoSerifCJKtc-hinted NotoSerifCJKtc-hinted.zip
~ % ls NotoSansCJKtc-hinted
LICENSE_OFL.txt
NotoSansCJKtc-Black.otf
NotoSansCJKtc-Bold.otf
NotoSansCJKtc-DemiLight.otf
NotoSansCJKtc-Light.otf
NotoSansCJKtc-Medium.otf
NotoSansCJKtc-Regular.otf
NotoSansCJKtc-Thin.otf
NotoSansMonoCJKtc-Bold.otf
NotoSansMonoCJKtc-Regular.otf
README
~ % ls NotoSerifCJKtc-hinted
NotoSerifCJKtc-hinted
LICENSE_OFL.txt
NotoSerifCJKtc-Black.otf
NotoSerifCJKtc-Bold.otf
NotoSerifCJKtc-ExtraLight.otf
NotoSerifCJKtc-Light.otf
NotoSerifCJKtc-Medium.otf
NotoSerifCJKtc-Regular.otf
NotoSerifCJKtc-SemiBold.otf
README

接下來,切換到 Matplotlib 套件的路徑。以下是在 Miniconda 下,Matplotlib 的字型檔的路徑。這路徑下存放著 Matplotlib 內建的字型檔。很可惜,其中沒有中文。

~ % cd ~/.conda/envs/example/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf

複製所有剛剛從 Google Noto Fonts 下載的字型檔到 mpl-data/fonts/ttf/ 下。Matplotlib 也有支援 OTF 字型檔案格式。

ttf % cp ~/NotoSansCJKtc-hinted/*.otf .
ttf % cp ~/NotoSerifCJKtc-hinted/*.otf .

然後,切換到 .matplotlib,並刪除它下面的 fontlist-v330.json。.matplotlib 是 Matplotlib 的 cache 資料夾。

ttf % cd ~/.matplotlib
.matplotlib % ls
fontlist-v330.json
.matplotlib % rm fontlist-v330.json
.matplotlib % ls

刪除後,你要先停掉 Jupyter,再重啟並且執行我們一開始的那個程式碼。那個程式碼裡面會呼叫 Matplotlib,所以 Matplotlib 會重新產生 fontlist-v330.json。

.matplotlib % ls
fontlist-v330.json
.matplotlib % vi fontlist-v330.json

打開 fontlist-v330.json,我們可以看到 Matplotlib 已經載入我們剛剛放入的字型檔。以下只有列出 NotoSansCJKtc、NotoSerifCJKtc 和 NotoSansMonoCJKtc 的 Regular 的字型檔。其中,要留意它們的 name 屬性。

...
    {
      "fname": "fonts/ttf/NotoSansCJKtc-Regular.otf",
      "name": "Noto Sans CJK TC",
      "style": "normal",
      "variant": "normal",
      "weight": 400,
      "stretch": "normal",
      "size": "scalable",
      "__class__": "FontEntry"
    },
...
    {
      "fname": "fonts/ttf/NotoSerifCJKtc-Regular.otf",
      "name": "Noto Serif CJK TC",
      "style": "normal",
      "variant": "normal",
      "weight": 400,
      "stretch": "normal",
      "size": "scalable",
      "__class__": "FontEntry"
    },
...
    {
      "fname": "fonts/ttf/NotoSansMonoCJKtc-Regular.otf",
      "name": "Noto Sans Mono CJK TC",
      "style": "normal",
      "variant": "normal",
      "weight": 400,
      "stretch": "normal",
      "size": "scalable",
      "__class__": "FontEntry"
    },
...

接下來切回 Matplotlib 套件的字型檔目錄,並且編輯 matplotlibrc。

.matplotlib % cd ~/.conda/envs/example/lib/python3.8/site-packages/matplotlib/mpl-data
mpl-data % ls
fonts images matplotlibrc stylelib
mpl-data % vi matplotlibrc

在 matplotlibrc 中,找到以下這幾行。移除前面的 # 號。剛剛在 fontlist-v330.json 中,我們找到的那三個 Regular 設定與設定裡面的 name 屬性值。如 NotoSansCJKtc-Regular.otf 是 Sans-Serif。所以,將它的 name 屬性值 Noto Sans CJK TC 插入到 font.sans-serif 列表中的第一個。以此類推,將三個都填入。

font.family:  sans-serif
#font.style:   normal
#font.variant: normal
#font.weight:  normal
#font.stretch: normal
#font.size:    10.0

font.serif:      Noto Serif CJK TC, DejaVu Serif, ...
font.sans-serif: Noto Sans CJK TC, DejaVu Sans, ...
#font.cursive:    Apple Chancery, Textile, ...
#font.fantasy:    Comic Neue, Comic Sans MS, ...
font.monospace:  Noto Sans Mono CJK TC, DejaVu Sans Mono, ...

基本上,這樣就設定完成了。停掉 Jupyter,再重新執行我們最一開始程式,來看看是否可以正確地顯示中文。

正確地顯示中文
正確地顯示中文
發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

You May Also Like