目录
  • 综述
  • 绘图代码和解析
    • 绘制一张多主体雷达图
    • 绘制多张单主体雷达图
  • 总结

    综述

    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数据的每一项并不是首尾相接的,因此我们需要把每一个列表的第一项copy一下,然后添加到列表末尾。

    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坐标雷达图内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!