当前位置:首页>python>科研绘图 | 基于Python绘制多模型性能对比雷达图

科研绘图 | 基于Python绘制多模型性能对比雷达图

  • 2026-09-30 11:26:21
科研绘图 | 基于Python绘制多模型性能对比雷达图

雷达图(Radar Chart),也被称为蜘蛛图(Spider Chart),是一种非常有效的多维度数据可视化工具。在机器学习模型比较、性能评估等场景中,雷达图能够直观地展示多个模型在不同指标上的表现,快速识别各模型的优势和劣势。

本文将详细介绍如何使用Python和matplotlib库,从CSV数据文件开始,一步步构建一个专业、美观的多模型比较雷达图。将实现以下功能:

  • Nature风格的专业图表:使用Times New Roman字体,符合学术期刊发表标准
  • 智能标签旋转:外环标签自动沿圆环方向排列,保证可读性
  • 多套配色方案:提供4种不同的配色方案,适应不同场景需求
  • 批量导出功能:一键生成单图和拼图,方便论文使用

结果

同时每个单图也会自动保存!!

一、环境准备与基础设置

在开始绘制之前,需要导入必要的库,并设置matplotlib的全局参数。这些设置将确保生成的图表符合学术期刊的发表标准,特别是Nature等顶级期刊对图表格式的要求。

首先,导入核心库:numpy用于数值计算,pandas用于数据处理,matplotlib用于绘图。然后,配置matplotlib的全局参数,包括字体、字号、线条宽度等。这些设置将应用到所有后续绘制的图表中。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom matplotlib import rcParams# =========================# 0. 基础设置 (Nature 风格)# =========================config = {"font.family": 'serif',"font.serif": ['Times New Roman'], "mathtext.fontset": 'stix',"font.size": 12,"axes.linewidth": 1.0,"figure.dpi": 300,}rcParams.update(config)

关键设置说明:

  • 字体设置:使用serif字体族,并指定Times New Roman作为首选字体。这是学术期刊常用的字体,具有专业、正式的外观。

  • 数学公式字体:mathtext.fontset设置为stix,确保数学公式与正文字体风格一致。

  • 字号和线条:基础字号设为12pt,坐标轴线宽设为1.0,这些都是期刊发表的标准设置。

  • 分辨率:figure.dpi设为300,确保导出的图片具有足够的分辨率,适合印刷和在线发表。


二、数据读取与预处理

数据是可视化的基础。设计为读取CSV格式的数据文件,其中第一列是模型名称(Model列),其余列是各种评估指标(如Accuracy、Precision、Recall等)。

这个函数的设计非常简洁高效:它读取CSV文件,将数据分为模型名称列表、指标名称列表和数值矩阵三部分。这种分离式的数据结构使得后续处理更加清晰和灵活。

# =========================# 1. 数据读取# =========================CSV_NAME = "model_performance.csv"def_read_table(csv_path):# 三行读取:Model列=模型名,其余列=指标    data = pd.read_csv(csv_path)    X = data.drop(columns=["Model"])    y = data["Model"]return y.astype(str).tolist(), X.columns.tolist(), X.astype(float).to_numpy()

函数解析:

  • 数据分离:使用drop(columns=["Model"])将模型名称列分离出来,剩余的列就是各个评估指标。

  • 类型转换:模型名称转换为字符串列表,指标名称直接获取列名,数值数据转换为numpy数组以便后续计算。

  • 返回值:返回三个值,分别是模型名称列表、指标名称列表和数值矩阵。这种设计使得函数调用非常直观。

三、核心工具函数详解

3.1 环形标签绘制函数

这是整个代码中最关键也最复杂的函数之一。在极坐标图中,标签的旋转角度计算需要特别小心,因为matplotlib的极坐标系统有theta_offset(角度偏移)和theta_direction(方向)两个参数,这些参数会影响标签的实际显示位置。

