作者Hsins (迅雷不及掩耳盗铃)
看板Python
标题Re: [问题] matplotlib显示中文的问题
时间Thu Nov 5 10:28:48 2020
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://webptt.com/cn.aspx?n=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://webptt.com/cn.aspx?n=bbs/Python/M.1604543332.A.D57.html
1F:→ Hsins: 我在 issue 里面有附上一个连结,不同的浏览器在处理字体 11/05 10:31
2F:→ Hsins: 回退也都是有各自的实作方式,火狐的满认真看待中日韩字元 11/05 10:32
3F:→ Hsins: 的,chromium 很有趣,一部分是写死的。然後我还顺便研究 11/05 10:32
4F:→ Hsins: 了一下在 xeCJK 这个中英混合排版的 xelatex 套件的处理方 11/05 10:33
5F:→ Hsins: 式,跟火狐有点像又有些不同,还有处理一些字元的映射问题 11/05 10:33
6F:→ alvinlin: 你有试过我上次po的方法吗? 其实不用那麽复杂呗 11/05 11:57
你知道我的这个 package 只要 pip install 之後然後 import 就是在做你说的
那些事情吗?除此之外,这样的做法还解决掉了当你今天有多个 Python 运行环
境时,只单独设定了一个的状况。另外其实是对於现在很多人会使用 Google 所
提供的 colab 环境或自己架设的 jupyter notebook server 来跑,只要简单汇
入这个包就好。
当然也不是没有缺点,就是我把七个字体放在包里使得大小有点可观,整体大概
有快要 150M 左右。
文中这些叙述,是希望让有兴趣的人可以知其然也知其所以然。不然你知道为什
麽对於浏览器和作业系统来说可以把中文字体设定加在一串字体的尾端达到中英
文分开设定字体,然而对於 matplotlib 只能将中文字体放置在列表前吗?
※ 编辑: Hsins (1.160.165.198 台湾), 11/05/2020 14:49:18
7F:推 MAGICXX: 不要那麽激动R 11/05 15:16
8F:→ Hsins: 欸斗,我只是打字的时候因为标点和不想添加太多语助词才会 11/05 15:23
9F:→ Hsins: 这样看起来很激动啦... 11/05 15:23
10F:→ alvinlin: 好啦好棒棒。其实我也研究了一会儿才写出上次的文章的。 11/05 20:43
11F:推 art1: 辛苦了,未来应该有机会用到 11/05 22:30
12F:嘘 panex0845: 缓存 11/06 20:04
13F:推 mirror0227: 做成套件太有心 给推 11/07 16:58
14F:推 M013: ☺ 11/09 12:14