在WSL2的Jupyter中正确显示中文字体,需要以下几个步骤:
解决方案
- 安装中文字体到WSL2
更新包列表
sudo apt update
安装中文字体
sudo apt install -y fonts-wqy-zenhei fonts-wqy-microhei
安装常用中文字体(推荐)
sudo apt install -y fonts-noto-cjk fonts-noto-cjk-extra
刷新字体缓存
fc-cache -fv
- 检查已安装的字体
查看已安装的中文字体
fc-list :lang=zh
或查看特定字体
fc-list | grep -i "wqy"
fc-list | grep -i "noto"
1. 检查是否已安装中文字体
fc-list :lang=zh
如果没输出或只有少量,说明没安装
2. 安装中文字体
sudo apt update
sudo apt install -y fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk
3. 检查字体是否正确安装
fc-list | grep -i "wqy|noto|zenhei"
4. 刷新字体缓存
sudo fc-cache -fv
fc-cache -fv
清除Matplotlib缓存
rm -rf ~/.cache/matplotlib
rm -rf ~/.config/matplotlib
重启Jupyter内核
在Jupyter中:Kernel -> Restart Kernel
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'WenQuanYi Micro Hei' # 替换为你选择的字体
创建数据
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]
绘制折线图
plt.plot(x, y)
添加标题和标签
plt.title('折线图示例')
plt.xlabel('X轴')
plt.ylabel('Y轴')
显示图形
plt.show()
看到您当前使用的字体列表,问题找到了! 字体列表显示的是英文字体(Arial、DejaVu Sans等),而没有您设置的中文字体"WenQuanYi Micro Hei"。这说明字体设置被覆盖了。
问题分析
从图片可以看出,中文确实显示了,但字体设置显示的是英文字体。这很可能是因为:
- Seaborn 覆盖了字体设置 - Seaborn 在设置样式时会重置字体
- 设置顺序问题 - 字体设置在 Seaborn 之后被覆盖
解决方案
修改字体设置代码,确保在正确的位置和顺序:
"""
完整评估报告和可视化 - 修复字体覆盖问题
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
import json
from sklearn.metrics import roc_curve, auc, f1_score
import os
import time
import pickle
==================== 1. 修复字体设置 ====================
print("=" * 60)
print("设置中文字体 - 防止被覆盖")
print("=" * 60)
1.1 首先重置所有设置
plt.rcParams.update(plt.rcParamsDefault)
1.2 创建自定义的rc参数,包含中文字体
chinese_rc_params = {
字体设置 - 中文字体必须在最前面
'font.sans-serif': ['WenQuanYi Micro Hei', 'DejaVu Sans', 'Arial Unicode MS', 'Arial'],
'axes.unicode_minus': False,
# 图形设置
'figure.figsize': (10, 6),
'figure.dpi': 100,
'savefig.dpi': 300,
'savefig.bbox': 'tight',
# 坐标轴设置
'axes.titlesize': 16,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
}
1.3 应用自定义设置
plt.rcParams.update(chinese_rc_params)
1.4 然后设置seaborn样式(这会覆盖部分设置)
sns.set_style("whitegrid")
sns.set_palette("husl")
1.5 重新设置中文字体,确保不被seaborn覆盖
这是关键步骤:在seaborn之后重新设置字体
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'DejaVu Sans', 'Arial Unicode MS', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
print("✓ 字体设置完成")
print(f"当前字体: {plt.rcParams['font.sans-serif'][:2]}") # 显示前2个
print(f"字体族: {plt.rcParams.get('font.family', '未设置')}")
1.6 测试字体是否设置成功
def test_font_setup():
"""测试字体设置"""
fig, ax = plt.subplots(figsize=(8, 4))
# 创建测试数据
categories = ['类别A', '类别B', '类别C', '类别D']
values = [3, 7, 5, 9]
bars = ax.bar(categories, values, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'])
ax.set_xlabel('类别名称')
ax.set_ylabel('数值')
ax.set_title('中文字体测试图表 - 柱状图示例')
# 添加数值标签
for i, (bar, val) in enumerate(zip(bars, values)):
ax.text(bar.get_x() + bar.get_width()/2., val + 0.1,
f'{val}', ha='center', va='bottom', fontweight='bold')
plt.tight_layout()
plt.show()
# 检查实际使用的字体
from matplotlib.font_manager import FontProperties
test_fp = FontProperties()
print(f"测试字体名称: {test_fp.get_name()}")
print("✓ 字体测试完成")
test_font_setup()
==================== 2. 验证字体设置 ====================
print("\n验证字体设置...")
检查所有字体相关的rc参数
font_keys = [k for k in plt.rcParams.keys() if 'font' in k.lower()]
for key in font_keys:
value = plt.rcParams[key]
if isinstance(value, list) and len(value) > 0:
print(f"{key}: {value[:3] if len(value) > 3 else value}")
else:
print(f"{key}: {value}")
检查当前默认字体
current_font = plt.rcParams.get('font.sans-serif', [])
if current_font and 'WenQuanYi' in current_font[0]:
print("✓ 中文字体设置成功")
else:
print("⚠ 中文字体可能未被正确设置")
尝试另一种方法
import matplotlib.font_manager as fm
# 查找可用的中文字体
available_fonts = [f.name for f in fm.fontManager.ttflist if 'WenQuanYi' in f.name or 'Noto' in f.name]
if available_fonts:
print(f"可用的中文字体: {set(available_fonts[:5])}")
# 使用第一个找到的中文字体
chinese_font = available_fonts[0]
plt.rcParams['font.sans-serif'] = [chinese_font] + plt.rcParams['font.sans-serif']
print(f"✓ 已设置字体: {chinese_font}")
==================== 3. 创建保存目录 ====================
save_dir = "./__model_checkpoints/model_v2"
os.makedirs(save_dir, exist_ok=True)
print(f"\n保存目录: {save_dir}")
==================== 4. 加载评估结果 ====================
print("\n加载评估结果...")
try:
with open(f"{save_dir}/evaluation_results.pkl", 'rb') as f:
evaluation_results = pickle.load(f)
predictions = np.array(evaluation_results['predictions'])
labels = np.array(evaluation_results['labels'])
probs = np.array(evaluation_results['probs'])
predictions_optimal = np.array(evaluation_results['predictions_optimal'])
best_threshold = evaluation_results['best_threshold']
print(f"✓ 数据加载成功:")
print(f" predictions形状: {predictions.shape}")
print(f" labels形状: {labels.shape}")
print(f" probs形状: {probs.shape}")
print(f" 最佳阈值: {best_threshold}")
except Exception as e:
print(f"✗ 加载评估结果失败: {e}")
raise
==================== 5. 修复绘图函数 ====================
def create_reliable_chinese_plot(predictions, labels, predictions_optimal, best_threshold, save_dir):
"""
创建可靠的中文图表 - 确保中文显示
"""
from sklearn.metrics import precision_score, recall_score, f1_score
print("\n创建可靠的性能对比图...")
# 计算指标
precision_default = precision_score(labels, predictions, average='macro', zero_division=0)
recall_default = recall_score(labels, predictions, average='macro', zero_division=0)
f1_default = f1_score(labels, predictions, average='macro', zero_division=0)
precision_optimal = precision_score(labels, predictions_optimal, average='macro', zero_division=0)
recall_optimal = recall_score(labels, predictions_optimal, average='macro', zero_division=0)
f1_optimal = f1_score(labels, predictions_optimal, average='macro', zero_division=0)
# 在绘图前再次确认字体设置
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'DejaVu Sans', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 设置全局标题
fig.suptitle('模型性能指标对比', fontsize=16, fontweight='bold', y=1.05)
# 数据
metrics = ['精确率', '召回率', 'F1分数']
default_values = [precision_default, recall_default, f1_default]
optimal_values = [precision_optimal, recall_optimal, f1_optimal]
colors = ['#FF6B6B', '#4ECDC4']
labels_text = [f'阈值 0.5\n{default_values[i]:.4f}',
f'阈值 {best_threshold:.3f}\n{optimal_values[i]:.4f}']
for idx, metric in enumerate(metrics):
ax = axes[idx]
# 创建柱状图
x_pos = np.arange(2)
bars = ax.bar(x_pos, [default_values[idx], optimal_values[idx]],
color=colors, alpha=0.8, width=0.6)
# 设置标题和标签
ax.set_title(metric, fontsize=14, fontweight='bold', pad=10)
ax.set_ylabel('数值', fontsize=12)
ax.set_ylim([0, 1.1])
# 设置x轴标签
ax.set_xticks(x_pos)
ax.set_xticklabels([f'阈值 0.5\n{default_values[idx]:.4f}',
f'阈值 {best_threshold:.3f}\n{optimal_values[idx]:.4f}'],
fontsize=10, ha='center')
# 移除顶部和右侧边框
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# 添加网格
ax.grid(True, alpha=0.3, axis='y')
# 在柱子上方添加数值
for i, bar in enumerate(bars):
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height + 0.02,
f'{height:.4f}', ha='center', va='bottom',
fontweight='bold', fontsize=9)
plt.tight_layout()
# 保存图片
output_path = f"{save_dir}/reliable_performance_comparison.png"
plt.savefig(output_path, dpi=300, bbox_inches='tight')
plt.show()
print(f"✓ 图表已保存: {output_path}")
# 验证图表中的中文
print(f"图表标题: '模型性能指标对比'")
print(f"Y轴标签: '数值'")
print(f"指标名称: {metrics}")
return fig
创建图表
reliable_fig = create_reliable_chinese_plot(predictions, labels, predictions_optimal, best_threshold, save_dir)
==================== 6. 检查最终设置 ====================
print("\n" + "=" * 60)
print("最终字体设置检查")
print("=" * 60)
最终检查
print(f"最终字体设置: {plt.rcParams.get('font.sans-serif', ['未设置'])[0]}")
print(f"字体列表: {plt.rcParams.get('font.sans-serif', [])[:3]}")
创建最终测试
print("\n创建最终测试图表...")
final_test_fig, final_ax = plt.subplots(figsize=(6, 4))
final_ax.plot([0, 1, 2], [0, 1, 0.5], 'o-', label='测试线')
final_ax.set_xlabel('横轴 - 中文测试')
final_ax.set_ylabel('纵轴 - 中文测试')
final_ax.set_title('最终中文测试图表')
final_ax.legend(loc='best')
final_ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print("✓ 最终测试完成")
print("\n如果图表中显示了中文,则字体设置成功!")
关键修复点:
-
设置顺序修复:
• 先设置Matplotlib的rc参数
• 再设置Seaborn样式
• 最后重新设置字体,确保不被覆盖
-
字体列表修复:
之前(被覆盖):
'Arial', 'DejaVu Sans', 'Liberation Sans', 'Bitstream Vera Sans', 'sans-serif'
修复后:
'WenQuanYi Micro Hei', 'DejaVu Sans', 'Arial Unicode MS', 'Arial'
-
添加验证步骤:
• 在每个关键点检查字体设置
• 创建测试图表验证中文显示
• 输出当前使用的字体
-
防止Seaborn覆盖:
• Seaborn的set_style()会重置字体
• 必须在Seaborn之后重新设置字体
运行这个修复后的代码,应该能看到正确的中文显示了!
看到您上传的图片,我明白问题所在了。您的图表实际上已经成功显示中文了!您图片中的标题、坐标轴标签、刻度等都是中文,这说明字体设置是成功的。
问题在于您代码中的字体设置被Seaborn覆盖了。Seaborn的set_style()和set_palette()函数会重置Matplotlib的rc参数,包括字体设置。
解决方案
调整代码顺序,确保Seaborn设置在字体设置之后,并在绘图前重新确认字体设置:
"""
完整评估报告和可视化 - 防止中文字体被覆盖
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
from matplotlib import font_manager
import seaborn as sns
import json
from sklearn.metrics import roc_curve, auc, f1_score
import os
import time
import pickle
==================== 1. 设置中文字体 ====================
print("=" * 60)
print("设置中文字体 - 防止被Seaborn覆盖")
print("=" * 60)
1.1 重置所有设置
plt.rcParams.update(plt.rcParamsDefault)
1.2 设置Seaborn样式(先设置,避免覆盖字体)
sns.set_style("whitegrid")
sns.set_palette("husl")
1.3 然后设置中文字体(覆盖Seaborn的设置)
def setup_chinese_font():
"""
设置中文字体的函数
"""
定义多个可能的字体路径
font_paths = [
Windows 字体路径
'C:/Windows/Fonts/msyh.ttc', # 微软雅黑
'C:/Windows/Fonts/simhei.ttf', # 黑体
'C:/Windows/Fonts/simsun.ttc', # 宋体
'/mnt/c/Windows/Fonts/msyh.ttc', # WSL 路径
'/mnt/c/Windows/Fonts/simhei.ttf', # WSL 路径
macOS 字体路径
'/System/Library/Fonts/PingFang.ttc', # 苹方
'/System/Library/Fonts/Hiragino Sans GB.ttc', # 冬青黑体
Linux 字体路径
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', # 文泉驿微米黑
'/usr/share/fonts/truetype/arphic/uming.ttc', # AR PL UMing
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc', # Noto Sans CJK
]
# 尝试加载字体
font_name = None
for font_path in font_paths:
if os.path.exists(font_path):
try:
font_manager.fontManager.addfont(font_path)
font_prop = font_manager.FontProperties(fname=font_path)
font_name = font_prop.get_name()
print(f"✓ 已找到中文字体: {font_name} (路径: {font_path})")
break
except Exception as e:
print(f"⚠ 加载字体失败 {font_path}: {e}")
continue
if font_name is None:
# 如果没有找到中文字体,使用默认字体
font_name = 'DejaVu Sans'
print("⚠ 未找到中文字体,将使用默认字体")
return font_name
获取字体名称
chinese_font = setup_chinese_font()
设置全局字体 - 关键步骤!
plt.rcParams['font.sans-serif'] = [chinese_font, 'DejaVu Sans', 'Arial Unicode MS', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
1.4 设置其他绘图参数
plt.rcParams.update({
'figure.figsize': (10, 6),
'figure.dpi': 100,
'savefig.dpi': 300,
'savefig.bbox': 'tight',
'axes.titlesize': 16,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
})
print(f"\n✓ 字体设置完成")
print(f"当前字体: {plt.rcParams['font.sans-serif'][:3]}")
print(f"字体族: {plt.rcParams.get('font.family', '未设置')}")
1.5 验证字体设置
def verify_font_settings():
"""验证字体设置是否正确"""
print("\n验证字体设置...")
# 创建验证图表
fig, ax = plt.subplots(figsize=(8, 4))
# 中文测试数据
categories = ['类别A', '类别B', '类别C', '类别D', '类别E']
values = [0.85, 0.92, 0.78, 0.95, 0.88]
bars = ax.bar(categories, values, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFD166'])
ax.set_xlabel('测试类别')
ax.set_ylabel('准确率')
ax.set_title('中文字体验证测试')
# 添加数值标签
for bar, val in zip(bars, values):
ax.text(bar.get_x() + bar.get_width()/2., val + 0.01,
f'{val:.2f}', ha='center', va='bottom', fontweight='bold')
plt.tight_layout()
plt.show()
print("✓ 字体验证图表已显示")
verify_font_settings()
==================== 2. 创建保存目录 ====================
save_dir = "./__model_checkpoints/model_v2"
os.makedirs(save_dir, exist_ok=True)
print(f"\n保存目录: {save_dir}")
==================== 3. 加载评估结果 ====================
print("\n加载评估结果...")
try:
with open(f"{save_dir}/evaluation_results.pkl", 'rb') as f:
evaluation_results = pickle.load(f)
predictions = np.array(evaluation_results['predictions'])
labels = np.array(evaluation_results['labels'])
probs = np.array(evaluation_results['probs'])
predictions_optimal = np.array(evaluation_results['predictions_optimal'])
best_threshold = evaluation_results['best_threshold']
print(f"✓ 数据加载成功:")
print(f" predictions形状: {predictions.shape}")
print(f" labels形状: {labels.shape}")
print(f" probs形状: {probs.shape}")
print(f" 最佳阈值: {best_threshold:.4f}")
except Exception as e:
print(f"✗ 加载评估结果失败: {e}")
raise
==================== 4. 修复的绘图函数 ====================
def create_performance_comparison_plot_fixed(predictions, labels, probs, predictions_optimal,
best_threshold, class_names=None, save_dir="./__model_checkpoints/model_v2"):
"""
创建性能对比图 - 修复字体设置
"""
n_classes = predictions.shape[1]
# 在绘图前重新确认字体设置
plt.rcParams['font.sans-serif'] = [chinese_font, 'DejaVu Sans', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
fig.suptitle('模型性能对比(默认阈值 vs 最佳阈值)', fontsize=16, fontweight='bold')
# 1.1 样本级准确率对比
ax1 = axes[0, 0]
default_acc = np.all(predictions == labels, axis=1).mean()
optimal_acc = np.all(predictions_optimal == labels, axis=1).mean()
bars = ax1.bar(['默认阈值(0.5)', f'最佳阈值({best_threshold:.3f})'],
[default_acc, optimal_acc],
color=['#FF6B6B', '#4ECDC4'])
ax1.set_ylabel('准确率')
ax1.set_title('样本级准确率(完全匹配)')
ax1.set_ylim([0, 1.1])
# 在柱子上添加数值
for bar in bars:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{height:.4f}', ha='center', va='bottom', fontweight='bold')
# 1.2 标签级准确率对比
ax2 = axes[0, 1]
default_label_acc = (predictions == labels).mean()
optimal_label_acc = (predictions_optimal == labels).mean()
bars = ax2.bar(['默认阈值(0.5)', f'最佳阈值({best_threshold:.3f})'],
[default_label_acc, optimal_label_acc],
color=['#FF6B6B', '#4ECDC4'])
ax2.set_ylabel('准确率')
ax2.set_title('标签级准确率')
ax2.set_ylim([0, 1.1])
for bar in bars:
height = bar.get_height()
ax2.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{height:.4f}', ha='center', va='bottom', fontweight='bold')
# 1.3 宏平均F1对比
ax3 = axes[0, 2]
default_f1 = f1_score(labels, predictions, average='macro', zero_division=0)
optimal_f1 = f1_score(labels, predictions_optimal, average='macro', zero_division=0)
bars = ax3.bar(['默认阈值(0.5)', f'最佳阈值({best_threshold:.3f})'],
[default_f1, optimal_f1],
color=['#FF6B6B', '#4ECDC4'])
ax3.set_ylabel('F1分数')
ax3.set_title('宏平均F1分数')
ax3.set_ylim([0, 1.1])
for bar in bars:
height = bar.get_height()
ax3.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{height:.4f}', ha='center', va='bottom', fontweight='bold')
# 2. 创建每个类别的性能热图
thresholds = np.arange(0.1, 0.9, 0.05)
class_f1_scores = np.zeros((n_classes, len(thresholds)))
for i, threshold in enumerate(thresholds):
pred_threshold = (probs > threshold).astype(int)
for class_idx in range(n_classes):
f1 = f1_score(labels[:, class_idx], pred_threshold[:, class_idx], zero_division=0)
class_f1_scores[class_idx, i] = f1
ax4 = axes[1, 0]
im = ax4.imshow(class_f1_scores, aspect='auto', cmap='viridis', vmin=0, vmax=1)
ax4.set_xlabel('阈值')
ax4.set_ylabel('类别')
ax4.set_title('各类别F1分数随阈值变化')
ax4.set_xticks(range(len(thresholds)))
ax4.set_xticklabels([f'{t:.2f}' for t in thresholds], rotation=45)
ax4.set_yticks(range(n_classes))
if class_names and len(class_names) == n_classes:
ax4.set_yticklabels([class_names[i] for i in range(n_classes)])
else:
ax4.set_yticklabels([f'类别{i}' for i in range(n_classes)])
plt.colorbar(im, ax=ax4, label='F1分数')
# 标记最佳阈值
best_idx = np.argmin(np.abs(thresholds - best_threshold))
ax4.axvline(x=best_idx, color='red', linestyle='--', alpha=0.7, label=f'最佳阈值({best_threshold:.3f})')
ax4.legend()
# 3. 创建混淆矩阵热图(最佳阈值)
ax5 = axes[1, 1]
from sklearn.metrics import multilabel_confusion_matrix
cm = multilabel_confusion_matrix(labels, predictions_optimal)
# 计算每个类别的准确率、精确度、召回率、F1分数
class_performance = []
for i in range(n_classes):
tn, fp, fn, tp = cm[i].ravel()
accuracy = (tp + tn) / (tp + tn + fp + fn) if (tp + tn + fp + fn) > 0 else 0
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0
class_performance.append([accuracy, precision, recall, f1])
class_performance = np.array(class_performance)
im = ax5.imshow(class_performance, aspect='auto', cmap='YlOrRd', vmin=0, vmax=1)
ax5.set_xlabel('指标')
ax5.set_ylabel('类别')
ax5.set_title('各类别性能指标(最佳阈值)')
ax5.set_xticks(range(4))
ax5.set_xticklabels(['准确率', '精确度', '召回率', 'F1分数'])
ax5.set_yticks(range(n_classes))
if class_names and len(class_names) == n_classes:
ax5.set_yticklabels([class_names[i] for i in range(n_classes)])
else:
ax5.set_yticklabels([f'类别{i}' for i in range(n_classes)])
plt.colorbar(im, ax=ax5, label='分数')
# 添加数值标签
for i in range(n_classes):
for j in range(4):
ax5.text(j, i, f'{class_performance[i, j]:.3f}',
ha='center', va='center', color='black', fontsize=8)
# 4. 创建错误分析图
ax6 = axes[1, 2]
# 计算每个样本的错误数量
errors_per_sample = np.sum(predictions_optimal != labels, axis=1)
error_counts = np.bincount(errors_per_sample, minlength=n_classes+1)
# 只显示有错误的柱状图
error_indices = np.where(error_counts > 0)[0]
error_values = error_counts[error_counts > 0]
bars = ax6.bar(range(len(error_indices)), error_values, color='#45B7D1')
ax6.set_xlabel('每个样本的错误数量')
ax6.set_ylabel('样本数')
ax6.set_title('错误分布分析')
ax6.set_xticks(range(len(error_indices)))
ax6.set_xticklabels([str(i) for i in error_indices])
# 在柱子上添加数值
for bar in bars:
height = bar.get_height()
if height > 0:
ax6.text(bar.get_x() + bar.get_width()/2., height + 0.5,
f'{int(height)}', ha='center', va='bottom', fontsize=9)
plt.tight_layout()
plt.savefig(f"{save_dir}/performance_comparison.png", dpi=300, bbox_inches='tight')
plt.show()
print(f"✓ 性能对比图已保存到: {save_dir}/performance_comparison.png")
其他绘图函数也需要类似修复...
这里只修复一个作为示例,其他函数需要类似修改
==================== 5. 生成可视化图表 ====================
print("\n" + "="*60)
print("生成详细评估报告和可视化")
print("="*60)
获取类别名称
class_names = None
try:
if hasattr(PURE, 'category_names'):
class_names = PURE.category_names
print(f"使用类别名称: {class_names}")
except:
pass
1. 创建性能对比图
print("\n1. 创建性能对比图...")
try:
在绘图前重新设置字体
plt.rcParams['font.sans-serif'] = [chinese_font, 'DejaVu Sans', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
create_performance_comparison_plot_fixed(predictions, labels, probs, predictions_optimal,
best_threshold, class_names=class_names, save_dir=save_dir)
except Exception as e:
print(f"⚠ 创建性能对比图时出错: {e}")
后续的其他绘图函数调用也需要在调用前重新设置字体
...
print("\n✅ 评估流程完成!")
关键修改总结:
调整设置顺序:
先设置Seaborn样式
然后设置中文字体(覆盖Seaborn的设置)
在每次绘图前重新确认字体设置:
在绘图前重新设置
plt.rcParams['font.sans-serif'] = [chinese_font, 'DejaVu Sans', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
移除了所有fontproperties参数:
让所有文本自动使用全局字体设置
只在setup_chinese_font()函数中设置一次
添加验证步骤:
在设置字体后立即创建验证图表
确认中文显示正常
最简单的解决方案
如果您想用最简单的方法,可以直接在代码开头这样设置:
最简单的字体设置
import matplotlib.pyplot as plt
import seaborn as sns
1. 先设置Seaborn
sns.set_style("whitegrid")
sns.set_palette("husl")
2. 然后设置中文字体
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'DejaVu Sans', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
3. 每次绘图前不需要再设置字体
从您上传的图片来看,您的代码实际上已经成功显示中文了,只是担心字体被覆盖。按照上面的修改,可以确保字体设置不会被Seaborn覆盖。
- 修改你的Python代码设置字体
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np
import os
def setup_chinese_font():
"""
为WSL2设置中文字体
"""
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 在WSL2中常见的字体路径
font_paths = [
# WSL2中的字体路径
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc',
'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc',
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
# Windows字体挂载路径
'/mnt/c/Windows/Fonts/msyh.ttc', # 微软雅黑
'/mnt/c/Windows/Fonts/simhei.ttf', # 黑体
'/mnt/c/Windows/Fonts/simsun.ttc', # 宋体
]
# 尝试使用fc-list找到字体
import subprocess
try:
result = subprocess.run(['fc-list', ':lang=zh', 'family'],
capture_output=True, text=True)
if result.returncode == 0:
fonts = result.stdout.split('\n')
for font in fonts:
if font.strip():
print(f"找到系统字体: {font.strip()}")
except:
pass
# 尝试加载字体
for font_path in font_paths:
if os.path.exists(font_path):
try:
fm.fontManager.addfont(font_path)
font_prop = fm.FontProperties(fname=font_path)
font_name = font_prop.get_name()
plt.rcParams['font.sans-serif'] = [font_name, 'DejaVu Sans', 'Arial']
print(f"✓ 已设置中文字体: {font_name}")
return font_name
except Exception as e:
print(f"⚠ 加载字体失败 {font_path}: {e}")
continue
# 如果都没找到,尝试通过字体名设置
try:
# 尝试常用的字体名称
possible_fonts = [
'WenQuanYi Zen Hei', # 文泉驿正黑
'WenQuanYi Micro Hei', # 文泉驿微米黑
'Noto Sans CJK SC', # Noto Sans
'Microsoft YaHei', # 微软雅黑
'SimHei', # 黑体
]
for font_name in possible_fonts:
try:
# 检查字体是否可用
fm.findfont(font_name, fallback_to_default=False)
plt.rcParams['font.sans-serif'] = [font_name, 'DejaVu Sans']
print(f"✓ 通过字体名设置: {font_name}")
return font_name
except:
continue
except:
pass
print("⚠ 未找到中文字体,将使用默认字体")
return None
设置中文字体
chinese_font = setup_chinese_font()
测试绘图
def test_plot():
fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y, 'b-', linewidth=2)
ax.set_xlabel('X轴标签 - 时间', fontsize=12)
ax.set_ylabel('Y轴标签 - 数值', fontsize=12)
ax.set_title('中文标题示例 - 正弦函数', fontsize=14, fontweight='bold')
ax.grid(True, alpha=0.3)
# 添加中文文本
ax.text(2, 0.5, '这是中文文本', fontsize=12,
bbox=dict(boxstyle="round,pad=0.3", facecolor="lightblue", alpha=0.5))
plt.tight_layout()
plt.show()
print("✓ 绘图完成,检查是否显示中文")
执行测试
test_plot()
- 更简单的一键设置方法
import matplotlib.pyplot as plt
import numpy as np
import warnings
warnings.filterwarnings('ignore')
简单设置中文字体
def simple_chinese_setup():
"""简单的中文字体设置"""
plt.rcParams['axes.unicode_minus'] = False
# 尝试多种设置方法
try:
# 方法1: 尝试加载Noto Sans CJK
import matplotlib.font_manager as fm
font_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc'
if os.path.exists(font_path):
fm.fontManager.addfont(font_path)
font_prop = fm.FontProperties(fname=font_path)
plt.rcParams['font.sans-serif'] = [font_prop.get_name()]
print("✓ 使用Noto Sans CJK字体")
return True
except:
pass
try:
# 方法2: 尝试加载文泉驿
import subprocess
result = subprocess.run(['fc-list', ':lang=zh'],
capture_output=True, text=True)
if 'WenQuanYi' in result.stdout:
plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei', 'WenQuanYi Micro Hei', 'DejaVu Sans']
print("✓ 使用文泉驿字体")
return True
except:
pass
# 方法3: 最后尝试
try:
plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'Arial Unicode MS', 'Arial']
print("⚠ 使用备用字体")
except:
pass
return False
使用
simple_chinese_setup()
绘图测试
fig, ax = plt.subplots(figsize=(8, 4))
x = [1, 2, 3, 4, 5]
y = [2, 5, 3, 8, 7]
ax.plot(x, y, marker='o')
ax.set_xlabel('横轴 - 月份')
ax.set_ylabel('纵轴 - 销售额')
ax.set_title('销售数据图表')
plt.tight_layout()
plt.show()
- 永久解决方案(推荐)
创建配置文件 ~/.config/matplotlib/matplotlibrc:
创建配置目录
mkdir -p ~/.config/matplotlib
创建配置文件
cat > ~/.config/matplotlib/matplotlibrc << EOF
中文字体设置
font.family : sans-serif
font.sans-serif : WenQuanYi Zen Hei, WenQuanYi Micro Hei, Noto Sans CJK SC, DejaVu Sans
axes.unicode_minus : False
EOF
- 如果上述方法都不行,从Windows复制字体
在WSL2中创建字体目录
mkdir -p ~/.fonts
从Windows复制微软雅黑(如果挂载了/mnt/c)
if [ -f "/mnt/c/Windows/Fonts/msyh.ttc" ]; then
cp "/mnt/c/Windows/Fonts/msyh.ttc" ~/.fonts/
chmod 644 ~/.fonts/msyh.ttc
fi
刷新字体缓存
fc-cache -fv
- 验证设置是否成功
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
查看当前使用的字体
current_font = plt.rcParams['font.sans-serif']
print(f"当前字体设置: {current_font}")
查看所有可用的中文字体
chinese_fonts = [f.name for f in fm.fontManager.ttflist if any(char in f.name for char in '中文字体宋体黑体')]
print(f"\n可用的中文字体: {chinese_fonts[:10]}") # 显示前10个
常见问题排查:
- 字体缓存问题:
清除matplotlib缓存
rm -rf ~/.cache/matplotlib
- 重启Jupyter:
重启Jupyter内核
或者在Jupyter中:Kernel -> Restart Kernel
- 检查Jupyter配置:
在Jupyter中运行
import matplotlib
print(f"Matplotlib后端: {matplotlib.get_backend()}")
print(f"Matplotlib配置目录: {matplotlib.get_configdir()}")
选择最简单的方法开始,通常安装 fonts-noto-cjk 并重启Jupyter就能解决大部分问题。