DEV Community

codemee
codemee

Posted on • Edited on

21

matplotlib 顯示中文

matplotlib 預設的字型並不是中文字型, 所以顯示中文會變成方框, 像是這個例子:



>>> import matplotlib.pyplot as plt
>>> plt.pie(
... [800, 300, 400],
... labels=['交通', '娛樂', '教育'])
([<matplotlib.patches.Wedge object at 0x000001CB83DFC250>, <matplotlib.patches.Wedge object at 0x000001CB83DFC700>, <matplotlib.patches.Wedge object at 0x000001CB83DFCB80>], [Text(-0.11498140519131439, 1.093974074857458, '交通'), Text(-0.7360435164738056, -0.8174594435547703, '娛樂'), Text(0.7360438608860855, -0.817459133444544, '教育')])


Enter fullscreen mode Exit fullscreen mode

顯示時會出現訊息告知目前的字型沒有 CJK 文字, 其中 4EA4 等等就是個別中文字的 unicode:



>>> plt.show()
D:\Program Files\Python310\lib\tkinter\__init__.py:839: UserWarning: Glyph 20132 (\N{CJK UNIFIED IDEOGRAPH-4EA4}) missing from current font.func(*args)
D:\Program Files\Python310\lib\tkinter\__init__.py:839: UserWarning: Glyph 36890 (\N{CJK UNIFIED IDEOGRAPH-901A}) missing from current font.func(*args)
D:\Program Files\Python310\lib\tkinter\__init__.py:839: UserWarning: Glyph 23067 (\N{CJK UNIFIED IDEOGRAPH-5A1B}) missing from current font.func(*args)
D:\Program Files\Python310\lib\tkinter\__init__.py:839: UserWarning: Glyph 27138 (\N{CJK UNIFIED IDEOGRAPH-6A02}) missing from current font.func(*args)
D:\Program Files\Python310\lib\tkinter\__init__.py:839: UserWarning: Glyph 25945 (\N{CJK UNIFIED IDEOGRAPH-6559}) missing from current font.func(*args)
D:\Program Files\Python310\lib\tkinter\__init__.py:839: UserWarning: Glyph 32946 (\N{CJK UNIFIED IDEOGRAPH-80B2}) missing from current font.func(*args)


Enter fullscreen mode Exit fullscreen mode

實際顯示畫面如下:

設定使用中文字體

不過其實系統本身已經有中文字型, 可以透過 fontManager 物件來檢視, 它會列出系統字型資資料夾下的字型:



>>> from matplotlib.font_manager import fontManager
>>> for i in sorted(fontManager.get_font_names()):
...     print(i)
Agency FB
Algerian
...
Microsoft JhengHei
Microsoft New Tai Lue
Microsoft PhagsPa
Microsoft Sans Serif
Microsoft Tai Le
Microsoft YaHei
Microsoft Yi Baiti
MingLiU
MingLiU-ExtB
...


Enter fullscreen mode Exit fullscreen mode

只要使用 matplotlib 模組的 rc() 函式, 就可以改用任何一種字型, 例如:



>>> import matplotlib
>>> matplotlib.rc('font', family='Microsoft JhengHei')


Enter fullscreen mode Exit fullscreen mode

這樣就可以改用微軟正黑體, 重新產生圓餅圖顯示:



>>> plt.pie(
... [800, 300, 400],
... labels=['交通', '娛樂', '教育'])
([<matplotlib.patches.Wedge object at 0x000001CB87E615D0>, <matplotlib.patches.Wedge object at 0x000001CB833A72E0>, <matplotlib.patches.Wedge object at 0x000001CB87E63310>], [Text(-0.11498140519131439, 1.093974074857458, '交通'), Text(-0.7360435164738056, -0.8174594435547703, '娛樂'), Text(0.7360438608860855, -0.817459133444544, '教育')])

>>> plt.show()


Enter fullscreen mode Exit fullscreen mode

就可以看到正確顯示中文的圖形了:

