Python爬虫实战,request+Matplotlib模块,Python绘制一个足球运动员的数据可视化图表

news2024/12/28 6:08:57

前言

用Python和Matplotlib绘制一个足球运动员的数据可视化图表。

Let’s start happily

开发工具

Python版本: 3.6.4

相关模块:

bs4模块

requests模块

pandas模块

matplotlib模块

json模块

numpy模块

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

文中完整版代码,评论留言获取。
赛季数据

数据来源于下面两个网站,Understat和Fbref。
UnderstatFbref
链接:https://understat.com/
链接:https://fbref.com/en/

欧洲足球五大联赛,英超、意甲、西甲、德甲、法甲。

先看一下射门数据的可视化,本质上和篮球的出手点图差不多,都是散点图类型。

导入相关的Python库。

import requests
from bs4 import BeautifulSoup as soup
import json
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

从Understat网站爬取射门数据,使用BeautifulSoup、JSON和pandas解析和处理数据。

# 请求数据, C罗的ID为2371
url = 'https://understat.com/player/2371'
html = requests.get(url)

# 解析处理数据
parse_soup = soup(html.content, 'lxml')
scripts = parse_soup.find_all('script')
strings = scripts[3].string

ind_start = strings.index("('")+2
ind_end = strings.index("')")
json_data = strings[ind_start:ind_end]
json_data = json_data.encode('utf8').decode('unicode_escape')
data = json.loads(json_data)
print(data)
# 处理数据, 包含射门位置、预期进球、射门结果、赛季
x = []
y = []
xg = []
result = []
season = []
for i, _ in enumerate(data):
    for key in data[i]:
        if key == 'X':
            x.append(data[i][key])
        if key == 'Y':
            y.append(data[i][key])
        if key == 'xG':
            xg.append(data[i][key])
        if key == 'result':
            result.append(data[i][key])
        if key == 'season':
            season.append(data[i][key])
columns = ['X', 'Y', 'xG', 'Result', 'Season']
df_understat = pd.DataFrame([x, y, xg, result, season], index=columns)
df_understat = df_understat.T
df_understat = df_understat.apply(pd.to_numeric, errors='ignore')
# 得到最终的结果
print(df_understat)

此处的ID,通过查询球员名字可知
ID
查询中国球员武磊,点击访问,在地址栏处,可以看到球员ID。

得到数据如下。
数据
包含射门位置(x、y)、xG(预期进球)、射门果、赛季。

其中x、y的坐标值为0~1之间,不适合在Matplotlib显示,所以选择放大100倍。

df_understat['X'] = df_understat['X'].apply(lambda x: x*100)
df_understat['Y'] = df_understat['Y'].apply(lambda x: x*100)
print(df_understat)

得到结果如下。
结果
既然已经成功获取Understat网站的数据,就可以去获取Fbref网站的数据啦。

这里是球员的一些个人信息,以及赛季的平均数据。
赛季的平均数据

比如全名、国家、位置、俱乐部、联赛、年龄、出生年份、上场时间、得分数据等等。

因为网页的数据是表格形式,所以直接使用pandas的read_html函数,解析表格爬取数据。

这个网站需要取消一下证书验证,要不然连接不成功。

# 全局取消证书验证

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

获取球员的相关数据。

def readfromhtml(filepath):
    # 选择第二个表格
    df = pd.read_html(filepath)[0]
    column_lst = list(df.columns)
    for index in range(len(column_lst)):
        column_lst[index] = column_lst[index][1]
    df.columns = column_lst
    df.drop(df[df['Player'] == 'Player'].index, inplace=True)
    df = df.fillna('0')
    df.set_index('Rk', drop=True, inplace=True)
    try:
        df['Comp'] = df['Comp'].apply(lambda x: ' '.join(x.split()[1:]))
        df['Nation'] = df['Nation'].astype(str)
        df['Nation'] = df['Nation'].apply(lambda x: x.split()[-1])
    except:
        print('Error in uploading file:' + filepath)
    finally:
        df = df.apply(pd.to_numeric, errors='ignore')
        return df


# 获取2020-2021欧洲五大联赛球员数据
df_fbref = readfromhtml('https://fbref.com/en/comps/Big5/shooting/players/Big-5-European-Leagues-Stats')
print(df_fbref)

得到结果如下。
在这里插入图片描述

数据都已经准备好了,那么我们就可以将数据绘制到图表上。