如果简单地使用原始角度,标签可能会出现倒置或方向错误的问题。函数通过计算"显示角度"(考虑了偏移和方向),然后让文字沿着圆环的切线方向排列,并在下半圆自动翻转,确保文字始终可读。

def_draw_ring_label(ax, text, angle_rad, radius, fontsize=12):# 需要用"显示角度"(考虑 theta_offset / theta_direction),否则会出现 AUC 等标签朝向不对    display_theta = ax.get_theta_direction() * angle_rad + ax.get_theta_offset()    angle_deg = (np.degrees(display_theta) + 360) % 360# 让文字沿切线方向放置;并在下半圆翻转,保证可读    rotation = angle_deg - 90    rotation = (rotation + 180) % 360 - 180# 归一化到 [-180, 180]if rotation < -90or rotation > 90:        rotation += 180        rotation = (rotation + 180) % 360 - 180    ax.text(        angle_rad,        radius,        text,        ha="center",        va="center",        rotation=rotation,        rotation_mode="anchor",        fontsize=fontsize,        fontweight="bold",        color="black",        zorder=5,    )

算法详解:

  1. 显示角度计算:display_theta = ax.get_theta_direction() * angle_rad + ax.get_theta_offset()

    • 这里考虑了极坐标的方向(顺时针或逆时针)和偏移量(通常设为π/2,使0度在顶部)
  2. 角度归一化:将角度转换为0-360度的范围,避免负角度带来的问题

  3. 切线方向计算:rotation = angle_deg - 90

    • 减去90度是为了让文字垂直于半径方向,即沿着圆环的切线方向
  4. 可读性优化:如果旋转角度在-90到90度之外,文字会倒置,此时需要翻转180度,确保文字始终正向可读

  5. 文本绘制:使用rotation_mode="anchor"确保文字围绕锚点旋转,而不是围绕中心点

3.2 四舍五入函数

在设置坐标轴刻度时,经常需要将数值四舍五入到指定的小数位数。Python内置的round函数使用的是"银行家舍入法"(round half to even),这在某些情况下可能不符合预期。实现了一个标准的四舍五入函数,使用Decimal模块确保精度。

def_round_half_up(x: float, ndigits: int = 2) -> float:from decimal import Decimal, ROUND_HALF_UPif ndigits <= 0:        q = Decimal("1")else:        q = Decimal("0." + "0" * (ndigits - 1) + "1")return float(Decimal(str(x)).quantize(q, rounding=ROUND_HALF_UP))

函数特点:

  • 精确控制:使用Decimal类型避免浮点数精度问题
  • 标准四舍五入:ROUND_HALF_UP确保0.5总是向上舍入
  • 灵活的小数位数:可以指定任意小数位数

四、雷达图绘制核心函数

这是整个代码的核心部分,plot_radar函数负责绘制完整的雷达图。这个函数设计得非常全面,包含了雷达图的所有要素:外环标签、网格线、数据系列、图例等。

4.1 函数参数与初始化

函数接受多个参数,包括模型名称、指标名称、数值矩阵、线条颜色、外环颜色等。这种参数化的设计使得函数具有很高的灵活性。

defplot_radar(    ax,    model_names: list[str],    metric_names: list[str],    values: np.ndarray,    line_colors_local: list[str],    ring_colors_local: list[str],    *,    annotate: str | None = None,    legend: bool = True,    legend_fontsize: float = 11,    label_fontsize: float = 12.0,):from matplotlib.lines import Line2D    n_models = len(model_names)    n_metrics = len(metric_names)    angles = np.linspace(0, 2 * np.pi, n_metrics, endpoint=False)    angles_closed = np.concatenate([angles, [angles[0]]])

关键初始化:

  • 角度计算:使用np.linspace将360度(2π)均匀分配给各个指标
  • 闭合角度:angles_closed在末尾添加第一个角度,使得多边形能够闭合
  • 数量统计:记录模型数量和指标数量,用于后续循环

4.2 坐标系统与范围设置

