Matplotlib 中文字體亂碼問題

花了一段時間解決這個問題,發篇文章記錄一下。

嘗試

一開始想到的是字型設定,所以就看一下系統有哪些中文字型:

fc-list :lang=zh

挑一個字體在畫圖前修改 font family:

plt.rcParams['font.family'] = 'Noto Sans CJK TC'

然後就炸了…噴出錯誤訊息:
/usr/local/lib/python3.7/site-packages/matplotlib/font_manager.py:1241: UserWarning: findfont: Font family ['Noto Sans CJK TC'] not found. Falling back to DejaVu Sans.

後來找到「解決 Python 3 Matplotlib 與 Seaborn 視覺化套件中文顯示問題」這篇文章,裡面提供兩種方法,一種是直接套絕對路徑,另一種則是手動去改設定檔,兩個方法對我而言都蠻麻煩的。

解法

想說能不能動到最少的 code 來解決這個問題,於是換個想法,可能是 Matplotlib 沒有找到 fc-list 列出來的字體,所以就來查到底哪些字體是 Matplotlib 吃得到的呢?

於是就找到這篇 stackoverflow:「How can i get list of font family (or Name of Font) in matplotlib
底下的人回答用這個方式可以列出 Matplotlib 找得到的 .ttf 字體:

import matplotlib.font_manager
[f.name for f in matplotlib.font_manager.fontManager.ttflist]

不過列出來很大一串,所以稍微修改一下,用集合去掉重複的:

from matplotlib import font_manager
font_set = {f.name for f in font_manager.fontManager.ttflist}
for f in font_set:
    print(f)

就可以找到所有可用的 font family 了,再也不會被 Falling back to DejaVu Sans 了。

最後找到的是「AR PL UMing CN」這個字體,居然是用 CN 結尾,而沒有 TW 的,真是神奇。但是至少可以用了。

順便提供一段簡單的測試代碼:

from matplotlib import pyplot as plt
plt.rcParams['font.family'] = 'AR PL UMing CN'
plt.text(.5, .5, '中文', fontsize=50)
plt.show()

下面這是我後來用 macOS 補截圖的,字型和上面不一樣,是正常的新細明體 PMingLiU
matplotlib chinese demo