# 安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mplsoccer
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple highlight_text

先安装mplsoccer、highlight_text这两个Python库。
mplsoccer、highlight_text这两个Python库

其中mplsoccer库可以自定义绘制足球场,无需我们自己绘制场地图。

想了解更多,可以访问它的GitHub地址。

https://github.com/andrewRowlinson/mplsoccer

GitHub地址

初始化一些设置,画布背景色、字体颜色、默认字体,字体大小,此处选择中文字体。

from highlight_text import ax_text,fig_text
import mplsoccer

# 背景色
background = '#D6DBD9'
# 字体颜色
text_color = 'black'
mpl.rcParams['xtick.color'] = text_color
mpl.rcParams['ytick.color'] = text_color
mpl.rcParams['text.color'] = text_color
# 中文字体
mpl.rcParams['font.family'] = 'Songti SC'
mpl.rcParams['legend.fontsize'] = 12

新建一个画布。

# 新建画布
fig, ax = plt.subplots(figsize=(10, 8))
# 关闭坐标轴
ax.axis('off')
# 背景色填充
fig.set_facecolor(background)
plt.show()

显示如下。
显示

绘制19-20赛季,C罗的进球情况。

# 垂直方向半个足球场
pitch = mplsoccer.VerticalPitch(half=True, pitch_type='opta', line_zorder=3, pitch_color='grass')
# 图表大小
ax_opta1 = fig.add_axes((0.05, 0.06, 0.45, 0.4))
ax_opta1.patch.set_facecolor(background)
pitch.draw(ax=ax_opta1)
plt.show()

通过设置mplsoccer的参数,绘制半个足球场。
设置mplsoccer的参数,绘制半个足球场

果然,左下方有半个足球场。

将射门数据用散点图表示,分为进球得分和未成功进球得分两种情况。

# 2019-2020赛季, C罗射门位置散点图(未得分), 透明度0.6
df_fil = df_understat.loc[df_understat['Season'] == 2019]

pitch.scatter(df_fil[df_fil['Result'] != 'Goal']['X'], df_fil[df_fil['Result'] != 'Goal']['Y'],
              s=np.sqrt(df_fil[df_fil['Result'] != 'Goal']['xG'])*100, marker='o', alpha=0.6,
              edgecolor='black', facecolor='grey', ax=ax_opta1)
plt.show()

未得分射门散点图。
未得分射门散点图

得分散点图。

# 2019-2020赛季, C罗射门位置散点图(得分), 透明度0.9
pitch.scatter(df_fil[df_fil['Result'] == 'Goal']['X'], df_fil[df_fil['Result'] == 'Goal']['Y'],
              s=np.sqrt(df_fil[df_fil['Result'] == 'Goal']['xG'])*100, marker='o', alpha=0.9,
              edgecolor='black', facecolor='#6778d0', ax=ax_opta1, label='Goal')

plt.show()

结果如下,失败的比成功的多。
结果

这样,我们就将C罗在2019-2020赛季的所有射门点数据可视化出来了。

其中散点的大小,是预期进球的大小。

添加标签及图例,设置相应的位置、文字、字体等设置。

# 添加图例
ax_opta1.legend(loc='lower right').get_texts()[0].set_color("black")

# 文字信息
ax_opta1.text(30, 61, '得分次数 : '+str(len(df_fil[df_fil['Result'] == 'Goal'])), weight='bold', size=11)
ax_opta1.text(30, 64, f"预期进球 : {round(sum(df_fil['xG']),2)}", weight='bold', size=11)
ax_opta1.text(30, 58, '射门次数 : '+str(len(df_fil)), weight='bold', size=11)
ax_opta1.text(90, 60, '2019-20赛季', weight='bold', size=14)

plt.show()

成功添加附加信息。
成功添加附加信息

显示赛季、xG、得分次数、射门次数信息。

同样将20-21赛季的数据绘制出来,放置在19-20赛季的右侧。

# 2020-2021赛季, C罗射门位置散点图
ax_opta2 = fig.add_axes((0.50, 0.06, 0.45, 0.4))
ax_opta2.patch.set_facecolor(background)
pitch.draw(ax=ax_opta2)

