在WSL2的Jupyter中正确显示中文字体seaborn覆盖plt的问题

在WSL2的Jupyter中正确显示中文字体,需要以下几个步骤:

解决方案

  1. 安装中文字体到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

  1. 检查已安装的字体

查看已安装的中文字体

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"。这说明字体设置被覆盖了。

问题分析

从图片可以看出,中文确实显示了,但字体设置显示的是英文字体。这很可能是因为:

  1. Seaborn 覆盖了字体设置 - Seaborn 在设置样式时会重置字体
  2. 设置顺序问题 - 字体设置在 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如果图表中显示了中文,则字体设置成功!")

关键修复点:

  1. 设置顺序修复:

    • 先设置Matplotlib的rc参数

    • 再设置Seaborn样式

    • 最后重新设置字体,确保不被覆盖

  2. 字体列表修复:

    之前(被覆盖):

    'Arial', 'DejaVu Sans', 'Liberation Sans', 'Bitstream Vera Sans', 'sans-serif'

    修复后:

    'WenQuanYi Micro Hei', 'DejaVu Sans', 'Arial Unicode MS', 'Arial'

  3. 添加验证步骤:

    • 在每个关键点检查字体设置

    • 创建测试图表验证中文显示

    • 输出当前使用的字体

  4. 防止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覆盖。

  1. 修改你的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()

  1. 更简单的一键设置方法

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()

  1. 永久解决方案(推荐)

创建配置文件 ~/.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

  1. 如果上述方法都不行,从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

  1. 验证设置是否成功

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个

常见问题排查:

  1. 字体缓存问题:

清除matplotlib缓存

rm -rf ~/.cache/matplotlib

  1. 重启Jupyter:

重启Jupyter内核

或者在Jupyter中:Kernel -> Restart Kernel

  1. 检查Jupyter配置:

在Jupyter中运行

import matplotlib

print(f"Matplotlib后端: {matplotlib.get_backend()}")

print(f"Matplotlib配置目录: {matplotlib.get_configdir()}")

选择最简单的方法开始,通常安装 fonts-noto-cjk 并重启Jupyter就能解决大部分问题。

相关推荐
yousuotu2 小时前
基于Python实现亚马逊销售数据分析与预测
开发语言·python·数据分析
m0_462605222 小时前
第N11周:seq2seq翻译实战-Pytorch复现
人工智能·pytorch·python
张登杰踩2 小时前
django后台管理配置教程
后端·python·django
laocooon5238578862 小时前
对传入的 x , y 两个数组做折线图, x 对应 x 轴, y 对应 y 轴。并保存到 Task1/image1/T2.png
python·numpy·pandas·matplotlib
羽飞2 小时前
GCC ABI炸弹
linux·c++·python
JH灰色2 小时前
【大模型】-AutoGen Studio的搭建
python·语言模型
趁月色小酌***2 小时前
JAVA 知识点总结3
java·开发语言·python
智航GIS2 小时前
6.1 for循环
开发语言·python·算法
冬至喵喵2 小时前
FLINK故障重启策略
大数据·python·flink