Matplotlib在Mac M1芯片绘图中文显示异常问题

最近需要用到matplotlib.pyplot库使用Python对一些数据进行绘图操作, 发现在Apple M1 芯片的Mac上, 中文显示异常, 写篇博文记录一下解决过程, 直达链接

环境情况

环境 配置
硬件及操作系统 Mac 2021 with M1 Pro chip
MacOS Monterey 12.4
系统
IDE Pycharm 2022.1.1 Professional
IDE
Python环境 Anaconda 2.2.0
Anaconda
Python 3.9.12
Matplotlib版本 matplotlib==3.5.2

问题展现

使用plt绘图的时候, 如果图表中含有中文会显示异常, 变为□, 如下图

中文显示异常

解决过程

修改支持中文的字体 plt.rcParams['font.sans-serif']=['SimHei']

解决matplotlib中文显示问题Font family [sans-serif] not found_ve2102388688的博客-CSDN博客_font.sans-serif

1
2
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

结果: 失败

1
2
findfont: Font family ['sans-serif'] not found. Falling back to DejaVu Sans.
findfont: Generic family 'sans-serif' not found because none of the following families were found: SimHei

提示SimHei字体未找到

修改添加字体支持

解决使用matplotlib.pyplot画图包含中文乱码显示问题(macbook上 family ‘sans-serif‘ not found 问题)_zzzxydq的博客-CSDN博客_pyplot中文乱码

结果: 未尝试

用法过于复杂, 不利于复现, 并且如果代码迁移到其他IDE或环境需要重新设置

修改支持中文的字体 plt.rc("font",family="AR PL UKai CN")

【python】matplotlib绘图显示不了中文,且没有SimHei、FangSong等字体_-徐徐图之-的博客-CSDN博客_python simhei

1
plt.rc("font",family="AR PL UKai CN")

结果: 失败

1
findfont: Font family ['AR PL UKai CN'] not found. Falling back to DejaVu Sans.

提示AR PL UKai CN字体未找到

导入pylab包

python中pyplot图表中文正常显示_航院小将的博客-CSDN博客_pyplot中文

1
from pylab import *

结果: 失败

1
2
findfont: Font family ['sans-serif'] not found. Falling back to DejaVu Sans.
findfont: Generic family 'sans-serif' not found because none of the following families were found: SimHei

提示SimHei字体未找到

使用matplotlib.rc修改默认字体

python中pyplot图表中文正常显示_航院小将的博客-CSDN博客_pyplot中文

1
2
3
# 预设字体格式,并传给rc方法
font = {'family': 'SimHei', "size": 24}
matplotlib.rc('font', **font) # 一次定义终身使用

结果: 失败

1
2
findfont: Font family ['sans-serif'] not found. Falling back to DejaVu Sans.
findfont: Generic family 'sans-serif' not found because none of the following families were found: SimHei

提示SimHei字体未找到

使用font_manager类

python中pyplot图表中文正常显示_航院小将的博客-CSDN博客_pyplot中文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
# 使用matplotlib下的font_manager
from matplotlib import font_manager
# 实例化 font_manager
my_font = font_manager.FontProperties(family='SimHei', size=24)
x = [1, 2, 3, 4, 5]
# 字体大小设置在my_font实例里面了,因为默认的是12,如果在下面设置无效
plt.title("直线", fontproperties=my_font) # 加上font类
plt.plot(x, x)
plt.xlabel("x 轴", fontproperties=my_font) # 需要在每一个使用汉字的地方加上
plt.ylabel("y 轴", fontproperties=my_font)

————————————————
版权声明:本文为CSDN博主「航院小将」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qi_yue_yu/article/details/90668030

结果: 未尝试

理论上与rc或pylab包方式一样, 无法解决字体不存在的问题

修改支持中文的字体 plt.rcParams['font.sans-serif'] = ['Heiti TC']

python - How to plot a figure with Chinese Characters in label - Stack Overflow

1
plt.rcParams['font.sans-serif'] = ['Heiti TC']

结果: 成功

该字体默认存在, 可以正确显示中文字符