# 根据条件, 筛选数据
df_fil = df_understat.loc[df_understat['Season'] == 2020]
# 未得分
pitch.scatter(df_fil[df_fil['Result'] != 'Goal']['X'], df_fil[df_fil['Result'] != 'Goal']['Y'],
              s=np.sqrt(df_fil[df_fil['Result']!='Goal']['xG'])*100, marker='o', alpha=0.6,
              edgecolor='black', facecolor='grey', ax=ax_opta2)
# 得分
pitch.scatter(df_fil[df_fil['Result']=='Goal']['X'], df_fil[df_fil['Result'] == 'Goal']['Y'],
              s=np.sqrt(df_fil[df_fil['Result'] == 'Goal']['xG'])*100, marker='o', alpha=0.9,
              edgecolor='black', facecolor='#6778d0', ax=ax_opta2, label='Goal')

# 添加图例, 文字信息
ax_opta2.legend(loc='lower right').get_texts()[0].set_color("black")

ax_opta2.text(30, 61, '得分次数 : '+str(len(df_fil[df_fil['Result'] == 'Goal'])), weight='bold', size=11)
ax_opta2.text(30, 64, f"预期进球 : {round(sum(df_fil['xG']),2)}", weight='bold', size=11)
ax_opta2.text(30, 58, '射门次数 : '+str(len(df_fil)), weight='bold', size=11)
ax_opta2.text(90, 60, '2020-21赛季', weight='bold', size=14)

plt.show()

结果如下。
在这里插入图片描述

C罗老当益壮啊,状态一点也没有下滑。

下面接着绘制所有球员的数据散点图,看看C罗的数据能在哪一档?

# 初始化
ax_scatter = fig.add_axes([0.52, 0.57, 0.4, 0.35])
ax_scatter.patch.set_facecolor(background)
plt.show()

创建一个坐标轴。
创建一个坐标轴

首先对数据进行筛选,上场时间最少要有900s,而且位置为前锋此类的。

毕竟我们不能拿个守门员,跟C罗比数据吧,参考意义不大。

# 得到散点图的X, Y坐标值
no_90s = 10
df_fil = df_fbref[df_fbref['90s'] >= no_90s]
# 前锋位置
df_fil = df_fil[df_fil['Pos'].apply(lambda x: x in ['FW', 'MF,FW', 'FW,MF'])]

# 每90s预期进球和得分次数
x, y = (df_fil['xG']/df_fil['90s']).to_list(), (df_fil['Gls']/df_fil['90s']).to_list()

# 生成所有前锋位置, 数据散点图
ax_scatter.scatter(x, y, alpha=0.3, c='#EF8804')

plt.show()

所有球员每90s预期进球和得分次数的数据情况。

现在我们筛选出C罗的数据,在散点图上用不同的颜色及透明度来突出显示它。

# C罗的数据
df_player = df_fil[df_fil['Player'] == 'Cristiano Ronaldo']
ax_scatter.scatter(df_player['xG']/df_player['90s'], df_player['Gls']/df_player['90s'], c='blue')

plt.show()

结果如下。
结果

可以看到C罗的数据还是比较高效的,虽不是第一,但也是前几的存在。

最后给散点图添加网格线,以及x轴和y轴标签。

# 添加网格线及标签
ax_scatter.grid(b=True, color='grey',
                linestyle='-.', linewidth=0.5,
                alpha=0.4)
ax_scatter.set_xlabel('每90秒的预期进球', fontdict={'fontsize': 12, 'weight': 'bold', 'color': text_color})
ax_scatter.set_ylabel('每90秒得分', fontdict=dict(fontsize=12, weight='bold', color=text_color))

plt.show()

结果如下。
结果

不愧是C罗,在2020-21赛季几乎每90秒就能进1颗球。

18年就已经有一个记录!C罗成历史第一位在90分钟内每分钟都有进球的球员。

最后添加文本信息,包含标题,C罗的头像,场上位置、年龄、效力球队。

此处使用hightlight-text库,可以高亮文本。

# 添加C罗的头像
ax_player = fig.add_axes([0.03, 0.53, 0.25, 0.45])
ax_player.axis('off')
im = plt.imread('ronaldo.png')
ax_player.imshow(im)

# 添加标题信息
fig_text(0.03, 0.94, "<克里斯蒂亚诺·罗纳尔多(C罗)> 赛季数据", weight='heavy', size=19, highlight_textprops=[{'color': 'blue'}])
fig_text(0.25, 0.85, '位置: <边锋>',weight='bold', size=15, highlight_textprops=[{'color':'#EF8804'}])
fig_text(0.25, 0.81, '年龄: <36>',weight='bold', size=15, highlight_textprops=[{'color':'red'}])

