Python 2 matplotlib绘图中文乱码修复方法
针对 Python 2 环境下使用 matplotlib 绘图时出现的中文乱码与负号方块问题,系统解析其底层编码与字形映射机制,提供动态 rcParams 配置、FontProperties 精确指定以及全局 matplotlibrc 固化三种修复方案,并配有排错决策指南。
在 Python 2.7 环境中使用 Matplotlib 进行数据可视化时,只要在图表标题、轴标签或图例中传入中文字符,往往会直接遇到汉字显示为空白“豆腐块”(方块 □)的现象,控制台还会伴随输出 UserWarning: Glyph ... missing from current font 警告;同时,坐标轴如果有负数刻度,负号 - 也常常会一同变为方块。本文直接给出针对 Python 2 的三种标准化修复方法,并详细剖析其底层的双层成因,帮助你在不同开发和部署场景下彻底排除中文显示故障。
一、乱码成因:Python 2 字节机制与字形映射的双重脱节
很多开发者在 Python 3 中习惯了直接传入中文字符串,但迁移或维护遗留 Python 2 项目时,原有的绘图脚本就会频繁报错或乱码。这并不是 Matplotlib 单方面的缺陷,而是由 Python 2 的语言运行时机制与 Matplotlib 内部的文本渲染机制叠加导致的:
- Python 2 的字符串字节类型(
str)陷阱:在 Python 2 中,不带前缀的字符串文字(如'数据分析')本质是字节序列(Byte String),其编码依赖于代码保存格式(通常是 UTF-8 或 GBK)。当 Matplotlib 尝试把这串原始字节按默认 ASCII 规则解码或直接交给底层字体解析时,由于缺乏明确的 Unicode 码点标识,便会造成解码中断或传递混乱。 - Matplotlib 默认无中文字体(Glyph Missing):Matplotlib 默认使用的无衬线字体族(sans-serif)指向的是
DejaVu Sans、Bitstream Vera Sans等西文字体。这些字体文件内部根本没有收录中文字形(Glyph)。当渲染器拿着汉字的 Unicode 码点去字体文件查表却找不到对应字形时,便只能绘制缺省占位符——即方块。 - 负号 Unicode 减号渲染冲突:Matplotlib 默认开启了
axes.unicode_minus = True。这一选项的初衷是为了让数学排版更美观,它会将减号-(ASCII 0x2D)自动转换为专用的 Unicode 减号字符−。然而,大多数常用中文字体(如黑体 SimHei、微软雅黑)的字形表中并未包含这个字符,导致负号刻度也随之变成方块。
二、快速修复:运行时动态配置 rcParams(推荐首选)
对于日常的数据分析脚本、离线计算任务或 Jupyter Notebook,最优雅、对系统侵入最小的方式是在脚本开头通过动态调整 matplotlib.rcParams 参数来指定中文字体,同时关闭负号 Unicode 转换。
1. 标准实现代码
请确保 Python 2 脚本顶部必须声明源文件编码,且传给 Matplotlib 的所有中文字符串前必须显式附带 u 前缀:
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
# 1. 注入中文字体到无衬线字体回退链的首位(以 Windows 黑体 SimHei 为例)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'sans-serif']
# 2. 修复负号显示为方块的问题,强制使用标准 ASCII 连字符
plt.rcParams['axes.unicode_minus'] = False
# 生成包含负数范围的模拟测试数据
x = np.linspace(-5, 5, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.plot(x, y, label=u'正弦波形')
# 注意:所有传递给绘图 API 的中文必须是 unicode 对象(即 u 前缀)
plt.title(u'Python 2 Matplotlib 中文支持验证图', fontsize=14)
plt.xlabel(u'时间轴(含负数区间:-5 至 5)', fontsize=11)
plt.ylabel(u'振幅测量值', fontsize=11)
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(loc='upper right')
plt.show()
不同操作系统内置的中文字体名称各异。在配置 rcParams['font.sans-serif'] 时,请按照所在系统选择已有的字体名称:
- Windows 系统:推荐使用
'SimHei'(黑体)或'Microsoft YaHei'(微软雅黑)。 - macOS 系统:推荐使用
'Arial Unicode MS'、'PingFang SC'或'STHeiti'(华文黑体)。 - Linux 系统(Ubuntu/Debian/CentOS):推荐使用
'WenQuanYi Micro Hei'(文泉驿微米黑)或'Noto Sans CJK SC'。若系统未安装,可执行sudo apt-get install fonts-wqy-microhei安装。
三、精细控制:使用 FontProperties 指定字体文件(适合无权限服务器)
当代码运行在没有 root 权限的 Linux 服务器、Docker 容器或跨平台共享项目时,系统可能根本没有安装上述全局中文字体。此时,最稳妥的做法是将一个开源字体文件(例如 simhei.ttf)直接放入项目目录中,使用 FontProperties 显式指定物理文件路径。
1. 实施方法与示例
# -*- coding: utf-8 -*-
import os
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# 解决负号显示异常(即便使用 FontProperties,负号仍受 rcParams 控制)
plt.rcParams['axes.unicode_minus'] = False
# 指定字体文件的绝对路径或相对项目根路径
font_path = os.path.join(os.path.dirname(__file__), 'fonts', 'simhei.ttf')
my_font = FontProperties(fname=font_path, size=12)
title_font = FontProperties(fname=font_path, size=14)
plt.plot([1, 2, 3], [-10, 20, 15], label=u'实测指标')
# 在标题、坐标轴中传入 fontproperties 参数
plt.title(u'通过 FontProperties 独立指定字体', fontproperties=title_font)
plt.xlabel(u'测试周期(周)', fontproperties=my_font)
plt.ylabel(u'产出增量(%)', fontproperties=my_font)
# 注意:图例 plt.legend() 接受的参数名为 prop 而非 fontproperties
plt.legend(prop=my_font)
plt.show()
在使用 FontProperties 时务必留意接口命名差异:对于 plt.title()、plt.xlabel()、plt.ylabel() 和 plt.text(),字体参数名为 fontproperties;而对于 plt.legend(),其接收字体对象的参数名为 prop。如果给 legend 传 fontproperties,参数会被忽略,图例文字依然会显示为方块。
四、全局生效:固化修改 matplotlibrc 配置文件
如果你希望在当前 Python 2 环境下的任何脚本中都不用每次手动写配置代码,可以直接修改 Matplotlib 的系统配置文件 matplotlibrc,并安装内置字体。
- 定位 Matplotlib 配置文件路径:在终端或交互式 Python 中执行以下命令,获取配置文件的物理绝对路径:
通常会输出类似于python -c "import matplotlib; print(matplotlib.matplotlib_fname())"/usr/local/lib/python2.7/site-packages/matplotlib/mpl-data/matplotlibrc的路径。 - 将中文字体拷贝到 Matplotlib 字体库:
进入
matplotlib/mpl-data/fonts/ttf/目录,将准备好的中文字体文件(如simhei.ttf)拷贝进该目录中。 - 修改
matplotlibrc配置项: 使用文本编辑器打开该文件,搜索并去掉以下三项开头的注释符号#并修改取值:font.family : sans-serif font.sans-serif : SimHei, DejaVu Sans, Bitstream Vera Sans axes.unicode_minus : False - 彻底清除字体索引缓存:
Matplotlib 会在用户主目录下缓存已发现的系统字体列表,如果不清除缓存,新的配置和字体文件将不会被读取。请删除缓存目录:
# Linux / macOS 缓存清理命令 rm -rf ~/.cache/matplotlib # Windows 缓存通常位于 # C:\Users\<用户名>\.matplotlib 或 C:\Users\<用户名>\.cache\matplotlib
五、常见排错排查决策与验证
在实际操作中,有时开发者已经加入了配置,但图表仍然出现异常。以下决策树梳理了从运行到最终正确输出的最常见故障节点:
| 异常现象 | 根本原因 | 对应的排查与修复步骤 |
|---|---|---|
SyntaxError: Non-ASCII character... |
Python 2 解释器默认将源码视作 ASCII,遇到源码文件中的中文文字时无法解析。 | 在脚本的首行或次行添加编码声明头:# -*- coding: utf-8 -*-。 |
中文显示为空白方块 □,且有 Glyph missing 警告 |
① 字符串未加 u 前缀导致字节解码失真;② 设置的字体在当前操作系统中不存在; ③ 字体缓存未刷新。 |
① 检查所有传入的中文是否为 u'...';② 使用 matplotlib.font_manager.fontManager.ttflist 打印可用字体名称列表,确认系统是否有该字体;③ 删除 ~/.cache/matplotlib 后重跑。 |
| 汉字显示完全正常,但刻度上的负号变成方块 □ | axes.unicode_minus 默认为 True,使用的中文字体库缺乏 Unicode 专用减号。 |
在代码中加入 plt.rcParams['axes.unicode_minus'] = False,令其使用通用 ASCII 连字符。 |
修改了 matplotlibrc 却完全不起效果 |
当前项目目录下存在同名 matplotlibrc 覆盖了全局配置,或者字体缓存依旧指向旧索引。 |
打印 matplotlib.matplotlib_fname() 确认实际加载的配置文件位置,并确认已清理缓存目录。 |
六、总结与编写规范建议
处理 Python 2 下的 Matplotlib 中文显示问题,记住并遵循一套标准范式即可彻底避免反复踩坑:
- 文件层面:文件头部永久保留
# -*- coding: utf-8 -*-,确保解释器正确解析脚本文件本身。 - 数据层面:所有进入绘图流程的静态字符串一律加上
u前缀;如果是从文件或网络读取的字符串,必须先使用.decode('utf-8')或.decode('gbk')显式解码为 Unicode。 - 绘图层面:在脚本导入模块后,立即执行
plt.rcParams['font.sans-serif'] = ['SimHei']与plt.rcParams['axes.unicode_minus'] = False。在无全局字体权限的服务器上,则统一用FontProperties读取项目内自带字体。
通过以上双层机制的协同处理,无论是在本地开发调试,还是在远程服务器自动化绘图,均能确保 Python 2 环境下的图表标题、轴标签与图例文字稳定、清晰地渲染显示。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