雷达图的坐标系统设置至关重要。需要确定网格的最大半径、外环的位置和宽度等。这些参数都是基于数据的最大值动态计算的。

    max_val = float(np.max(values)) if values.size else1.0    r_grid_max = 1.10if max_val <= 1.0else _round_half_up(max_val, 2)    r_ring_inner = r_grid_max    r_ring_width = r_grid_max * 0.155    r_outer = r_ring_inner + r_ring_width    r_ring_mid = r_ring_inner + r_ring_width / 2    ax.figure.patch.set_facecolor("white")    ax.set_facecolor("white")    ax.set_theta_offset(np.pi / 2)    ax.set_theta_direction(-1)    ax.set_ylim(0, r_outer + r_grid_max * 0.03)    ax.set_axisbelow(True)

参数说明:

  • 动态范围:如果最大值不超过1.0,使用1.10作为网格最大值;否则使用四舍五入后的最大值
  • 外环设计:外环的内半径等于网格最大值,宽度为最大值的15.5%,这样设计使得外环与网格紧密贴合
  • 极坐标设置:
    • theta_offset=np.pi/2:使0度位于顶部(12点钟方向)
    • theta_direction=-1:设置为顺时针方向(符合常规习惯)
  • 背景色:统一设置为白色,确保图表干净整洁

4.3 外环标签绘制

外环是雷达图的重要视觉元素,它不仅美观,更重要的是承载了指标名称。使用ax.bar函数绘制扇形块,每个扇形对应一个指标,颜色各不相同。

    seg_width = 2 * np.pi / n_metricsfor i, (ang, label) in enumerate(zip(angles, metric_names)):        ax.bar(            ang - seg_width / 2,            r_ring_width,            width=seg_width,            bottom=r_ring_inner,            align="edge",            color=ring_colors_local[i % len(ring_colors_local)],            edgecolor="white",            linewidth=2.0,            zorder=1,        )        _draw_ring_label(ax, label, ang, radius=r_ring_mid, fontsize=label_fontsize)

绘制细节:

  • 扇形宽度:seg_width = 2π / n_metrics,确保所有扇形均匀分布
  • 位置调整:ang - seg_width / 2使扇形以角度为中心对称
  • 颜色循环:使用取模运算i % len(ring_colors_local),即使指标数量超过颜色数量也能正常工作
  • 白色边框:edgecolor="white"和linewidth=2.0创建明显的分隔线
  • 标签绘制:调用_draw_ring_label函数,标签会自动沿圆环方向排列

4.4 网格线与坐标轴设置

网格线帮助读者准确读取数值,设置了径向网格线(虚线)和同心圆网格线,并配置了坐标轴刻度。

    ax.set_xticks(angles)    ax.set_xticklabels([""] * n_metrics)    ax.set_rlabel_position(0)    yticks = [        _round_half_up(r_grid_max * 0.25, 2),        _round_half_up(r_grid_max * 0.50, 2),        _round_half_up(r_grid_max * 0.75, 2),        _round_half_up(r_grid_max, 2),    ]    ax.set_yticks(yticks)    ax.set_yticklabels([f"{t:g}"for t in yticks], fontsize=10, fontweight="bold", color="black")    grid_color = "#7F7F7F"    ax.yaxis.grid(True, linestyle="--", linewidth=0.9, color=grid_color, alpha=0.6)    ax.xaxis.grid(True, linestyle="--", linewidth=0.8, color=grid_color, alpha=0.5)    ax.spines["polar"].set_color("#333333")    ax.spines["polar"].set_linewidth(1.8)    theta = np.linspace(0, 2 * np.pi, 720)    ax.plot(theta, np.full_like(theta, r_outer), color="#333333", linewidth=1.2, alpha=0.9, zorder=2)

网格设计要点:

  • 刻度位置:使用25%、50%、75%、100%四个位置,这是雷达图的标准设置
  • 格式优化:f"{t:g}"自动去除不必要的零和小数点
  • 网格样式:使用灰色虚线,透明度适中,既清晰又不抢夺数据焦点
  • 外环实线:在网格最外层绘制一条实线,增强视觉边界

