这个错误表明您的系统无法找到 simhei(黑体)字体。以下是彻底解决这个问题的完整指南:
# 更新软件包索引
sudo apt update
# 安装 simhei 字体(黑体)
sudo apt install -y fonts-arphic-uming fonts-arphic-ukai fonts-wqy-microhei fonts-wqy-zenhei fonts-noto-cjk
# 刷新系统字体缓存
sudo fc-cache -f -v
# 清除 Matplotlib 缓存
rm -rf ~/.cache/matplotlib
# 列出所有中文字体
fc-list | grep -i -E 'hei|simhei|cjk|han|msyh|simhei|noto'
# 检查特定字体
fc-match -s SimHei
fc-match -s 'Noto Sans CJK SC'
fc-match -s 'WenQuanYi Zen Hei'
在您的 Python 脚本开头添加以下配置:
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np
import os
def setup_chinese_font():
"""配置中文字体支持"""
# 字体替代方案(按优先级排序)
font_options = [
'SimHei', # 首选 - SimHei
'Noto Sans CJK SC', # 备用1 - Google Noto
'WenQuanYi Zen Hei', # 备用2 - 文泉驿正黑
'WenQuanYi Micro Hei', # 备用3 - 文泉驿微米黑
'Microsoft YaHei', # 备用4 - 微软雅黑
'DejaVu Sans', # 最后的回退
]
# 尝试设置字体
for font_name in font_options:
try:
# 查找字体文件
font_path = fm.findfont(fm.FontProperties(family=font_name))
# 配置为系统默认
plt.rcParams['font.family'] = font_name
plt.rcParams['font.sans-serif'] = [font_name]
plt.rcParams['axes.unicode_minus'] = False
print(f"已成功配置字体: {font_name} ({os.path.basename(font_path)})")
return
except:
continue
# 如果所有字体都失败,使用回退方案
plt.rcParams['font.family'] = 'sans-serif'
print("警告: 未找到中文字体,将使用系统默认")
# 在脚本开头调用设置
setup_chinese_font()
如果上述安装后仍然找不到 simhei 字体,可以手动安装:
# 创建字体目录
mkdir -p ~/.fonts/simhei
# 下载 simhei 字体
wget -O ~/.fonts/simhei/simhei.ttf "https://github.com/msys2/MSYS2-packages/raw/main/mingw-w64-font-simhei/mingw-w64-font-simhei-1.0.0-1-any.pkg.tar.zst?raw=true"
# 刷新字体缓存
fc-cache -f -v ~/.fonts/
在您的代码中,添加以下函数来手动指定字体:
def ensure_simhei_font():
"""确保使用 simhei 字体"""
try:
# 尝试多种可能的字体路径
possible_paths = [
os.path.expanduser("~/.fonts/simhei/simhei.ttf"),
"/usr/share/fonts/truetype/arphic/simhei.ttf",
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"
]
for path in possible_paths:
if os.path.exists(path):
# 添加字体到 Matplotlib
font_prop = fm.FontProperties(fname=path)
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['axes.unicode_minus'] = False
print(f"使用字体文件: {path}")
return True
return False
except Exception as e:
print(f"字体处理错误: {e}")
return False
# 在设置函数中调用
if not ensure_simhei_font():
setup_chinese_font() # 回退到之前的设置
在您的代码中添加以下函数来重建字体缓存:
def rebuild_font_cache():
"""重建 Matplotlib 字体缓存"""
from matplotlib import font_manager
# 删除旧的缓存文件
cache_dir = os.path.join(fm.get_cachedir(), 'font*.cache')
if os.path.exists(cache_dir):
for cache_file in os.listdir(fm.get_cachedir()):
if cache_file.startswith('font') and cache_file.endswith('.cache'):
os.remove(os.path.join(fm.get_cachedir(), cache_file))
# 创建新的缓存
try:
font_manager._rebuild()
print("Matplotlib 字体缓存已重建")
return True
except Exception as e:
print(f"重建字体缓存失败: {e}")
return False
# 在脚本开头调用
rebuild_font_cache()
在您的脚本末尾添加以下测试函数:
def test_chinese_font():
"""测试中文字体显示"""
plt.figure()
plt.plot([0, 1, 2], [3, 2, 1])
plt.title("中文标题测试 - 黑体")
plt.xlabel("横坐标标签")
plt.ylabel("纵坐标标签")
# 保存测试文件
test_file = "chinese_font_test.png"
plt.savefig(test_file, bbox_inches='tight')
plt.close()
print(f"测试图表已保存至: {test_file}")
# 执行测试
test_chinese_font()
以下是一个完整的解决方案脚本:
#!/usr/bin/env python3
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import os
import shutil
# 1. 设置中文环境支持
def setup_chinese_font():
"""配置中文字体支持"""
try:
# 检查可用字体
font_list = [f.name for f in fm.fontManager.ttflist]
chinese_fonts = ['SimHei', 'Noto Sans CJK SC', 'WenQuanYi Zen Hei',
'WenQuanYi Micro Hei', 'Microsoft YaHei']
# 查找第一个可用的中文字体
for font_name in chinese_fonts:
if any(font_name in name for name in font_list):
plt.rcParams['font.family'] = font_name
plt.rcParams['font.sans-serif'] = [font_name]
plt.rcParams['axes.unicode_minus'] = False
print(f"配置字体: {font_name}")
return
# 没有找到预设字体,使用回退
plt.rcParams['font.family'] = 'sans-serif'
print("警告: 未找到预设中文字体,使用系统默认")
except Exception as e:
print(f"字体配置错误: {e}")
plt.rcParams['font.family'] = 'sans-serif'
# 2. 确保使用 simhei 字体
def ensure_simhei_font():
"""尝试使用 simhei 字体"""
possible_paths = [
os.path.expanduser("~/.fonts/simhei/simhei.ttf"),
"/usr/share/fonts/truetype/arphic/simhei.ttf",
"/usr/share/fonts/truetype/msttcorefonts/simhei.ttf",
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"
]
for path in possible_paths:
if os.path.exists(path):
try:
# 添加字体到 Matplotlib
fm.fontManager.addfont(path)
# 设置为新加载的字体
font_name = fm.FontProperties(fname=path).get_name()
plt.rcParams['font.family'] = font_name
plt.rcParams['axes.unicode_minus'] = False
print(f"成功加载字体: {font_name} ({os.path.basename(path)})")
return True
except Exception as e:
print(f"加载字体 {path} 失败: {e}")
return False
# 3. 重建字体缓存
def rebuild_font_cache():
"""重建 Matplotlib 字体缓存"""
try:
# 删除缓存目录
cache_dir = fm.get_cachedir()
if os.path.exists(cache_dir):
shutil.rmtree(cache_dir)
os.makedirs(cache_dir)
# 重建缓存
fm._rebuild()
print("Matplotlib 字体缓存已重建")
return True
except Exception as e:
print(f"重建字体缓存失败: {e}")
return False
# 4. 测试字体显示
def test_chinese_display():
"""测试中文字体显示"""
try:
plt.figure(figsize=(8, 4))
# 创建简单图表
x = [1, 2, 3]
y = [3, 2, 1]
plt.plot(x, y)
# 添加中文文本
plt.title("中文标题 - 黑体测试")
plt.xlabel("横坐标 - 测试")
plt.ylabel("纵坐标 - 测试")
plt.grid(True)
# 保存测试图像
test_file = "chinese_font_test.png"
plt.savefig(test_file, bbox_inches='tight')
plt.close()
# 检查文件是否创建成功
if os.path.exists(test_file) and os.path.getsize(test_file) > 0:
print(f"中文字体测试成功! 图片保存至: {test_file}")
return True
else:
print("测试图表保存失败")
return False
except Exception as e:
print(f"测试中文字体显示时出错: {e}")
return False
# 主流程
if __name__ == "__main__":
print("===== 开始解决中文字体问题 =====")
# 步骤1: 重建字体缓存
print("\n[1/4] 重建字体缓存...")
rebuild_font_cache()
# 步骤2: 尝试使用 simhei 字体
print("\n[2/4] 尝试加载 SimHei 字体...")
if not ensure_simhei_font():
# 步骤3: 设置备选字体
print("\n[3/4] 设置备选中文字体...")
setup_chinese_font()
# 步骤4: 测试显示
print("\n[4/4] 测试中文字体显示...")
if not test_chinese_display():
print("\n⚠️ 警告: 中文字体显示测试失败,可能需要手动安装字体")
print("请尝试以下命令手动安装中文字体:")
print(" sudo apt install fonts-arphic-uming fonts-arphic-ukai fonts-wqy-microhei fonts-wqy-zenhei fonts-noto-cjk")
print("然后重新运行此脚本")
如果上述方法都不起作用,可以考虑将字体直接嵌入到 Python 脚本中:
import base64
import tempfile
from io import BytesIO
def embed_font_in_plot():
"""在图表中嵌入字体"""
# 字体文件转换为 base64
FONT_DATA = b"""
# 字体文件内容
...
""" # 这里放入字体文件的二进制内容
# 创建临时字体文件
with tempfile.NamedTemporaryFile(suffix=".ttf", delete=False) as temp_font:
temp_font.write(FONT_DATA)
temp_font_path = temp_font.name
# 使用临时字体文件
font_prop = fm.FontProperties(fname=temp_font_path)
plt.rcParams['font.family'] = font_prop.get_name()
# 创建图表
plt.figure()
plt.title("嵌入字体测试 - 中文")
plt.xlabel("横坐标")
plt.ylabel("纵坐标")
# 保存到内存
buf = BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
# 清理临时文件
os.unlink(temp_font_path)
return buf
使用 Docker 容器:
FROM python:3.10-slim
RUN apt-get update && apt-get install -y \
fonts-wqy-microhei \
fonts-wqy-zenhei \
fonts-noto-cjk \
fonts-noto-cjk-extra
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
升级 Matplotlib:
pip install --upgrade matplotlib
使用虚拟环境:
python -m venv .venv
source .venv/bin/activate
pip install matplotlib
使用 SVG 后端:
import matplotlib
matplotlib.use('SVG') # 使用 SVG 后端
通过以上步骤,您应该能够彻底解决 “findfont: Generic family ‘sans-serif’ not found because none of the following families were found: simhei” 错误。如果问题仍然存在,请考虑使用网页截图替代方案或改用英文标签。