IT · 2022年4月10日 0

如何一键解决matplotlib中文显示问题

matplotlib的中文显示问题是一个老生常谈的话题了,我们在网上也可以查到非常多的解决方案,但是在我看来这些解决方案都过于“手动”不够优雅,而且我身边的业务运行环境基本全部都基于Docker容器化技术实现,对于matplotlib的中文字体设置也必然需要有自动化配置流程,于是大概半年前我写了mplfonts这个包,可以轻松+愉快地一键配置matplotlib中文字体环境。

这个包之前一直是我自己在用,并未考虑兼容性问题,以至于我给身边的朋友说这个包以后,他在自己的电脑上用不了。很长一段时间我也没有管这个事情,最近心血来潮想把它捡起来,于是在GitHub Actions里增加了多系统多版本的CI,修补了一些bug,然后重新更新了版本。目前来看,从我自己测试和CI的测试结果来看应该是OK的,当然还是需要有更多人在实际使用中的反馈才是更真实的。

安装

mplfonts的安装方法是pip: $ pip install -U mplfonts

使用

安装好mplfonts之后,需要有一个初始化的配置过程。有两种方法:

  1. 在终端执行$ mplfonts init即可。
  2. 嵌入初始化代码,在脚本中加入:
from mplfonts.bin.cli import init
init()

以上两种方式的结果是等效的,并且只需要执行一次即可。

完成以上步骤,你就可以享受丝滑的中文字体了。而且默认是Google和Adobe合作设计的开源字体Noto,可以随意使用,无需顾虑版权争议。

我们来看一下例子:

import matplotlib.pyplot as plt
from mplfonts import use_font

FONT_NAMES = {
    'Noto Sans Mono CJK SC': 'Noto等宽',
    'Noto Serif CJK SC': 'Noto宋体',
    'Noto Sans CJK SC': 'Noto黑体',
    'Source Han Serif SC': '思源宋体',
    'Source Han Mono SC': '思源等宽',
    'SimHei': '微软雅黑'
}

def test_chinese():
    for font_name, desc in FONT_NAMES.items():
        use_font(font_name)
        fig = plt.figure(figsize=(4, 1))
        
        ax = plt.Axes(fig, [0., 0., 1., 1.]) 
        ax.set_axis_off()  
        fig.add_axes(ax)
        
        plt.text(.1, .6, font_name, fontsize=20)
        plt.text(.1, .2, desc, fontsize=20)

        plt.show()

test_chinese()

漫谈

其实饱受matplotlib字体显示之苦的并非只有中文,邻国韩国和日本的网友在使用matplotlib的时候也会遇到相同的问题,社区里一般会把这个问题称为“豆腐块(tofu)”,就是说写出来的字是豆腐。

关于豆腐问题,在GitHub上有一个台湾的哥们写了一个包:mpl-tc-fonts,这是一种比较优雅的解决方案,他先下载了Google的Noto CJK开源字体,然后在程序入口自动化地执行命令安装字体,再修改matplotlibrc配置文件以使其生效,最终实现繁体中文的正确显示。但是他的这个包不支持简体中文,而且程序里很多硬编码,不利于更多非英文字体的扩展,于是我就参考他的一些实现方式,写了mplfonts,初期的设计理念是在解决中文字体渲染问题的同时,为其他非拉丁字母语系问题的字体扩展留下余地。

关于Google的开源字体Noto,其名称很有意思,据说是”No tofu“的简写,也就是”不要豆腐块“,是Google与Adobe联合设计的开源字体,由于免费开源且字体优美,目前在网页设计领域已经得到了非常广泛的使用,关于这款字体的更多信息可以去Google搜索。目前我在mplfonts包里集成了Noto CJK字族,衬线体和无衬线体都包含:

  • Noto Sans Mono CJK SC:Noto等宽黑体(无衬线体)
  • Noto Serif CJK SC:Noto宋体(衬线体)
  • Noto Sans CJK SC:Noto黑体(无衬线体)
  • Source Han Serif SC:思源宋体(衬线体)
  • Source Han Mono SC:思源等宽宋体(无衬线体)

其中等宽无衬线字体比较适合于与代码并存的文本环境中,具体选择的看个人喜好。

其实我还偷偷加入了出镜率很高的微软雅黑(SimHei),但是请勿商用以免被方正集团碰瓷

其实mplfonts还有管理字体的功能,更多功能介绍建议查看GitHub上该仓库的README。

如果使用过程中遇到任何问题,可以通过以下方式寻求帮助:

  1. 在GitHub mplfonts仓库的Issue中提交议题,把遇到的问题、报错信息描述清楚,并等待回复。
  2. 关注公众号“Clarmy吱声”,在公众号后台留言,我都会看到。