Python matplotlib绘制极坐标雷达图:多主体对比与单主体子图实现

沈知远
沈知远
发布时间:2026-10-16 | 5人浏览过
原创

本文详细介绍如何使用Python的matplotlib库绘制极坐标雷达图。内容涵盖多主体雷达图的绘制,包括数据预处理、角度计算、封闭多边形处理及颜色填充;同时讲解如何将单主体雷达图拆分为多个子图进行对比展示,涉及subplot子图创建、循环遍历绘图及样式调整等关键步骤。

综述

Python的matplotlib绘图库功能强大,能够绘制多种类型的图表,其中也包括雷达图。

雷达图,又称网络图、蜘蛛图或星图,是一种不规则的多边形图形。它能够直观地展示同一事物在不同维度上的指标表现,应用场景广泛。例如,在本文中,我们利用雷达图来对比不同球员的各项能力值。

matplotlib库中绘制雷达图的基础是极坐标系,因此所有的数据点和标签都需要根据角度来计算其在坐标系中的位置。

本文将详细解析绘制雷达图的思路、具体步骤以及各个函数方法的用法,如有不当之处,欢迎指正。

绘图代码和解析

绘制一张多主体雷达图

所谓多主体雷达图,是指在一张图表中显示由多个多边形组成的属性图,从而形成直观的对比效果。

预处理

首先需要安装所需的库,并解决中文和符号显示的问题,设置默认字体,同时修改绘图样式。

加载数据集(数据来源:某足球APP),从字典中提取键和值,分别保存在labels和score变量中。

import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['KaiTi']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
plt.style.use('ggplot')  # 设置ggplot主题样式

# 原始数据集并获取数据集长度
results = [{"速度": 68, "射门": 91, "传球": 83, "盘带": 83, "防守": 47, "力量": 82},
           {"速度": 88, "射门": 87, "传球": 82, "盘带": 86, "防守": 42, "力量": 69},
           {"速度": 58, "射门": 55, "传球": 70, "盘带": 67, "防守": 86, "力量": 77}]
data_length = len(results[0])

 # 将极坐标根据数据长度进行等分,形成角度列表
angles = np.linspace(0, 2 * np.pi, data_length, endpoint=False)

# 分离属性字段和数据
labels = [key for key in results[0].keys()]
score = [[v for v in result.values()] for result in results]

封闭雷达图

由于绘制出的图形是一个封闭的多边形,而提取出的score、labels和angles数据的每一项并不是首尾相接的,因此需要将每个列表的第一项复制并添加到列表末尾,以实现封闭。

angles = np.concatenate((angles, [angles[0]]))
labels = np.concatenate((labels, [labels[0]]))
score_Harry = np.concatenate((score[0], [score[0][0]]))
score_Son = np.concatenate((score[1], [score[1][0]]))
score_Tobi = np.concatenate((score[2], [score[2][0]]))

这里因为涉及三个球员的数据,所以有三组score数据。

这里提及np.concatenate函数,这是numpy库中用于合并多个数组的函数,参数格式为:concatenate((arr1,arr2,arr3),axis=0),第一个括号内是要合并的数组,可以包含任意数量,第二个axis参数与合并方式有关,此处暂不赘述。

绘制图像

绘制图像的基本步骤与绘制条形图类似,但有几点需要注意:

在plot函数中,绘制条形图时第一和第二个参数分别填写“横坐标-纵坐标”,而由于雷达图基于极坐标,matplotlib提供了“角度-半径”的极坐标参数填写方式。

plot中的颜色仅控制边框颜色,fill函数中的颜色是填充颜色,可以自由组合以达到美观效果。

fill函数中的alpha参数表示覆盖区的透明度,取值区间为0-1,数值越小表示越透明。

plt.legend图例函数中的loc参数用于描述图例的位置。

代码如下:

# 设置图形的大小
fig = plt.figure(figsize=(8, 6), dpi=100)

# 新建一个子图
ax = plt.subplot(111, polar=True)

# 绘制雷达图并填充颜色
ax.plot(angles, score_Harry, color='orange')
ax.fill(angles, score_Harry, 'y', alpha=0.4)
ax.plot(angles, score_Son, color='b')
ax.fill(angles, score_Son, 'cyan', alpha=0.4)
ax.plot(angles, score_Tobi, color='r')
ax.fill(angles, score_Tobi, 'salmon', alpha=0.4)

# 设置雷达图中每一项的标签显示
ax.set_thetagrids(angles * 180 / np.pi, labels, fontsize=15)

ax.set_theta_zero_location('E')  # 设置0度坐标轴起始位置,东西南北

ax.set_rlim(0, 100)  # 设置雷达图的坐标刻度范围

ax.set_rlabel_position(270)  # 设置雷达图的坐标值显示角度,相对于起始角度的偏移量
ax.set_title("热刺球员能力对比图")
plt.legend(["哈里·凯恩", "孙兴愍", "托比"], loc='lower left')

plt.show()

完整代码:

import numpy as np
import matplotlib.pyplot as plt

# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['KaiTi']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
plt.style.use('ggplot')  # 设置ggplot样式

# 原始数据集并获取数据集长度
results = [{"速度": 68, "射门": 91, "传球": 83, "盘带": 83, "防守": 47, "力量": 82},
           {"速度": 88, "射门": 87, "传球": 82, "盘带": 86, "防守": 42, "力量": 69},
           {"速度": 58, "射门": 55, "传球": 70, "盘带": 67, "防守": 86, "力量": 77}]
data_length = len(results[0])

angles = np.linspace(0, 2 * np.pi, data_length, endpoint=False)  # 将极坐标根据数据长度进行等分

# 分离属性字段和数据
labels = [key for key in results[0].keys()]
score = [[v for v in result.values()] for result in results]

# 使雷达图数据封闭
angles = np.concatenate((angles, [angles[0]]))
labels = np.concatenate((labels, [labels[0]]))
score_Harry = np.concatenate((score[0], [score[0][0]]))
score_Son = np.concatenate((score[1], [score[1][0]]))
score_Tobi = np.concatenate((score[2], [score[2][0]]))

# 设置图形的大小
fig = plt.figure(figsize=(8, 6), dpi=100)

# 新建一个子图
ax = plt.subplot(111, polar=True)

# 绘制雷达图并填充颜色
ax.plot(angles, score_Harry, color='orange')
ax.fill(angles, score_Harry, 'y', alpha=0.4)
ax.plot(angles, score_Son, color='b')
ax.fill(angles, score_Son, 'cyan', alpha=0.4)
ax.plot(angles, score_Tobi, color='r')
ax.fill(angles, score_Tobi, 'salmon', alpha=0.4)

# 设置雷达图中每一项的标签显示
ax.set_thetagrids(angles * 180 / np.pi, labels, fontsize=15)

ax.set_theta_zero_location('E')  # 设置0度坐标轴起始位置,东西南北

ax.set_rlim(0, 100)  # 设置雷达图的坐标刻度范围

ax.set_rlabel_position(270)  # 设置雷达图的坐标值显示角度,相对于起始角度的偏移量
ax.set_title("热刺球员能力对比图")
plt.legend(["哈里·凯恩", "孙兴愍", "托比"], loc='lower left')

plt.show()

最后得到的雷达图:

效果看起来还不错(?)

绘制多张单主体雷达图

数据处理部分与上述相同,我们直接从绘图部分开始讲解。

建立子图

首先使用plt.figure绘制好基本画布,然后需要建立三个子图(对应三个球员):

ax1 = plt.subplot(131, polar=True)
ax2 = plt.subplot(132, polar=True)
ax3 = plt.subplot(133, polar=True)

我们将整个画布视为一个矩阵,包含m行n列。

第一个参数是一个三位数,第一位表示该子图在整个画布的行位置,1表示总共把画布划分为1行;第二位表示列,3表示总共把画布划分为3列;第三个参数表示索引值,指的是具体的位置,按照从上到下、从左到右的顺序排列。例如,在一个2*2的画布中,索引值为3表示在第二行第一个位置。

循环遍历画每个子图

首先将画图用的子图、数据、标签、颜色等用列表存储起来,以便遍历。

遍历每一个子图:

首先绘制角度坐标轴和框线,’-.'表示框线的样式是由一个小线段加一个点组成,lw是linewidth的缩写,表示线的粗细。

先绘制沿半径方向的等值线,再绘制角度轴。

绘图并填充颜色,与上述方法相同。

标出数据下标,ha和va用于调整水平和垂直方向的位置。

最后调整labels、坐标值范围等参数。

ax, data, name, color = [ax1, ax2, ax3], [score_Harry, score_Son, score_Tobi], ["哈里·凯恩", "孙兴愍", "托比"], ["orange", "cyan", "green"]

for i in range(3):
    # 绘制角度轴和框线
    for j in np.arange(0, 100+20, 20):
        ax[i].plot(angles, 7*[j], '-.', lw=0.5, color='black')  #  沿半径方向的等值线
    for j in range(5):
        ax[i].plot([angles[j], angles[j]], [0, 100], '-.', lw=0.5, color='black')  #  绘制角度轴

    # 绘制图像并填充颜色
    ax[i].plot(angles, data[i], color=color[i])
    ax[i].fill(angles, data[i], color=color[i], alpha=0.4)

    # 数据下标
    for a, b in zip(angles, data[i]):
        ax[i].text(a, b+5, '%.00f' % b, ha='center', va='center', fontsize=10, color='black')

    # 参数设置
    ax[i].set_thetagrids(angles*180/np.pi, labels)
    ax[i].set_theta_zero_location('N')
    ax[i].set_rlim(0, 100)
    ax[i].set_rlabel_position(0)
    ax[i].set_title(name[i])

最后得到效果(个人审美有限,不喜勿喷):

总体来说,强大的matplotlib结合灵活运用代码和美化技巧,即可得到一幅好看的雷达图。

总结

到此这篇关于用Python绘制极坐标雷达图的文章就介绍到这了,更多相关Python坐标雷达图内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表