# 添加俱乐部logo
ax_team = fig.add_axes([0.27, 0.55, 0.15, 0.15])
ax_team.axis('off')
im = plt.imread('FCJ.png')
ax_team.imshow(im)

# 添加备注
fig_text(0.07, 0.03, '本图制作者:<小F>   数据来源:Fbref.com、Understat.com',
        size=12, highlight_textprops=[{'color': '#EF8804'}], weight='bold')
plt.show()

得到结果如下。
结果

保存为图片。

# 保存为图片
plt.savefig('ronaldo_viz.png', dpi=300, facecolor=background)

看起来还不错哦。
在这里插入图片描述

好了,本期的分享就到此结束了,有兴趣的小伙伴可以自行去实践学习。

快给自己喜欢的足球运动员,也制作一个赛季数据面板吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/54550.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sqoop数据导入 第2关:Mysql导入数据至HDFS上

为了完成本关任务,你需要掌握: 1、数据库( MySQL )建表。 2、Mysql 数据导入至 HDFS 中。 数据库( MySQL )建表 用命令进入 MySQL 客户端。 mysql -uroot -p123123 -h127.0.0.1 创建数据库hdfsdb(格式默认为utf8),并在数据库内建立表student,其表结构如下: mys…

通过求解数学模型来选择编码节点的最佳数量和位置(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

【✨十五天搞定电工基础】电阻电路的分析方法

本章要求1. 掌握支路电流法、叠加原理和戴维宁定理等电路的基本分析方法; 2. 了解实际电源的两种模型及其等效变换; 3. 了解非线性电阻元件的伏安特性及静态电阻、动态电阻的概念&#xff0c;以及简单非线性电阻电路 的图解分析法。 目录 一、电阻串并联连接的等效变换 1、…

企业如何有效的防爬虫?

防爬虫&#xff0c;简单来说&#xff0c;就是在尽量减少对正常用户的干扰的情况下尽可能的加大爬虫的成本。 而反防爬虫&#xff0c;或者说制造隐蔽性强的爬虫&#xff0c;就是尽量模拟正常用户的行为。 这两者是动态博弈的。大公司基本都有防爬的项目&#xff0c;以保护数据…

一图了解es6常用数据迭代函数map,filter,fill,reduce

一、一图胜千言 前端开发中&#xff0c;js数组处理是最常用的&#xff0c;除了for循环外&#xff0c;随着es6的普及&#xff0c;像reduce()、filter()、map()、some()、every()以及…展开属性都是最常用到的。 今天偶然从网上看到这张图&#xff0c;真是眼前一亮&#xff0c;真…

盘点JAVA中延时任务的几种实现方式

场景描述 ①需要实现一个定时发布系统通告的功能&#xff0c;如何实现&#xff1f; ②支付超时&#xff0c;订单自动取消&#xff0c;如何实现&#xff1f; 实现方式 一、挂起线程 推荐指数&#xff1a;★★☆ 优点&#xff1a; JDK原生(JUC包下)支持&#xff0c;无需引入新…

RabbitMQ之集群管理

1、在node2、node3、node4三台Linux虚拟机中安装RabbitMQ。 2、从node2拷贝.erlang.cookie到node3、node4的相应目录 如果没有该文件&#xff0c;手动创建/var/lib/rabbitmq/.erlang.cookie &#xff0c;生成Cookie字符串&#xff0c;或者启动一次RabbitMQ自动生成该文件。生产…

五年Java编程生涯,大专学历最终逆袭阿里,面试+学习+经历分享

五年时间&#xff0c;对于程序员来说&#xff0c;真的非常非常宝贵&#xff0c;掉的头发都够塞满键盘的缝隙了。就说新一代偶像 TFboys 吧&#xff0c;你应该知道这个组合吧&#xff0c;黄金合作期也就三五年的时间&#xff0c;现在基本上就处于各自单飞&#xff08;solo&#…

深度学习笔记之受限玻尔兹曼机(一)玻尔兹曼分布介绍

机器学习笔记之受限玻尔兹曼机——玻尔兹曼分布介绍引言回顾&#xff1a;Hammersley-Clifford定理玻尔兹曼分布的物理意义引言 从本节开始&#xff0c;将介绍受限玻尔兹曼机。本节将从马尔可夫随机场开始&#xff0c;介绍玻尔兹曼机分布。 回顾&#xff1a;Hammersley-Cliffo…

NCP81239MNTXG 开关降压/升压控制器,USB 功率传递和 Type-C 应用

NCP81239MNTXG USB 功率传递 (PD) 控制器是一款同步降压/升压控制器&#xff0c;适用于为笔记本电脑、平板电脑、台式系统以及很多使用 USB PD 标准和 C−Type 线缆的其他消费设备提供电池电压或适配器电压到所需电源轨的转换。结合使用 USB PD 或 C−Type 接口控制器时完全符合…

【笔记】Java - VM options、Program arguments、Environment variables、eclipse variables

java使用ide开发的时候&#xff0c;运行程序&#xff08;application&#xff09;前都要设置启动配置&#xff1a; VM options、Program arguments、Environment variables 很多时候我们是默认配置启动的&#xff0c;所以没太注意。但是如果我们有特殊需求、项目上线时&#xf…

VSCode 安装教程(超详细)

文章目录VSCode 安装使用教程&#xff08;图文版&#xff09;那么&#xff0c;什么是 IDE 呢 &#xff1f;目前&#xff0c;前端开发主流的 IDE 有以下 5 个下边我们开始玩转 VSCodeVSCode 下载、安装Window 版 VScode 安装流程1、下载 Vscode 安装文件2、下载完成单击运行&…

Postman的使用——设置全局参数,参数的传递,从登录接口的响应body中提取数据更新全局参数,从响应cookie中提取数据更新全局变量

Postman的使用——设置全局参数&#xff0c;引用全局参数&#xff0c;参数的传递&#xff0c;从登录接口的响应body中提取数据更新全局参数&#xff0c;从响应cookie中提取数据更新全局变量一、设置全局参数二、引用全局参数三、从登录接口的响应body中提取数据更新全局参数四、…

cmd命令以及一些操作

文章目录前言set和echoif语句判断有无指定文件夹相对路径创建文件夹创建bat脚本换行符前言 因为下载下来的代码用bash脚本写的&#xff0c;cmd不能完美运行&#xff0c;因此想着对照着转成cmd&#xff0c;这样就方便了。 set和echo set demohello world!!! echo %demo%这就是…

[附源码]计算机毕业设计springboot学生宿舍维修管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

动态规划——数字三角形模型

数字三角形模型&#xff1a; 给定一个如下图所示的数字三角形&#xff0c;从顶部出发&#xff0c;在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点&#xff0c;一直走到底层&#xff0c;要求找出一条路径&#xff0c;使路径上的数字的和最大。 输入格式&#…

力扣 895. 最大频率栈

题目 设计一个类似堆栈的数据结构&#xff0c;将元素推入堆栈&#xff0c;并从堆栈中弹出出现频率最高的元素。 实现 FreqStack 类: FreqStack() 构造一个空的堆栈。 void push(int val) 将一个整数 val 压入栈顶。 int pop() 删除并返回堆栈中出现频率最高的元素。 如果出现…

傻妞旧版本(合集)

目录一、前言二、下载三、新版傻妞订阅合集一、前言 傻妞旧版本(合集),包含amd和arm版本 二、下载 &#x1f170;️amd✅还未大改&#xff0c;init web未出 &#x1f534;[sillyGirl_amd_2022-08-05] ➡️百度网盘 ➡️天翼云盘&#xff08;访问码&#xff1a;ha8s&#xff09…

如何开通小程序?开通小程序要钱吗?

关于如何开通小程序&#xff1f;开通小程序要钱吗&#xff1f;这两个问题&#xff0c;今天给大家做一个简单的解答。 一、如何开通小程序&#xff1f; “开通小程序”这个说法其实并不准确&#xff0c;能开通的是小程序账号&#xff0c;开通完小程序账号后还需要去制作小程序&…

计算机视觉之目标检测训练数据集(皮卡丘)《2》

在做目标检测&#xff0c;训练数据集的时候&#xff0c;可以先看前段时间的一篇基础文章&#xff1a;计算机视觉之目标检测(object detection)《1》https://blog.csdn.net/weixin_41896770/article/details/128062645先熟悉一些基本知识&#xff0c;如&#xff1a;锚框&#xf…