Python matplotlib 中文字型配置解決方案
matplotlib 預設不支援中文,中文會顯示為方塊/方框
控制台警告:
UserWarning: Glyph XXXXX missing from current font
根本原因:matplotlib 的預設字型不包含中文字元。
當以下情況時使用此 Skill: 1. ✅ matplotlib 綁圖中中文顯示為方框/亂碼 2. ✅ 需要配置中文字型 3. ✅ 負號顯示為方框 4. ✅ 圖例、標題、座標軸標籤中文顯示異常 5. ✅ 跨平臺字型相容問題 6. ✅ 字型路徑配置問題 7. ✅ 字型快取問題
# 建立字型目錄
mkdir -p fonts
# 下載 BabelStoneHan 字型(約 50MB)
curl -L -o fonts/BabelStoneHan.ttf "https://www.babelstone.co.uk/Fonts/Download/BabelStoneHan.ttf"
# 或者使用 wget
wget -O fonts/BabelStoneHan.ttf "https://www.babelstone.co.uk/Fonts/Download/BabelStoneHan.ttf"
其他字型選擇(小於 10MB): - WenQuanYi Micro Hei (文泉驛微米黑) - 約 4MB - SimHei (黑體) - 系統自帶 - Microsoft YaHei (微軟雅黑) - Windows 系統自帶
# 複製配置模板到你的專案
cp ~/.openclaw/skills/python-matplotlib-chinese-font/templates/setup_font.py ./
import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
# 字型檔案路徑(請修改為你的實際路徑)
font_file = './fonts/BabelStoneHan.ttf'
# 關鍵:顯式新增字型
fm.fontManager.addfont(font_file)
# 建立 FontProperties
font_prop = fm.FontProperties(fname=font_file)
# 設定全域性字型
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['axes.unicode_minus'] = False
# 使用
fig, ax = plt.subplots()
ax.set_title('中文標題', fontproperties=font_prop)
ax.set_xlabel('橫軸', fontproperties=font_prop)
ax.legend(['圖例'], prop=font_prop)
# 建立字型目錄
mkdir -p fonts
# 下載 BabelStoneHan 字型
curl -L -o fonts/BabelStoneHan.ttf "https://www.babelstone.co.uk/Fonts/Download/BabelStoneHan.ttf"
專案結構:
your_project/
├── fonts/
│ └── BabelStoneHan.ttf ← 中文字型檔案(需自行下載)
├── scripts/
│ └── your_script.py
└── ...
字型推薦:
- BabelStoneHan.ttf(開源,支援中文)← 需自行下載,約 50MB
- SimHei.ttf(黑體)- 系統自帶
- Microsoft YaHei.ttf(微軟雅黑)- Windows 系統自帶
- WenQuanYi Micro Hei(文泉驛微米黑)- 約 4MB
import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
# 字型檔案相對於指令碼的路徑
_FONT_FILE_RELATIVE = os.path.join('..', '..', 'fonts', 'BabelStoneHan.ttf')
def _get_font_path():
"""獲取字型檔案的絕對路徑"""
script_dir = os.path.dirname(os.path.abspath(__file__))
font_file = os.path.join(script_dir, _FONT_FILE_RELATIVE)
return os.path.normpath(font_file)
def setup_chinese_font():
"""配置中文字型(相容所有 matplotlib 版本)"""
font_file = _get_font_path()
if os.path.exists(font_file):
# 建立 FontProperties
font_prop = fm.FontProperties(fname=font_file)
font_name = font_prop.get_name()
# 註冊字型(相容新舊版本 matplotlib)
try:
# 方法1:matplotlib 3.2+ 使用 addfont
if hasattr(fm.fontManager, 'addfont'):
fm.fontManager.addfont(font_file)
else:
# 方法2:舊版本 matplotlib,手動新增到字型列表
try:
fm.fontManager.ttflist.append(fm.FontEntry(
fname=font_file,
name=font_name,
style=font_prop.get_style(),
variant=font_prop.get_variant(),
weight=font_prop.get_weight(),
stretch=font_prop.get_stretch(),
size=font_prop.get_size()
))
except Exception:
pass
except Exception:
pass
# 設定全域性字型
plt.rcParams['font.family'] = font_name
plt.rcParams['axes.unicode_minus'] = False # 解決負號顯示問題
return font_prop
return fm.FontProperties()
⚠️ 版本相容性說明:
| matplotlib 版本 | 方法 | 說明 |
|---|---|---|
| ≥ 3.2 | fontManager.addfont() |
推薦方法 |
| < 3.2 | fontManager.ttflist.append() |
相容方法 |
# 建立 FontProperties
font_prop = fm.FontProperties(fname=font_file)
# 設定全域性字型
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['axes.unicode_minus'] = False # 解決負號顯示問題
print(f"✅ 已載入中文字型: {font_file}")
return font_prop
else:
print(f"⚠️ 未找到字型檔案: {font_file}")
return fm.FontProperties()
chinese_font = setup_chinese_font()
---
### **第 3 步:在綁圖時使用字型**
#### **方法 A:全域性設定(推薦)**
```python
# 配置字型
chinese_font = setup_chinese_font()
# 綁圖時自動使用全域性字型
fig, ax = plt.subplots()
ax.set_title('中文標題') # 自動使用全域性字型
ax.set_xlabel('橫軸標籤')
ax.legend(['圖例1', '圖例2'])
# 配置字型
chinese_font = setup_chinese_font()
# 綁圖時顯式指定 fontproperties
fig, ax = plt.subplots()
ax.set_title('中文標題', fontproperties=chinese_font)
ax.set_xlabel('橫軸標籤', fontproperties=chinese_font)
ax.legend(['圖例1', '圖例2'], prop=chinese_font)
# ❌ 錯誤:使用執行目錄
font_file = os.path.join(os.getcwd(), 'fonts', 'BabelStoneHan.ttf')
# ✅ 正確:使用指令碼所在目錄
script_dir = os.path.dirname(os.path.abspath(__file__))
font_file = os.path.join(script_dir, '..', '..', 'fonts', 'BabelStoneHan.ttf')
font_file = os.path.normpath(font_file) # 規範化路徑
# ❌ 錯誤:直接建立 FontProperties
font_prop = fm.FontProperties(fname=font_file)
# ✅ 正確:先 addfont,再建立 FontProperties
fm.fontManager.addfont(font_file) # 關鍵!
font_prop = fm.FontProperties(fname=font_file)
# 設定全域性字型
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['axes.unicode_minus'] = False # 解決負號顯示問題
# ✅ 使用 os.path.normpath() 規範化路徑 font_file = os.path.normpath(font_file) # ✅ 檢查檔案是否存在 if os.path.exists(font_file): fm.fontManager.addfont(font_file)小蔥技能站7w4.net,專業的AI技能分享平臺。
✅ 優點:
- 不依賴系統字型
- 可移植性好
- 跨平臺相容
❌ 避免:
- 使用系統字型路徑(/usr/share/fonts/...)
- 假設字型已安裝
原因:沒有呼叫 addfont() 顯式新增字型
解決:
# ✅ 必須先呼叫 addfont
fm.fontManager.addfont(font_file)
font_prop = fm.FontProperties(fname=font_file)
原因:字型不支援負號
解決:
plt.rcParams['axes.unicode_minus'] = False
原因:使用 os.getcwd() 而不是指令碼所在目錄
解決:
# ✅ 使用指令碼所在目錄
script_dir = os.path.dirname(os.path.abspath(__file__))
原因:程式碼修改有誤或傳送了舊圖片
解決:
1. 刪除舊圖片:rm -f output.png
2. 重新執行指令碼
3. 檢查圖片修改時間:stat output.png | grep Modify
'FontManager' object has no attribute 'addfont'原因:fontManager.addfont() 是 matplotlib 3.2+ 才有的方法
解決:使用版本相容性檢查
# 相容所有 matplotlib 版本
if hasattr(fm.fontManager, 'addfont'):
# matplotlib 3.2+
fm.fontManager.addfont(font_file)
else:
# matplotlib < 3.2
try:
fm.fontManager.ttflist.append(fm.FontEntry(...))
except Exception:
pass
檢查 matplotlib 版本:
import matplotlib
print(matplotlib.__version__)
原因:matplotlib 快取了舊字型配置
解決:
# 清除字型快取
try:
fm._load_fontmanager(try_read_cache=False)
except:
pass
| 方案 | 優點 | 缺點 | 推薦度 |
|---|---|---|---|
| 字型檔案在專案內 | 可移植、跨平臺 | 需要管理字型檔案 | ⭐⭐⭐⭐⭐ |
| 使用系統字型 | 無需管理檔案 | 依賴系統、不可移植 | ⭐⭐ |
| 臨時下載字型 | 自動化 | 網路依賴、速度慢 | ⭐⭐⭐ |
python-matplotlib-chinese-font/
├── SKILL.md # Skill 說明文件(本檔案)
├── references/
│ ├── plot_utils.py # 完整工具模組
│ └── test_chinese_font.py # 測試程式碼
└── templates/
└── setup_font.py # 配置模板(可直接複製)
⚠️ 字型檔案需自行下載,詳見"第 0 步:下載字型檔案"
references/plot_utils.pyreferences/test_chinese_font.pytemplates/setup_font.py# ✅ 推薦配置
import os
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
# 1. 字型路徑(相對於指令碼)
_FONT_FILE_RELATIVE = os.path.join('..', '..', 'fonts', 'BabelStoneHan.ttf')
# 2. 獲取絕對路徑
def _get_font_path():
script_dir = os.path.dirname(os.path.abspath(__file__))
font_file = os.path.join(script_dir, _FONT_FILE_RELATIVE)
return os.path.normpath(font_file)
# 3. 配置字型
def setup_chinese_font():
font_file = _get_font_path()
if os.path.exists(font_file):
fm.fontManager.addfont(font_file) # 關鍵!
font_prop = fm.FontProperties(fname=font_file)
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['axes.unicode_minus'] = False
return font_prop
return fm.FontProperties()
# 4. 使用
chinese_font = setup_chinese_font()
| 版本 | 日期 | 說明 |
|---|---|---|
| v1.0.0 | 2026-03-21 | 初始版本 - BabelStoneHan 字型配置方案 |
| v1.1.0 | 2026-03-21 | 新增 matplotlib 版本相容性支援 |
| v1.2.0 | 2026-04-02 | 字型檔案改為使用者自行下載(滿足 clawhub 檔案大小限制) |
Skill 建立時間:2026-03-21
維護者:太子
當前版本:v1.2.0