2020年2月27日 星期四

Python, Matplotlib, 中文字體顯示的問題

雖然網路上有許多篇文章探討,不過最近再碰到這個問題的時候,仍舊看得有點似懂非懂的。

這裡綜合整理一下個人的看法,並且添上一些說明。

關於中文字體的顯示這是新手關卡,幾乎會碰到也幾乎需要解決。

要解決這個問題,首先可對兩個地方進行改善。

一、 系統磁碟:\\使用者\使用者名稱\.matplotlib
二、python環境\Lib\site-packages\matplotlib\mpl-data (如果使用anaconda,環境就是anaconda的資料夾。如果使用visual studio,可以從python環境打開檔案管理員進入資料夾。)


【如果你想增加字體,一定要做的步驟】

首先第一個地方,進入後會發現一個 fontList.json 的檔案,簡單來說,就是 matplotlib 讀取字體的紀錄。如果想要加入新的字體在 matplotlib 的繪圖中顯示,就得刪除  fontList.json ,讓 matplotlib 重新讀取並生成新的 json。萬一沒有刪,這個檔案就不會變更,新增的字體就不會被讀取到。(如果刪了matplotlib的字體,該json檔也會被變更。)

想顯示中文字,也不一定要新增中文字體,你可以用記事本打開來看,其中有一行「"C:\\WINDOWS\\Fonts\\kaiu.ttf",」這表示它讀取到系統字形的 kaiu.ttf,也就是知名的「標楷體」,於是在程式中只要指定字體為標楷體,就可以正常顯示中文。

plt.rcParams['font.sans-serif'] = ['DFKai-SB'] #可以直接用上此行顯示中文字,如果不嫌棄標楷體的話

""" 一定要使用「字體名稱」,不是字檔名kaiu。可以從新生的 json 檔搜尋字檔名(如: kaiu.ttf),會看到有一項 "name": "DFKai-SB",其餘字體也可以找到對應的name。"""


【新增字體】

從第二地方 mpl-data 進入 fonts 再進入 ttf 資料夾,這裡可以丟上你喜歡的字體,從網路上下載的也行。

假設我有一個喜歡的字型,範例字型,把它的 ttf 檔放進來後,去第一地方刪除 fontList.json 然後重載(import matplotlib),然後打開 json 搜尋字檔名 I.Ngaan.ttf ,就會找到該字體的 "name": "I.Ngaan"。

plt.rcParams['font.sans-serif'] = ['I.Ngaan']

這樣就能讓 matplotlib 以這個字體顯示。


【一勞永逸,懶得在程式裡加上那一行】

第二地方有個名為 matplotlibrc 的檔案,可用記事本打開它。搜尋「font.sans-serif」,把字體名,注意!是字體名!要怎麼得知字體名?可由【新增字體】這一部分去了解。在該行的冒號後面加入字體名(範例: I.Ngaan, 或是 DFKai-SB,),然後刪除前方註解(#)。

font.sans-serif     : I.Ngaan,  DFKai-SB,  DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif

至於其他很像的「font.cursive」或是「font.fantasy」,從這裡可以了解他們的意思。

!!接著這裡也可以順便解決另外一個常見的matplotlib的問題「負號無法正常顯示」。

找到解決方法通常是加上一句:
plt.rcParams['axes.unicode_minus']=False

在這個 matplotlibrc 的檔案中,搜尋「axes.unicode_minus」可以找到一句
#axes.unicode_minus  : True

將其改成
axes.unicode_minus  : False

就可以一次解決負號顯示的問題。


會特別紀錄這篇,是因為字體名的關係,網路上有教學如何添加字體,給了範例,卻沒有說為什麼字體名是這個。於是我嘗試用['標楷體']卻失敗,用字檔名['kaiu']也失敗,可是,一定得有一個可以找到對照的地方,搜尋方法,最後從json檔找到答案,。
這些方法與說明是目前我在網路沒有找到的,也許日後還會碰到這問題,到時來到在這裡就能找到解答。
個人是不推薦第三種一勞永逸的解法,因為換台電腦就要再去改寫,實在麻煩。所以推薦使用 ['DFKai-SB'] (標楷體),因為對繁體中文的系統都會自帶這個字體,這樣就不需要額外再改動任何檔案。