注:这是一篇旧文的中文翻译版本。

前不久,我在使用 Matplotlib 画图的时候,发现一些 Unicode 字符(例如,汉字) 无法正常显示:在生成的图片中,汉字是乱码的,显示为一个方框。经过大量的查找和阅读,我终于明白了如何在使用 Matplotlib 时,正确渲染 Unicode 字符1

简单来说,之所以中文字符被显示为方框,是因为 Matplotlib 默认使用的字体并不支持中文字符,并不是 Matplotlib 本身的原因。为了能够在图片上正确显示中文字符,我们需要指示 Matplotlib 使用一种支持中文的字体即可。或者,更直接地,我们在画图时可以直接给 Matplotlib 提供一个中文字体的路径。

本文假设 fc-list 命令安装在你的电脑上。如果你的电脑上没有这个命令,你应该先安装 fontconfig。在 Linux 系统上,这个程序通常是自带的,无需安装;在 Windows 系统上,可以安装 MiKTeXTeX Live 来使用 fc-list 命令。

以下介绍几种在 Matplotlib 中使用中文字符的不同方式。

指定中文字体名称

第一种使用中文的方式是给 Matplotlib 提供一个有效的中文字体名。再开始下面步骤之前,确保你的系统上已经安装了中文字体,如果你使用的是中文系统,这应该不是问题;或者如果你想使用一种新的中文字体,可以尝试 Google 和 Adobe 发布的 Source Han Serif。首先,你需要在系统上安装中文字体2

找到有效的中文字体名

Matplotlib 提供了FontManager 类来处理字体相关的操作。这个类有一个 ttflist 属性,该属性提供了 Matplotlib 所能够发现到的字体列表。从这个字体列表,我们也可以很容易得到这些字体的名称。问题是,我们不清楚这些字体中有哪些字体是支持中文的。

这时候,我们就需要 fc-list 帮助了。这个命令行工具可以帮助我们找到系统上安装的中文字体:使用 fc-list :lang=zh 可以列出系统上可用的中文字体。值得注意的是,这些中文字体并非都可以被 Matplotlib 使用:Matplotlib 无法使用其中的 ttc 格式的字体(参见这里)。所以我们需要得到 Matplotlib 索引的字体和系统提供的中文字体两个集合的交集。

使用字体

找到了 Matplotlib 索引的中文字体以后,我们可以通过更改 Matplotlib rc 指示 Matplotlib 使用中文字体。这样设置以后,后续脚本中的画图语句都会使用新指定的中文字体。加入我们在系统中安装了 STKaiti 这个字体,下面的脚本将会使用这个字体来渲染图片中的中文:

import matplotlib as mpl
font_name = "STKaiti"
mpl.rcParams['font.family']=font_name
mpl.rcParams['axes.unicode_minus']=False # in case minus sign is shown as box

plt.text(0.5, 0.5, s=u'测试')
plt.show()

在上面的代码中,font_name 可以任意一个有效的中文字体名。另外,如果你仅仅想在某个画图命令中使用中文字体,可以在画图命令中指定使用的字体名称,如下所示:

plt.text(0.5, 0.5, s=u'测试', fontname=font_name)

这种方式是我认为比较好的在 Matplotlib 中使用中文的方式。

指定中文字体的具体路径

为了使用系统中的任何字体,我们也可以使用第二种方式:直接给 Matplotlib 提供一个字体的路径。代码如下:

import matplotlib.font_manager as mfm
import matplotlib.pyplot as plt

font_path = "/usr/share/fonts/custom/simhei.ttf"
prop = mfm.FontProperties(fname=font_path)
plt.text(0.5, 0.5, s=u'测试', fontproperties=prop)
plt.show()

上述代码中,变量 font_path 是系统上某个中文字体的绝对路径。

结论

以上提供的两种方式都比较方便实用,我们可以根据自己的实际需要选取使用。要获取完整的代码,可以参考 这里

参考链接


  1. 尽管这篇文章是以中文为例,但是对于其他语言也是同样的道理,只需要相应设置即可。 ↩︎

  2. 如果不清楚如何在不同系统上安装新字体,可以查看 这里这里的指导。 ↩︎