背景
- matplotlib繪製圖形、地圖等,需要貼上說明文字時,內設是英數,python 2或matplotlib2時代,對中文確實不太友善,並沒有中文字型。
- 雖然新版的matplotlib已經會自動連結電腦系統的字型,不再需要./matplotlib/fontList.json檔案,但此一筆記也可以應用在需要安裝特定字型情況。
問題
問題有3個層次
- matplotlib的字型有哪些?是否包括了所要的字型?若沒有,是要如何加上、或設為內定字型?
- 如果找不到指定的字型,程式會報錯。(如simhei.ttf not found)
- python程式內如何選取字型的種類?
- python的字型編碼(coding)?與所要讀取檔案(如地圖檔案中的中文字型)的編碼是否能正確解讀、正確轉寫?
- 程式會報錯utf-8…
matplotlib的字型庫與內設參數之設定
顯示所有目前已經載入記憶體的字型
import matplotlib.font_manager
a = sorted([f.name for f in matplotlib.font_manager.fontManager.ttflist])
for i in a:
print(i)
- 字型有很多,可以選擇所要的字型名稱,寫在python程式中設定為圖形輸出的字型。
- 如果列印出的字型都沒有期待中的字型,需要知道字型庫在哪裡,以便增減。
fontList.json
- 第一次執行
import matplotlib
時,系統程式會將字型相關參照寫在$HOME/.matplotlib/fontList.json檔案內(或fontlist-vXXX.json、XXX為版次),包括檔案名稱、字型名稱、寬度、是否可以放大等等,內容如下。
...
993 "fname": "fonts/ttf/NotoSansTC-Thin.otf",
994 "name": "Noto Sans TC",
995 "style": "normal",
996 "variant": "normal",
997 "weight": 250,
998 "stretch": "normal",
999 "size": "scalable",
1000 "__class__": "FontEntry"
...
- 這個檔案不能自行修改,只能閱覽
- 增減字型之後,這個檔案不會自行更新,需手動將其刪除,讓系統程式再去搜尋一遍產生新的json檔。
- 如果是用IDE(包括PyCharm、jupyter、ipython)必須先退出、增減字型後,再重新進入IDE,才會重新搜尋字型。
- json檔中fname只是相對目錄,還必須找到matplotlib之絕對路徑。
字型所在之絕對路徑
- 顯示matplotlib之根目錄,以標定字型檔案所在位置
import matplotlib
print(matplotlib.__file__)
>>> /opt/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/__init__.py
- 輸出
__init__.py
位置設若稱為$root
- 字型檔案將會放在
$root/mpl-data/fonts/ttf
- 所有的內設參數(包括字型等)都放在
$root/mpl-data/matplotlibrc
檔案內
- 字型檔案將會放在
Python Matplotlib 無法顯示中文 (Python初學特訓班、圖表、直線圖) @查理2017
https://codertw.com/程式語言/359974/ https://matplotlib.org/users/text_props.html?highlight=configuring%20font%20family
增減字型
- 因電腦系統字型檔案會有平台版本的差異,為保證顯示上沒有問題,還是以電腦系統現有的字型,安裝到matplotlib可以抓到的位置,這樣比較安全。
找到系統現有的字型
- linux/mac可以執行fc-list列出電腦所有可用的字型,要記住字型的名稱,以便在python程式內正確選取。
$ fc-list :lang=zh family
Heiti TC,黑體\-繁,黒体\-繁,Heiti\-번체,黑体\-繁
STSong
.PingFang HK,.蘋方\-港,.苹方\-港
.PingFang SC,.蘋方\-簡,.苹方\-简
Hiragino Sans GB,冬青黑體簡體中文,ヒラギノ角ゴ 簡体中文,冬青黑体简体中文,冬青黑體簡體中文 W3,Hiragino Sans GB W3,ヒラギノ角ゴ 簡体中文 W3,冬青黑体简体中文 W3
Hiragino Sans GB,冬青黑體簡體中文,ヒラギノ角ゴ 簡体中文,冬青黑体简体中文,冬青黑體簡體中文 W6,Hiragino Sans GB W6,ヒラギノ角ゴ 簡体中文 W6,冬青黑体简体中文 W6
.PingFang TC,.蘋方\-繁,.苹方\-繁
PingFang HK,蘋方\-港,苹方\-港
PingFang SC,蘋方\-簡,苹方\-简
.LastResort
PingFang TC,蘋方\-繁,苹方\-繁
GB18030 Bitmap
Heiti SC,黑體\-簡,黒体\-簡,Heiti\-간체,黑体\-简
.Hiragino Sans GB Interface
Arial Unicode MS
Songti TC,宋體\-繁,宋体\-繁
Songti SC,宋體\-簡,宋体\-简
- 再列出所在的位置與樣式(style,細、粗、正常等),前者在複製檔案時需要知道,後者在python程式內設定時會更精確。
In [18]: !fc-list|grep Songti
/System/Library/Fonts/Supplemental/Songti.ttc: Songti SC,宋體\-簡,宋体\-简:style=Light,細體,细体
/System/Library/Fonts/Supplemental/Songti.ttc: Songti TC,宋體\-繁,宋体\-繁:style=Regular,標準體,常规体
/System/Library/Fonts/Supplemental/Songti.ttc: Songti SC,宋體\-簡,宋体\-简:style=Regular,標準體,常规体
/System/Library/Fonts/Supplemental/Songti.ttc: Songti TC,宋體\-繁,宋体\-繁:style=Light,細體,细体
/System/Library/Fonts/Supplemental/Songti.ttc: Songti SC,宋體\-簡,宋体\-简:style=Black,黑體,黑体
/System/Library/Fonts/Supplemental/Songti.ttc: Songti SC,宋體\-簡,宋体\-简:style=Bold,粗體,粗体
/System/Library/Fonts/Supplemental/Songti.ttc: Songti TC,宋體\-繁,宋体\-繁:style=Bold,粗體,粗体
/System/Library/Fonts/Supplemental/Songti.ttc: STSong:style=Regular,標準體,Ordinær,Normal,Normaali,Regolare,レギュラー,일반체,Regulier,Обычный,常规体
複製與設定
- 將所要增加的字型檔案、從本機原來位置,或自網路下載檔案,複製到前述
$root/mpl-data/fonts/ttf
目錄下 - 修改
$root/mpl-data/matplotlibrc
檔案- 此法不是官網所建議,但許多網友還是這樣做。官網主要考慮的是其他使用者(unix系統)的權益,而網友的實作大多是在PC上,並沒有這層顧慮。只是重灌matplotlib時必須重新再做一遍。
- 將字型名稱增加在指定的rcParam參數位置,如。
font.sans-serif:simhei, ...
python程式內的字型控制
setting eg.
import matplotlib.pyplot as plt
...
plt.text(x0-0.01, y0-0.004, shape.record[3], fontsize=6)
plt.rcParams['font.sans-serif'] = ['Noto Sans CJK TC']
plot_map(sf)
matplotlib.rcParams['font.sans-serif'] = ['Source Han Sans TW', 'sans-serif']
plt.rcParams['font.family'] = 'Microsoft JhengHei UI'
rcParams
The base default font is controlled by a set of rcParams:
rcParam | usage |
---|---|
‘font.family’ | List of either names of font or {‘cursive’, ‘fantasy’, ‘monospace’, ‘sans’, ‘sans serif’, ‘sans-serif’, ‘serif’}. |
‘font.style’ | The default style, ex ‘normal’, ‘italic’. |
‘font.variant’ | Default variant, ex ‘normal’, ‘small-caps’ (untested) |
‘font.stretch’ | Default stretch, ex ‘normal’, ‘condensed’ (incomplete) |
‘font.weight’ | Default weight. Either string or integer |
‘font.size’ | Default font size in points. Relative font sizes (‘large’, ‘x-small’) are computed against this size. |
字型別名與rcParam參數
The mapping between the family aliases ({‘cursive’, ‘fantasy’, ‘monospace’, ‘sans’, ‘sans serif’, ‘sans-serif’, ‘serif’}) and actual font names is controlled by the following rcParams:
family alias | rcParam with mappings |
---|---|
‘serif’ | ‘font.serif’ |
‘monospace’ | ‘font.monospace’ |
‘fantasy’ | ‘font.fantasy’ |
‘cursive’ | ‘font.cursive’ |
{‘sans’, ‘sans serif’, ‘sans-serif’} | ‘font.sans-serif’ |
which are lists of font names.
鄉鎮區中文名稱及邊界之繪製
Wesely之貢獻
- 原始shp檔:內政部
- 程式:WeselyOng(2021)
- 程式修改
- shape檔案存放的位置
- 中文字型
- 新版matplotlib(3.5.3)安裝時已經將電腦系統的字型納入
- 經執行matplotlib.font_manager(顯示matplotlib已建立的字型庫)、以及fc-list(顯示電腦目前有的字型庫),取二者的交集(以devp工作站為例,找到文泉驛共9筆字型)。
- 選取
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei']
即可
- 縣市界
- 因Wesely原作主題是鄉鎮區、刻意(逐筆檢查)未將東沙島畫在範圍內以減小圖幅,應用到繪製縣市界線圖時,此一邏輯會將整個高雄市都排除了。因此需要逐點檢查。此處應用
panda.DataFramne.loc
來篩選 - 縣市界檔案中的中文名稱序位,不是
shape.record[3]
,而是在shape.record[2]
。
- 因Wesely原作主題是鄉鎮區、刻意(逐筆檢查)未將東沙島畫在範圍內以減小圖幅,應用到繪製縣市界線圖時,此一邏輯會將整個高雄市都排除了。因此需要逐點檢查。此處應用
x = [i[0] for i in shape.shape.points[:]]
y = [i[1] for i in shape.shape.points[:]]
df=pd.DataFrame({'x':x,'y':y})
df=df.loc[(df.x>118) & (df.x<123) ].reset_index(drop=True)
x,y=list(df.x),list(df.y)