修改 rcParams 物件

剛剛的 rc 函式修改的其實是 matplotlib 模組的 rcParams 字典物件, 你也可以直接修改設定, 例如:



>>> matplotlib.rcParams['font.family'] = 'MingLiU'
>>> plt.pie(
... [800, 300, 400],
... labels=['交通', '娛樂', '教育'])
([<matplotlib.patches.Wedge object at 0x0000021F3E56BC40>, <matplotlib.patches.Wedge object at 0x0000021F3EE44910>, <matplotlib.patches.Wedge object at 0x0000021F3E569BD0>], [Text(-0.11498140519131439, 1.093974074857458, '交通'), Text(-0.7360435164738056, -0.8174594435547703, '娛樂'), Text(0.7360438608860855, -0.817459133444544, '教育')])

>>> plt.show()


Enter fullscreen mode Exit fullscreen mode

就會將字型改為明體:

使用 rc 函式的好處是同時可以更改多項設定, 例如若要將字體改回之前的黑體, 同時又想要將字體變大, 就可以這樣做:



>>> matplotlib.rc('font',
...     family='Microsoft JhengHei',
...     size=32
... )
>>> plt.pie(
... [800, 300, 400],
... labels=['交通', '娛樂', '教育'])
([<matplotlib.patches.Wedge object at 0x0000021F3E51D000>, <matplotlib.patches.Wedge object at 0x0000021F3E51EE60>, <matplotlib.patches.Wedge object at 0x0000021F3E51EAD0>], [Text(-0.11498140519131439, 1.093974074857458, '交通'), Text(-0.7360435164738056, -0.8174594435547703, '娛樂'), Text(0.7360438608860855, -0.817459133444544, '教育')])

>>> plt.show()


Enter fullscreen mode Exit fullscreen mode

要注意的是使用 rcParams 字典物件時, 索引鍵是功能分類.細項名稱 這樣的格式, 但叫用 rc 函式時, 則是 rc('功能分類', 細項名稱=) 的參數格式。

附帶一題, matplotlib 模組的 rcParams 和 matplotlib.pyplot 模組的 rcParams 引用的是同一個物件, 由以下程式可以確認:



>>> matplotlib.rcParams is matplotlib.pyplot.rcParams
True


Enter fullscreen mode Exit fullscreen mode

這樣做只是方便大家使用而已。

matplotlibrc 設定檔

如果你希望儲存上述設定, 不需要每次都重新在程式中設定, 也可以將設定寫入 matplotlibrc 檔, 目前使用的設定檔路徑可以由以下程式取得:



>>> matplotlib.matplotlib_fname()
'D:\\code\\pytest\\lib\\site-packages\\matplotlib\\mpl-data\\matplotlibrc'


Enter fullscreen mode Exit fullscreen mode

這是在我的虛擬環境的 matplotlib 安裝資料夾下, 預設內容所有設定都被註解, 並有加上許多解說, 你可以複製到當前目錄下, 然後修改其中的設定, 例如:

存檔後, 在重新回到 Python 下匯入 matplotlib 模組, 就可以看到預設的字型已經更改了:



>>> import matplotlib
>>> matplotlib.rcParams['font.family']
['Microsoft JhengHei']


Enter fullscreen mode Exit fullscreen mode

在 Windows 下你也可以將這個設定檔放到使用者家目錄的 .matplotlib 資料夾下, 這樣不論你在哪個目錄下, 都會採用設定檔中的設定。

如果是 *nix 系統, 就要複製到家目錄下的 .config/matplotlib 下。

用更具彈性的方式

matplotlib 提供有比較彈性的機制, 可以讓你快速變換字型, 並且在找不到指定的字型可用時, 依序採用替補的字型。這項功能藉助 serif、sans-serif、cursive、fantasy、monospace 這 5 種通用字型, 這每一種通用字型都可以指定實際要採用的字型清單, 實際使用時只要設定要用哪一種通用字型即可。舉例來說:



>>> matplotlib.rc('font',
...     family='serif',
...     serif=['ABC', 'MingLiU'],
...     size=32
... )


Enter fullscreen mode Exit fullscreen mode

這裡我們設定 serif 通用字型實際上要用的字型是 ABC 字型, 如果執行時候找不到 ABC 行, 就改用清單中的下一個, 也就是 MingLiu 字型。另外, 我們也設定 font.family 是 serif 字型, 如此執行前面一樣的圓餅圖, 就會因為找不到 ABC 字型而依照上述設定套用明體字型了。

這個機制等於可以讓你設定 5 組字型清單, 並可隨時替換, 也可以透過字型清單因應不同平台套用不同的系統預設字型, 像是在 Mac 上預設並不會有微軟的字型, 就可以在字型清單中加入 Mac 對應的字型, 就不會因為找不到字型而顯示錯誤的結果了。

暫時替換字型

如果想要在同一張圖上使用不同字體, 可以善用 matplotlib 或是 matplotlib.pyplot 模組都有的 rc_context() 函式, 像是這樣:



>>> plt.rc('font', family='MingLiu')
>>> with plt.rc_context(rc= {'font.family': 'Microsoft JhengHei'}):
...     plt.title("圓餅圖")
>>> plt.pie(
... [800, 300, 400],
... labels=['交通', '娛樂', '教育'])
([<matplotlib.patches.Wedge object at 0x0000025D64A0AA10>, <matplotlib.patches.Wedge object at 0x0000025D64A217E0>, <matplotlib.patches.Wedge object at 0x0000025D64A234F0>], [Text(-0.11498140519131439, 1.093974074857458, '交通'), Text(-0.7360435164738056, -0.8174594435547703, '娛樂'), Text(0.7360438608860855, -0.817459133444544, '教育')])

>>> plt.show()


Enter fullscreen mode Exit fullscreen mode

你可以看到一開始先設定使用明體, 然後透過 rc_context() 與 with 合用, 暫時改用黑體標示標題文字, with 結束後會自動變回使用明體, 因此圓餅圖上的文字就變成明體了。

加入額外的中文字型

如果想要使用系統沒有的字型, 但不想將字型安裝到系統上;或是要使用有安裝、但是沒有放在系統字型資料夾下的字型, 可以透過 fontManager 的 addFont() 方法新增, 例如把上述的圓餅圖改成韓文:



>>> plt.pie(
... [800, 300, 400],
... labels=['교통', '오락', '기르다'])


Enter fullscreen mode Exit fullscreen mode

就會因為系統沒有韓文字型又顯示成方塊了:

利用 addfont() 方法, 就可以動態加入額外的韓文字型, 我將這個字型下載後儲存在 d:\temp 資料夾下:



>>> fontManager.addfont('D:\\temp\\NotoSerifKR-Regular.otf')
>>> for i in sorted(fontManager.get_font_names()):
...     print(i)
Agency FB
...
Noto Serif CJK TC
Noto Serif KR
Noto Serif TC
...


Enter fullscreen mode Exit fullscreen mode

再設定使用這個韓文字型:



>>> matplotlib.rc('font', family='Noto Serif KR')
>>> plt.pie(
... [800, 300, 400],
... labels=['교통', '오락', '기르다'])
([<matplotlib.patches.Wedge object at 0x000001CB88634340>, <matplotlib.patches.Wedge object at 0x000001CB88636050>, <matplotlib.patches.Wedge object at 0x000001CB88635750>], [Text(-0.11498140519131439, 1.093974074857458, '교통'), Text(-0.7360435164738056, -0.8174594435547703, '오락'), Text(0.7360438608860855, -0.817459133444544, '기르다')])

>>> plt.show()


Enter fullscreen mode Exit fullscreen mode

就可以正常顯示了:

結語

搞定中文, 你用 matplotlib 繪製的圖表就更親近使用者, 也更易閱讀, 希望這篇文章的內容可以幫到大家。

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs