2018年8月7日 星期二

讓 matplotlib 和 seaborn 支援中文


核心概念:


  • 支援中文其實就是想辦法讓系統支援 CJK 字型;所以本質上是「換字型」的方法。用 "customized font" 當關鍵字下去找,會比「中文 支援 matplotlib」的資料豐富。
  • 想辦法讓 matplotlib 有對應的 CJK 字型、並且在畫圖的時候找得到那些字型
  • matplotlib 可以說是 seaborn 的底層元件



所以實做上會是:

  • 確認系統某處有中文字型,或是怎麼準備需要的字型檔案。
    • matplotlib 吃 ttf
    • 指令 fc-list :lang=zh or fc-cache -fv
  • 搞清楚 matplotlib 要讀的字型要放哪裡
  • 搞清楚 matplotlib 可以怎麼讀
  • 討清楚 matplotlib 讀到的字型,可能是怎麼傳遞給 seaborn


查看系統中字型


查看字型(限 zh)
fc-list :lang=zh

查看字型快取
fc-cache -fv

查看 matplotlib 讀得到的字型


from matplotlib.font_manager import FontManager
import subprocess
fm = FontManager()
mat_fonts = set(f.name for f in fm.ttflist)
可以參考這個 gist

#!/usr/bin/env python3
from matplotlib.font_manager import FontManager
import subprocess
fm = FontManager()
mat_fonts = set(f.name for f in fm.ttflist)
output = subprocess.check_output(
'fc-list :lang=zh -f "%{family}\n"', shell=True)
output = output.decode('utf-8')
zh_fonts = set(f.split(',', 1)[0] for f in output.split('\n'))
available = mat_fonts & zh_fonts
print('*' * 10, '系統中的字體', '*' * 10)
print(zh_fonts)
print('*' * 10, 'matplotlib 讀到的字體', '*' * 10)
print(mat_fonts)
print('*' * 10, '可用的字體 - 系統中和 matplotlib 讀到的字體交集', '*' * 10)
for f in available:
print(f)
view raw list-fonts.py hosted with ❤ by GitHub



存放 matplotlib 讀得到的字型的地方


/usr/share/fonts/truetype/arphic

或是

site-packages/matplotlib/mpl-data/fonts/ttf

因為吃 ttf,而現在很多字型已經是 ttc 這種格式(把好幾個 ttf 打包起來),所以可以將系統中的中文字型抽出來放進上述目錄裡。這支小程式可以幫忙做這種轉檔


"""Convert TTC font to TTF using fontforge with python extension.
**Warning** The scripts saves splitted fonts in the current working directory.
Usage:
split_ttc_font_to_ttf.py Droid.ttc
Preinstallation: apt-get install python-fontforge
"""
import sys
import fontforge
fonts = fontforge.fontsInFile(sys.argv[1])
for fontName in fonts:
font = fontforge.open('%s(%s)'%(sys.argv[1], fontName))
font.generate('%s.ttf'%fontName)
font.close()



讓 matplotlib 開始讀字型


注意,每一次的新增刪減字型,都要把快取移除,新的狀態才會生效

rm -fr ~/.cache/matplotlib

每一次使用的時候決定要使用的字型

new_fonts = ['AR PL UKai TW'] + mpl.rcParams['font.sans-serif']
mpl.rcParams['font.sans-serif'] = new_fonts

或是可以調整 site-packages/matplotlib/mpl-data/matplotlibrc 來選定每次的預設字型(沒有好好試過)


seaborn 上的字型


對 seaborn 操作後,matplotlib 字型設定會回到預設值。要再調整過。










Ref:

https://newtoypia.blogspot.com/2018/08/matplotlib-ttc.html

https://scentellegher.github.io/visualization/2018/05/02/custom-fonts-matplotlib.html

https://monkey0105.github.io/2016/10/10/matplotlib-chinese-display/

https://medium.com/@aitmr1234567890/%E8%A7%A3%E6%B1%BApython-3-matplotlib%E8%88%87seaborn%E8%A6%96%E8%A6%BA%E5%8C%96%E5%A5%97%E4%BB%B6%E4%B8%AD%E6%96%87%E9%A1%AF%E7%A4%BA%E5%95%8F%E9%A1%8C-f7b3773a889b

沒有留言:

張貼留言