4.5 数据系列绘制

这是雷达图的核心部分,为每个模型绘制一条多边形线,并填充淡色区域。所有模型使用统一的圆形标记,只通过颜色区分。

# 统一圆点 marker(图例与 RF 一致),只变化颜色for i in range(n_models):        row = values[i, :]        row_closed = np.concatenate([row, [row[0]]])        c = line_colors_local[i % len(line_colors_local)]        ax.fill(angles_closed, row_closed, color=c, alpha=0.05, zorder=3)        ax.plot(            angles_closed,            row_closed,            color=c,            linewidth=1.6,            marker="o",            markersize=5,            markerfacecolor=c,            markeredgecolor="white",            markeredgewidth=0.9,            zorder=4,        )

绘制策略:

  • 填充区域:使用ax.fill绘制填充区域,alpha=0.05使得填充非常淡,不会遮挡其他数据
  • 线条样式:线宽1.6,确保清晰可见
  • 标记设计:
    • 统一使用圆形标记(marker="o")
    • 标记大小适中(markersize=5)
    • 白色边框(markeredgecolor="white")增强对比度
    • 边框宽度0.9,使标记更加精致
  • 图层顺序:使用zorder参数控制绘制顺序,确保标记在最上层

五、批量导出多套配色方案

在实际应用中,经常需要尝试不同的配色方案,以适应不同的论文风格或期刊要求。export_multi_palette函数实现了批量生成多套配色方案的功能。

5.1 配色方案定义

定义了4套不同的配色方案,每套都有其特点和适用场景。

defexport_multi_palette():    palettes = [        ("P1", "Classic (Red/Blue/Orange/Green)", ["#C00000", "#2E75B6", "#E69F00", "#2CA02C", "#9467BD", "#8C564B"]),        ("P2","Okabe-Ito",            ["#0072B2", "#D55E00", "#009E73", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442", "#000000"],        ),        ("P3", "Tableau(tab10)", "tab10"),        ("P4", "Dark2", "Dark2"),    ]    ring_colors_local = ["#B7DEE8","#C5D9F1","#F4CCCC","#F9CB9C","#FFE599","#D9EAD3","#D0E0E3","#D9D2E9","#FCE5CD","#FFF2CC","#EAD1DC","#D0CECE",    ]

配色方案说明:

  • P1 - Classic:经典配色,使用红、蓝、橙、绿等常见颜色,适合大多数场景
  • P2 - Okabe-Ito:色盲友好配色方案,经过科学设计,确保色盲患者也能区分
  • P3 - Tableau:Tableau软件的标准配色,专业且美观
  • P4 - Dark2:较深的色调,适合需要强调对比的场景

外环颜色:使用柔和的 pastel 色调,12种颜色循环使用,确保外环美观且不抢夺数据焦点。

六、总结

  1. 准备数据:将模型性能数据保存为CSV文件,格式如前文所示
  2. 修改文件名:如果CSV文件名不是model_performance.csv,修改CSV_NAME变量
  3. 运行程序:直接运行Python脚本
  4. 查看结果:程序会在当前目录生成5张图片(四个配色单图和一个总图):
    • model_performance_radar_P1.jpeg
    • model_performance_radar_P2.jpeg
    • model_performance_radar_P3.jpeg
    • model_performance_radar_P4.jpeg
    • model_performance_radar_4palettes.jpeg

现在绘图代码都不支持免费获取了,20/篇文章,同时欢迎加入小编科研绘图VIP群,198/年,保证每年更新40篇以上的科研绘图相关文章,涵盖机器学习模型(回归和分类)的shap分析、还有各种如皮尔逊分析等相关的图,以及期刊复现图,源代码直接复制或者打开就能绘图。同时进群还赠送微信推文中所有绘图代码以及科研绘图SHAP分析软件和依赖图分析软件,且免费更新使用。后期还会免费赠送一些科研绘图小软件,还有拼图软件(开发中)!!!!

最新文章

随机文章