Python Matplotlib中文显示问题解决方案

11 次阅读

Matplotlib 绘制图表时,如果标题、坐标轴名称、图例或注释包含中文,常见的问题是中文字符显示为方框、乱码,甚至完全无法显示。这类问题通常不是 Matplotlib 本身不支持中文,而是当前环境没有配置合适的中文字体。

解决 Matplotlib 中文显示问题,核心就是找到系统中可用的中文字体,并通过 rcParams 或 FontProperties 告诉 Matplotlib 使用该字体。

一、为什么 Matplotlib 中文会显示异常

Matplotlib 默认字体通常是 DejaVu Sans,这款字体能够很好地覆盖英文、数字以及大量常见符号,但并不完整支持中文字符。

例如执行下面的代码:

Python
运行
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [10, 25, 18, 32, 40]

plt.plot(x, y)
plt.title("销售数据趋势")
plt.xlabel("月份")
plt.ylabel("销售额")
plt.show()

如果运行环境没有合适的中文字体,就可能出现类似下面的现象:

UserWarning: Glyph xxxx missing from current font.

最终图表中的中文可能变成:

□□□□□□

或者显示成无法识别的符号。

因此,问题的关键并不是修改字符串编码,而是为 Matplotlib 指定支持中文的字体。

二、最简单的解决方法

如果系统中已经安装了中文字体,可以直接通过 plt.rcParams 设置字体。

例如 Windows 系统通常可以使用微软雅黑:

Python
运行
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

x = [1, 2, 3, 4, 5]
y = [10, 25, 18, 32, 40]

plt.plot(x, y)
plt.title("销售数据趋势")
plt.xlabel("月份")
plt.ylabel("销售额")
plt.show()

其中:

Python
运行
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]

用于指定 Matplotlib 的无衬线字体。

而:

Python
运行
plt.rcParams["axes.unicode_minus"] = False

用于解决坐标轴负号显示异常的问题。

这两个配置经常一起使用。

三、不同操作系统应该选择什么字体

不同操作系统默认安装的中文字体并不相同,因此不要直接照搬某个系统的字体名称。

Windows

Windows 常见中文字体包括:

Microsoft YaHei
SimHei
SimSun
KaiTi
FangSong

例如:

Python
运行
plt.rcParams["font.sans-serif"] = ["SimHei"]

也可以使用:

Python
运行
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]

通常微软雅黑的显示效果比较适合普通数据可视化。

macOS

macOS 可以尝试:

Python
运行
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]

部分 macOS 环境也可以使用:

PingFang SC
Heiti SC
STHeiti

例如:

Python
运行
plt.rcParams["font.sans-serif"] = ["PingFang SC"]

实际使用时仍然建议先确认字体是否存在。

Linux

Linux 环境中是否能够显示中文,取决于系统安装的字体。

常见选择包括:

Noto Sans CJK SC
Noto Sans CJK CN
WenQuanYi Zen Hei
SimHei

例如:

Python
运行
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC"]

如果服务器是精简安装的 Linux,可能根本没有中文字体,这时需要额外安装字体。

四、如何查看 Matplotlib 能使用哪些字体

如果不确定当前环境有哪些字体,可以通过 Matplotlib 查询。

Python
运行
from matplotlib.font_manager import fontManager

for font in fontManager.ttflist:
    print(font.name)

运行后会得到类似:

DejaVu Sans
Liberation Sans
Microsoft YaHei
SimHei
Noto Sans CJK SC
...

找到支持中文的字体名称后,再进行配置即可。

也可以直接检查某个字体是否存在:

Python
运行
from matplotlib.font_manager import findfont

print(findfont("Microsoft YaHei"))

如果返回一个字体文件路径,通常说明 Matplotlib 能够找到该字体。

五、使用 FontProperties 精确指定字体

全局设置适合整个程序都使用同一种中文字体。如果只希望某个标题或者图例使用中文字体,可以使用 FontProperties。

示例:

Python
运行
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

font = FontProperties(fname="C:/Windows/Fonts/msyh.ttc")

x = [1, 2, 3, 4, 5]
y = [10, 25, 18, 32, 40]

plt.plot(x, y)

plt.title("销售数据趋势", fontproperties=font)
plt.xlabel("月份", fontproperties=font)
plt.ylabel("销售额", fontproperties=font)

plt.show()