中文字符正确显示

图片保存空白

执行plt.savefig(1.jpg)后, 图片显示空白, 问题出在plt.show()之后保存, 会新建一个空白画板, 因此需要先执行plt.savefit()再执行plt.show()即可解决

【Python】解决使用 plt.savefig 保存图片时一片空白_secsilm的博客-CSDN博客_plt.sav

Docker容器内中文异常

🆙 2022-07-13 15:50:28

上面的方法本地部署是可以用的, 但是放到容器中就不行了, 容器中缺少字体支持

通过阅读知乎1的答案, 进入容器查看一下mathplotlib的默认字体

1
2
3
4
5
6
7
8
9
# 查询当前系统所有字体
from matplotlib.font_manager import FontManager
import subprocess

mpl_fonts = set(f.name for f in FontManager().ttflist)

print('all font list get from matplotlib.font_manager:')
for f in sorted(mpl_fonts):
print('\t' + f)
没有中文字体支持

上面是我在python:3.9-slim的基础镜像中执行的结果, 通过知乎2的另一篇文章确认: 没有能支持中文的字体, 其中推荐了以下几类字体

1
2
3
4
5
6
7
8
goodfont=[
'Adobe Heiti Std',
'Arial Unicode MS',
'DengXian',
'SimHei',
'STKaiti',
'STXihei',
]

个人觉得SimHei是一个不错的选择, 而且很容易下载到👉🏻SimHei免费字体下载 - 英文字体免费下载尽在字体家

阅读了简书3和CSDN4的博文, 提示可以通过添加font_manger.FontProperties(fname=<FONT_PATH.ttf>)实现自定义字体的方法

1
2
3
4
5
6
7
8
9
import matplotlib.font_manager as ftm

font_props = ftm.FontProperties(fname=config.FONT_PATH)
plt.rcParams['axes.unicode_minus'] = False
plt.xlabel(f'{current_date}月', fontproperties=font_props)
plt.ylabel('气温(℃)', fontproperties=font_props)
plt.legend(['最高温度', '最低温度'], fontproperties=font_props)
plt.xticks(date)
plt.title('最近几天温度变化趋势', fontproperties=font_props)

上面的代码会报错

legend不支持fontproperties参数

legend不支持fontproperties参数, 修改一下代码

1
2
#plt.legend(['最高温度', '最低温度'], fontproperties=font_props)
plt.legend(['最高温度', '最低温度'])

图片可以显示了, 不过图例不出意外的乱码了

图例仍然是乱码

这个确实解决了一部分问题, 参考了一下博客园5的博文, 执行mathplotlib.mathplotlib_fname(), 可以拿到rc文件的路径

RC文件路径

既然我要在容器里用, 直接把ttf放过去也不失为一种解决方案

容器ttf存储路径

上面的图显示的ttf文件与python执行显示的mathplotlib字体一致, 确定该目录就是存放字体的路径, 直接在dockerfile里添加一行

1
RUN mv /app/utils/weather_forcast/SimHei.ttf /usr/local/lib/python3.9/site-packages/matplotlib/mpl-data/fonts/ttf/

构造一个函数用于解决中文乱码

1
2
3
4
5
6
7
def _fix_chinese_chars():
logger = logging.getLogger(_fix_chinese_chars.__name__)
mapper = {'darwin': 'Heiti TC', 'linux': 'SimHei'}
default = 'DejaVu Sans'
os_version = platform.system().lower()
plt.rcParams['font.sans-serif'] = mapper.get(os_version, default)
logger.debug('OS type: %s', os_version)

添加后测试, 问题解决~

中文正常显示

  1. 彻底解决Python里matplotlib不显示中文的问题 - 知乎↩︎

  2. matplotlib 兼容中文汉字的所有字体——展示&推荐 - 知乎↩︎

  3. 给maplotlib添加中文字体FontProperties - 简书↩︎

  4. Windows——matplotlib添加中文字体_WaitFoF的博客-CSDN博客↩︎

  5. 解决matplotlib的中文问题 - Tacey Wong - 博客园↩︎