Re: [問題] matplotlib顯示中文的問題

看板Python作者 (迅雷不及掩耳盜鈴)時間3年前 (2020/11/05 10:28), 3年前編輯推噓3(419)
留言14則, 7人參與, 3年前最新討論串3/4 (看更多)
tl;dr 長話短說,我弄了個套件只要 import 就能夠將思源繁中字體的三個常見字重和 cwTeX 開源字體設定好,額外設定也不難。 https://github.com/Hsins/mpl-tc-fonts 有興趣的可以慢慢看一下下面的內容,反正我禮拜一晚上追了一下,發現很多人 會隨便亂設定跟書上亂講是有情有可原的,並沒有想像中容易。 ---- 上禮拜剛好有朋友又問到這個問題,索性就跑去看了一下 matplotlib 關於字體 設定部分的原始碼。對整個 matplotlib 來說,字體渲染其實並不是一個那麼好 處理的部分,特別是當考慮到廣大的中日韓字元(CJK characters)使用者的時 候... 多數人卡關的其實是關於 matplotlib 字體緩存的部分,說穿了其實就是套件本 身會持有一個 FontList 去管理已知可用的字體,並且在自己的資料夾下面保有 字體檔的緩存,但這樣其實並不是一個節省空間的作法(系統字體倉庫有一份, 而我自己套件倉庫下又多存一份),所以在 2.0.0版本之後提供了直接使用字體 檔案路徑,添加進 FontList 以便使用時查找。 不過這一個階段又有人卡關了,因為必須提供字體檔案的絕對路徑,有一大部分 的使用者由於使用的作業系統有所不同,路徑的表達方式也有所不同,這一個問 題在早期使用 os 套件庫時會有些小問題,不過在 Python 3 之後提供了好用的 pathlib 可以簡單又優雅地處理路徑在不同作業系統下表達方式不同的問題。 然而接下來又會撞到下一個關卡,就是設定 matplotlib 下繪圖的字體設定,在 官方文件裡面說: You can explicitly set which font family is picked up for a given font style (e.g., 'serif', 'sans-serif', or 'monospace'). In the example below, we only allow one font family (Tahoma) for the sans-serif font style. The default family is set with the font.family rcparam, e.g. ```python rcParams['font.family'] = 'sans-serif' ``` and for the font.family you set a list of font styles to try to find in order: ```python rcParams['font.sans-serif'] = ['Tahoma', 'DejaVu Sans', 'Lucida Grande', 'Verdana'] ``` 問題到了這裡,其實並沒有解決!在這裡上面的 'font.family' 是告訴繪圖的 套件我可以選用哪些字體族,比如此處只從 'sans-serif' 字體族去找字體, 於是我還必須在 'font.sans-serif' 字體族設定裡面去添加我的中文字體才能 滿足需求。 很多教學文章在這裡就全部亂了套,這些文章東抄西抄大概也沒有認真去看一下 問題到底在哪。比如把中文字體直接放在了 'font.family' 裡面,又或者是沒 有在 'font.family' 裡面添加 'serif' 就把中文字體添加到 'font.serif' 中 ,一點用處也沒有。 然而即使把中文字體添加到上述的 'font.san-serif' 中了,問題也未必能夠解 決!因為還有一個關卡就是在這個字體列表中的字體順序。這邊必須特別提出來 講的原因就是 matplotlib 沒有實作字體回退(font fallback) 的機制,然而 字體設定又給你一個列表,多數人會誤以為這邊的運作機制和瀏覽器中的字體設 定一樣: https://www.ptt.cc/bbs/Web_Design/M.1279032453.A.80B.html 不不不!並不是這樣的,在 matplotlib 的認知裡面,這個字體列表並不是用來 「依序套用」字體的順序列表,是拿來「依序尋找」字體的順序列表,所以如果 字體列表中的第一個字體能夠在他維護的 FontList 中找到並且路徑有效,就會 用從頭到尾都用這個字體,如果這個字體是拉丁字符集,那麼遇到中日韓字符自 然會變成方塊(也就是俗稱的豆腐)。有興趣幫忙實作的可以追一下這個 issue : https://github.com/matplotlib/matplotlib/issues/18883 最後還請大家幫我測試一下有沒有什麼大問題 雖然沒什麼技術含量的一個 package.... -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.160.165.198 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Python/M.1604543332.A.D57.html

11/05 10:31, 3年前 , 1F
我在 issue 裡面有附上一個連結,不同的瀏覽器在處理字體
11/05 10:31, 1F

11/05 10:32, 3年前 , 2F
回退也都是有各自的實作方式,火狐的滿認真看待中日韓字元
11/05 10:32, 2F

11/05 10:32, 3年前 , 3F
的,chromium 很有趣,一部分是寫死的。然後我還順便研究
11/05 10:32, 3F

11/05 10:33, 3年前 , 4F
了一下在 xeCJK 這個中英混合排版的 xelatex 套件的處理方
11/05 10:33, 4F

11/05 10:33, 3年前 , 5F
式,跟火狐有點像又有些不同,還有處理一些字元的映射問題
11/05 10:33, 5F

11/05 11:57, 3年前 , 6F
你有試過我上次po的方法嗎? 其實不用那麼複雜唄
11/05 11:57, 6F
你知道我的這個 package 只要 pip install 之後然後 import 就是在做你說的 那些事情嗎?除此之外,這樣的做法還解決掉了當你今天有多個 Python 運行環 境時,只單獨設定了一個的狀況。另外其實是對於現在很多人會使用 Google 所 提供的 colab 環境或自己架設的 jupyter notebook server 來跑,只要簡單匯 入這個包就好。 當然也不是沒有缺點,就是我把七個字體放在包裡使得大小有點可觀,整體大概 有快要 150M 左右。 文中這些敘述,是希望讓有興趣的人可以知其然也知其所以然。不然你知道為什 麼對於瀏覽器和作業系統來說可以把中文字體設定加在一串字體的尾端達到中英 文分開設定字體,然而對於 matplotlib 只能將中文字體放置在列表前嗎? ※ 編輯: Hsins (1.160.165.198 臺灣), 11/05/2020 14:49:18

11/05 15:16, 3年前 , 7F
不要那麼激動R
11/05 15:16, 7F

11/05 15:23, 3年前 , 8F
欸斗,我只是打字的時候因為標點和不想添加太多語助詞才會
11/05 15:23, 8F

11/05 15:23, 3年前 , 9F
這樣看起來很激動啦...
11/05 15:23, 9F

11/05 20:43, 3年前 , 10F
好啦好棒棒。其實我也研究了一會兒才寫出上次的文章的。
11/05 20:43, 10F

11/05 22:30, 3年前 , 11F
辛苦了,未來應該有機會用到
11/05 22:30, 11F

11/06 20:04, 3年前 , 12F
緩存
11/06 20:04, 12F

11/07 16:58, 3年前 , 13F
做成套件太有心 給推
11/07 16:58, 13F

11/09 12:14, 3年前 , 14F
11/09 12:14, 14F
文章代碼(AID): #1VesDarN (Python)
文章代碼(AID): #1VesDarN (Python)