这种方法最大的优势是可以针对单个文本对象设置字体,不会影响整个 Matplotlib 环境。

如果字体文件路径明确,FontProperties 通常比单纯指定字体名称更加稳定。

六、解决图例中文显示问题

图例也是中文显示问题比较容易遗漏的位置。

例如:

Python
运行
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

x = [1, 2, 3, 4, 5]

plt.plot(x, [10, 20, 15, 30, 40], label="实际销售额")
plt.plot(x, [12, 18, 20, 28, 35], label="预计销售额")

plt.title("销售额对比")
plt.xlabel("月份")
plt.ylabel("金额")
plt.legend()

plt.show()

只要全局字体设置正确,标题、坐标轴以及图例一般都会同时正常显示。

七、为什么中文正常了,但负号变成方框

这是 Matplotlib 中文字体配置中非常典型的另一个问题。

例如图表中存在负数:

Python
运行
y = [-10, -5, 0, 5, 10]

部分中文字体可能无法正确处理 Matplotlib 默认使用的 Unicode 负号,因此坐标轴上的负数可能出现异常。

解决方法就是:

Python
运行
plt.rcParams["axes.unicode_minus"] = False

完整示例:

Python
运行
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

x = [1, 2, 3, 4, 5]
y = [-10, -5, 0, 5, 10]

plt.plot(x, y)
plt.title("温度变化趋势")
plt.xlabel("日期")
plt.ylabel("温度")
plt.show()

因此,处理中文图表时,建议把中文字体和负号配置一起考虑。

八、服务器环境中的 Matplotlib 中文问题

本地 Windows 电脑能够正常显示中文,但代码部署到 Linux 服务器后出现方框,是非常常见的情况。

原因通常是:

本地安装了中文字体,而服务器没有安装。

例如代码:

Python
运行
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]

在 Windows 上可能正常,但服务器没有 Microsoft YaHei,自然无法找到对应字体。

对于 Linux 服务器,更适合准备一款开源中文字体,例如 Noto Sans CJK,然后指定字体文件。

示例:

Python
运行
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt

font = FontProperties(
    fname="/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
)

plt.title("数据分析结果", fontproperties=font)
plt.xlabel("时间", fontproperties=font)
plt.ylabel("数值", fontproperties=font)

plt.show()

实际路径需要根据服务器的字体安装位置调整。

九、程序中动态查找中文字体

如果代码需要同时运行在 Windows、macOS 和 Linux 上,不建议把某一个系统的字体路径写死。

可以准备多个候选字体,然后让程序自动选择。

例如:

Python
运行
import matplotlib.pyplot as plt
from matplotlib.font_manager import fontManager

font_names = {font.name for font in fontManager.ttflist}

candidates = [
    "Microsoft YaHei",
    "SimHei",
    "PingFang SC",
    "Noto Sans CJK SC",
    "WenQuanYi Zen Hei"
]

for name in candidates:
    if name in font_names:
        plt.rcParams["font.sans-serif"] = [name]
        break

plt.rcParams["axes.unicode_minus"] = False

这样可以减少程序对特定操作系统的依赖。

不过需要注意,字体名称必须与当前 Matplotlib 能识别的名称一致。

十、使用 Seaborn 时如何处理中文

如果项目同时使用 Seaborn 和 Matplotlib,也可以直接设置 Matplotlib 的全局参数。

Python
运行
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

sns.set_theme()

sns.lineplot(
    x=[1, 2, 3, 4],
    y=[20, 35, 28, 45]
)

plt.title("销售趋势")
plt.xlabel("月份")
plt.ylabel("销售额")

plt.show()

如果发现 sns.set_theme() 等主题设置影响了字体,可以在主题设置完成后再次设置字体:

Python
运行
sns.set_theme()

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

这样更容易确保最终绘图配置符合预期。

十一、Matplotlib 找不到新安装的字体怎么办

有时候已经安装了字体,但 Matplotlib 仍然提示:

Glyph xxxx missing from current font

这可能是字体缓存没有及时更新。

可以先查看 Matplotlib 使用的缓存目录:

Python
运行
import matplotlib

print(matplotlib.get_cachedir())

关闭 Python 程序后,可以删除对应的 Matplotlib 字体缓存,让下一次启动时重新扫描字体。

也可以在程序中查看当前字体管理器能够识别到的字体:

Python
运行
from matplotlib.font_manager import fontManager

print(len(fontManager.ttflist))

如果新字体已经出现在 ttflist 中,说明字体扫描已经生效。

十二、图片保存后中文变成方框的处理方法

有些情况下,窗口中显示正常,但保存 PNG、JPG 或 PDF 后出现中文异常。

首先确保保存图片之前已经完成字体配置:

Python
运行
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

plt.plot([1, 2, 3], [10, 20, 15])
plt.title("销售数据")

plt.savefig("result.png", dpi=300, bbox_inches="tight")
plt.show()

对于需要提交报告、网页展示或打印的图片,可以适当提高 dpi,但清晰度与中文字体是否存在是两个不同的问题。

如果输出 PDF,还需要特别关注字体嵌入问题。某些字体格式或 PDF 后端的处理方式可能影响最终文件的兼容性,因此正式项目中最好使用实际环境验证生成结果。

十三、推荐封装成统一配置

如果一个项目中有大量绘图代码,每次都设置字体比较麻烦,可以单独封装配置函数。

Python
运行
import matplotlib.pyplot as plt
from matplotlib.font_manager import fontManager


def setup_matplotlib_chinese():
    available_fonts = {font.name for font in fontManager.ttflist}

    candidates = [
        "Microsoft YaHei",
        "SimHei",
        "PingFang SC",
        "Noto Sans CJK SC",
        "WenQuanYi Zen Hei"
    ]

    for font_name in candidates:
        if font_name in available_fonts:
            plt.rcParams["font.sans-serif"] = [font_name]
            break
    else:
        raise RuntimeError("当前系统没有找到可用的中文字体")

    plt.rcParams["axes.unicode_minus"] = False

程序启动时执行:

Python
运行
setup_matplotlib_chinese()

后续绘制图表时,就不需要反复配置。

这种方式尤其适合数据分析项目、报表系统以及自动生成图表的后端服务。

十四、排查 Matplotlib 中文乱码的思路

遇到中文显示异常时,可以按照以下顺序检查:

第一步,确认 Matplotlib 本身能够正常绘图。

第二步,查看系统是否安装中文字体。

第三步,通过 fontManager.ttflist 确认 Matplotlib 是否能够识别该字体。

第四步,使用字体名称设置:

Python
运行
plt.rcParams["font.sans-serif"] = ["字体名称"]

第五步,同时处理负号:

Python
运行
plt.rcParams["axes.unicode_minus"] = False

第六步,如果字体名称方式无效,直接使用字体文件路径:

Python
运行
FontProperties(fname="字体文件路径")

第七步,如果运行在服务器中,重点检查服务器是否真正安装了中文字体。

第八步,如果只是在导出的 PDF、图片中异常,则进一步检查保存格式和字体嵌入情况。

十五、一个完整的中文绘图示例

下面给出一个可以直接参考的完整示例:

Python
运行
import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]

# 解决负号显示问题
plt.rcParams["axes.unicode_minus"] = False

months = ["一月", "二月", "三月", "四月", "五月", "六月"]
sales = [120, 150, 135, 180, 210, 195]

plt.figure(figsize=(9, 5))

plt.plot(
    months,
    sales,
    marker="o",
    label="销售额"
)

plt.title("上半年销售数据趋势")
plt.xlabel("月份")
plt.ylabel("销售额(万元)")
plt.legend()

plt.grid(True, alpha=0.3)
plt.tight_layout()

plt.savefig("sales.png", dpi=300, bbox_inches="tight")
plt.show()

如果当前电脑安装了微软雅黑,这段代码中的标题、坐标轴、图例以及横坐标中文都可以正常显示。

十六、总结

Matplotlib 中文显示异常的根本原因通常是字体缺少中文字符或 Matplotlib 没有正确找到中文字体,而不是 Python 字符串本身存在编码问题。

最常用的解决方案是:

Python
运行
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

如果代码需要跨平台运行,则应该根据 Windows、macOS 和 Linux 的实际字体情况选择合适字体。对于服务器、Docker 容器等无桌面环境,还需要确认系统中已经安装中文字体。

当字体名称配置不稳定时,可以进一步使用 FontProperties 直接指定字体文件。对于大型项目,则可以将中文字体配置统一封装,避免不同绘图模块重复处理。

掌握字体检查、全局配置、局部字体设置和服务器字体安装这几个关键环节后,大多数 Matplotlib 中文乱码、中文方框以及负号异常问题都能够快速定位和解决。