完美解决matplotlib画图中文显示问题
相信有很多人曾经被matplotlib画图的中文显示问题所困扰,包括我自己。每次生产环境发生改变,都会遭遇到这个问题,然后需要花大量的时间在它上边。最可气的是每次遇到的问题不一定一样,上一次使用的方法不一定适用。网上的教程很多,但没有看到一个完整的、必杀的解决方案。
我在花了大量时间进行多次尝试之后,总结出了一套流程,截止目前我遇到过的所有的不同环境下(Linux + Mac)的matplotlib中文显示问题都得到了完美解决,因此整理出来分享给大家,希望能让大家少走弯路,把时间花在更有价值的地方。
刚好我购置了一台腾讯云的服务器,我们就拿它为例,看一下如何配置。
首先我们安装好Python3+matplotlib,然后进入Python,画一张图来看看效果:
import matplotlib.pyplot as plt
plt.plot([1,3,2,4], '--r')
plt.title(u'测试')
plt.savefig('temp.png')
![](https://img.haomeiwen.com/i14318844/072564cebae39b58.jpg)
可以看到虽然我们为title
设置了中文“测试”,但实际上显示出来的却是两个方框。好,那我们就开始解决这个问题。
第一步:确认系统字体
我们在命令行中通过fc-list :lang=zh
来查看下系统是否有安装中文字体。
# root @ VM_0_16_centos in ~ [14:20:29]
$ fc-list :lang=zh
# root @ VM_0_16_centos in ~ [14:22:01]
$
我们看到输出为空,这说明我们的Linux系统暂时没有安装中文字体,我们需要进行安装。老版本有很多种安装方法,有一些甚至需要root权限,这一点很不友好。因为很多朋友的服务器是公司提供的,出于安全考虑,普通技术员工并没有root权限。
好在现在绝大多数的linux版本都已经可以非常快速地通过复制文件的方式来安装字体了。
我们先下载喜欢的中文字体,比如黑体、楷体和微软雅黑。下载好之后,我们将文件上传到服务器,并移动到个人目录下的.fonts
文件夹内。
然后,我们再检查一下:
# root @ VM_0_16_centos in ~ [14:27:46]
$ fc-list :lang=zh
/root/.fonts/msyh.ttf: 微软雅黑,Microsoft YaHei:style=Regular
/root/.fonts/simhei.ttf: 黑体,SimHei:style=Regular,Normal,obyčejné,Standard,Κανονικά,Normaali,Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,Arrunta
/root/.fonts/simkai.ttf: 楷体_GB2312,KaiTi_GB2312:style=Regular
可以看到,我们已经成功地将三个中文字体安装到了系统中,是不是很简单快速?
第二步:安装matplotlib字体支持
接下来我们要在matplotlib中安装中文字体(这一步在有些教程里是不需要的,但是时灵时不灵,我们最好也安装一下。),这一步需要我们先确认字体的安装目录。
In [9]: import matplotlib as mpl
In [10]: mpl.matplotlib_fname()
Out[10]: '/usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc'
我们看到了matplotlib的配置文件的地址,记住这个地址,后边修改配置时要用到。现在我们用它来定位字体文件夹。我们进入配置文件所在目录:
# root @ VM_0_16_centos in ~ [14:41:22] C:1
$ cd /usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data/
# root @ VM_0_16_centos in /usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data [14:41:24]
$ ll
总用量 52K
drwxr-xr-x 5 root root 4.0K 11月 30 14:03 fonts
drwxr-xr-x 2 root root 4.0K 11月 30 14:03 images
-rw-r--r-- 1 root root 33K 11月 30 14:03 matplotlibrc
drwxr-xr-x 3 root root 4.0K 11月 30 14:03 sample_data
drwxr-xr-x 2 root root 4.0K 11月 30 14:03 stylelib
# root @ VM_0_16_centos in /usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data [14:41:25]
$ cd fonts
# root @ VM_0_16_centos in /usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data/fonts [14:41:29]
$ ll
总用量 12K
drwxr-xr-x 2 root root 4.0K 11月 30 14:03 afm
drwxr-xr-x 2 root root 4.0K 11月 30 14:03 pdfcorefonts
drwxr-xr-x 2 root root 4.0K 11月 30 14:03 ttf
# root @ VM_0_16_centos in /usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data/fonts [14:41:31]
$ cd ttf
# root @ VM_0_16_centos in /usr/local/lib64/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf [14:41:33]
$ ll
总用量 6.7M
-rw-r--r-- 1 root root 26K 11月 30 14:03 cmb10.ttf
-rw-r--r-- 1 root root 21K 11月 30 14:03 cmex10.ttf
-rw-r--r-- 1 root root 32K 11月 30 14:03 cmmi10.ttf
-rw-r--r-- 1 root root 26K 11月 30 14:03 cmr10.ttf
-rw-r--r-- 1 root root 20K 11月 30 14:03 cmss10.ttf
-rw-r--r-- 1 root root 29K 11月 30 14:03 cmsy10.ttf
-rw-r--r-- 1 root root 28K 11月 30 14:03 cmtt10.ttf
......
好了,接下来我们将刚才的字体文件复制过来即可。
第三步:修改matplotlib配置文件
我们先关闭所有的Python程序,包括Python、IPython、Jupyter等,因为一会儿修改完之后需要清空缓存并重启程序生效。
还记得刚才的matplotlibrc的地址吧,我们用趁手的文本编辑器打开它,去掉如下三行开头的注释符,并在font.sans-serif的取值中,将我们刚才三个字体的英文名称添加到最前边。英文名称在我们刚才使用fc-list :lang=zh
时可以看到。
axes.unicode_minus : True
font.family : sans-serif
font.sans-serif : Microsoft YaHei, SimHei, KaiTi_GB2312, DejaVu Sans, Bitstream Vera Sans, ...
保存退出。
这一步需要注意的是,如果你的系统中存在多个Python环境,那一定要确保你安装的字体以及修改的配置文件是你要使用的那一个环境中的。
第四步:删除缓存
不删除缓存的话,在代码中指定字体文件或字体名称理论上也可以使用,但这样太麻烦 ,我们要解决就解决彻底。
一般情况下,缓存在~/.cache/matplotlib
目录下,但也有些会在~/.matplotlib
目录下(我的Mac是这样的),不管在哪里,我们直接清除掉这个目录即可。
rm -rf ~/.cache/matplotlib
或者
rm -rf ~/.matplotlib
第五步:重启Python程序
现在我们重新打开我们的Python程序,检查一下是否已经好了。
import matplotlib.pyplot as plt
plt.plot([1,3,2,4], '--r')
plt.title(u'测试')
plt.savefig('temp.png')
![](https://img.haomeiwen.com/i14318844/dc003082c9c107f1.jpg)
大功告成,我们的title
成功地显示出来了。
第六步:针对Python2的补充
另外说一点,由于Python2默认的编码方式并不是UTF-8
,因此在Python2中,我们要在字符串之前添加u
,强制将字符串以Unicode方式编码。如上例,在Python2中,我们应该使用u"测试"
。
以上就是我梳理的完整的解决流程,如有严格按照此流程操作仍不能解决的,可以联系我,我们一起探讨。