在科研论文中,模型性能对比图是展示实验结果的核心手段。常见的柱状图、雷达图虽然直观,但在呈现多个模型、多项指标时往往显得拥挤或不够美观。本文介绍一种"环形柱状图"(Radial Bar Chart)的 Python 绘制方法,利用极坐标与 matplotlib 的 barh 结合,让数据从圆心向外层层展开,视觉上更具层次感与冲击力,尤其适合机器学习模型的性能对比场景。

核心思路是将 matplotlib 的 projection='polar'(极坐标)模式与 barh(横向柱状图)结合。barh 的 y 轴控制每个环的半径位置,x 轴(实际是角度)控制柱子的长度。inner_radius = 3.0 定义内圈半径,使圆心区域留白,营造环形感;bar_height 控制每个环的厚度;theta_values 将数值线性映射到角度范围(0 到 1.5π,约 270°),留出缺口让图表更透气。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv('model_metrics.csv')
labels = df['Model'].values
values = df['Accuracy'].values
colors = ['#4E342E', '#BF360C', '#F57C00', '#FBC02D', '#DCE775', '#7CB342']
N = len(labels)
bar_height = 0.65
inner_radius = 3.0
y_pos = np.arange(N) + inner_radius
max_ref = 1.1
theta_values = (values / max_ref) * (1.5 * np.pi)
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': 'polar'})
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
极坐标中文字右对齐的实现有一个精巧的细节:极坐标下弧长 s = r × θ,要保证标签与柱子起点的物理距离恒定,θ 必须随半径 r 变化。具体公式为 angle_offset = -(固定距离 / 半径)。这样无论标签落在内圈还是外圈,与柱子的间距都完全一致,整张图的对齐感非常舒适,远比直接给每个标签设置固定 x 坐标更好。
fixed_distance_offset = 0.4# 控制标签与柱子起点的物理距离
for i, (bar, value, label) in enumerate(zip(bars, values, labels)):
label_text = f"{label} = ({value:.3f})"
radius = y_pos[i]
angle_offset = - (fixed_distance_offset / radius)
ax.text(x=angle_offset, y=radius, s=label_text,
ha='right', va='center',
fontsize=12, fontname='Times New Roman', color='black')
进阶版脚本将四个指标(Accuracy、Precision、Recall、F1-Score)以 2×2 子图布局呈现在一张画布上,同时提供 Nature、Lancet、Science、用户自定义四套配色方案,通过循环自动生成四张不同风格的大图。这种设计在科研投稿时尤为实用——只需选择合适的配色包,就能快速匹配目标期刊的视觉风格,大幅提升制图效率。
color_palettes = {
'Nature_NPG': ['#3C5488', '#00A087', '#4DBBD5', '#E64B35', '#F39B7F', '#8491B4'],
'Lancet': ['#00468B', '#ED0000', '#42B540', '#0099B4', '#925E9F', '#FDAF91'],
'Science_AAAS': ['#374E55', '#DF8F44', '#00A1D5', '#B24745', '#79AF97', '#6A6599'],
'User_Style': ['#B22222', '#00468B', '#228B22', '#008B8B', '#800080', '#FA8072']
}
fig, axes = plt.subplots(2, 2, figsize=(15, 15), subplot_kw={'projection': 'polar'})
for idx, metric in enumerate(metrics):
ax = axes.flatten()[idx]
values = df[metric].values
theta_values = (values / max_ref) * (1.5 * np.pi)
ax.barh(y_pos, theta_values, height=bar_height, color=colors[:N], align='center', left=0)
多子图场景下,为每个子图单独添加图例会显得冗余。更优的做法是使用 fig.legend()(而非 ax.legend())将图例置于整张画布的几何中心。关键参数是 loc='center' 配合 bbox_to_anchor=(0.5, 0.5),将图例锁定在画布正中央,同时通过 transform=fig.transFigure 确保坐标参考系是整个 Figure 而非某个子图。图例句柄的顺序需要与环的排列顺序对应反转,让最外圈模型显示在图例最上方,与视觉层次保持一致。
legend_handles = [mpatches.Patch(color=c, label=l)
for c, l in zip(reversed(current_colors), reversed(fixed_models))]
font_prop = {'family': 'Times New Roman', 'size': 13}
fig.legend(handles=legend_handles,
loc='center',
bbox_to_anchor=(0.5, 0.5),
frameon=False,
title="Model Comparison",
title_fontsize=14,
prop=font_prop,
handlelength=1.5, handleheight=1.5)
plt.subplots_adjust(wspace=0.4, hspace=0.35)
plt.savefig(f'CenterLegend_{palette_name}.jpeg', dpi=600, format='jpeg', bbox_inches='tight')
最终输出的图表以环形阵列展示六个模型的性能,从圆心向外依次递增,四项指标分据四个象限,中心图例统一标注模型与颜色映射关系。整套方案的优势在于:数据处理逻辑极简(只需一个排序好的 CSV)、绘图参数高度可复用(配色、子图数量均可配置)、输出质量可达期刊级别的 600 DPI。只需替换自己的 CSV 数据文件即可完整出图。
现在绘图代码都不支持免费获取了,20/篇文章。同时欢迎加入小编科研绘图VIP群,258/年,所有科研绘图相关文章代码免费获取,涵盖机器学习模型(回归和分类)的shap分析、还有各种如皮尔逊分析等相关的图,以及期刊复现图,源代码直接复制或者打开就能绘图。同时进群赠送SHAP科研分析软件5.0,且免费更新使用。VX:GISyanjiushengya!!!

