Python数据可视化小项目
英雄联盟S14世界赛选手数据可视化
由于本学期有一门数据可视化课程,课程结课作业要求完成一个数据可视化的小Demo,于是便有了这个小项目,课程老师要求比较简单,只要求熟练运用可视化工具展示数据,并不要求数据来源,因此这个小项目非常简单
项目简介
这是一个基于 PyEcharts 的数据可视化小项目,展示了英雄联盟 S14 世界赛选手的关键数据表现,适合作为数据可视化课程作业或兴趣项目。
项目特点:
- 数据源权威,来源于 Kaggle。
- 涉及多种可视化类型,包括柱状图、箱形图、雷达图等。
- 共包含 14 个可视化图表,分布在 3 个 HTML 页面中,方便浏览与展示。
完整代码:英雄联盟S14世界赛选手数据可视化
数据来源
数据来自 Kaggle 平台的 2024 LoL Championship Player Stats & Swiss Stage。
- 数据涵盖选手的各项核心指标,如 KDA、场均击杀、场均死亡等。
- 细化到每分钟视野分数、野区控制等高级数据。
数据示例
| TeamName | PlayerName | Position | Games | … | Penta Kills | Solo Kills | Country | FlashKeybind |
|---|---|---|---|---|---|---|---|---|
| Top Esports | 369 | Top | 8 | … | 0 | 2 | China | D |
| Dplus KIA | aiming | Adc | 9 | … | 0 | 2 | South Korea | F |
| MAD Lions KOI | alvaro | Support | 5 | … | 0 | 0 | Spain | D |
| … | … | … | … | … | … | … | … | … |
| LNG Esports | zika | Top | 8 | … | 0 | 2 | China | D |
效果展示
主要采用PyEcharts来完成数据可视化
数据总览
该模块主要有一个各队伍平均胜率的柱状图和全部选手的国籍分布饼图组成

# 计算各队伍平均胜率,并将其转换为百分数形式(乘以100并保留两位小数)
team_win_rates = df.groupby('TeamName')['Win rate'].mean().reset_index()
team_win_rates['Win rate'] = team_win_rates['Win rate'].apply(lambda x: round(x * 100, 2))
print(team_win_rates)
# 绘制柱状图
bar = Bar(init_opts=opts.InitOpts(width="1100px", height="500px")
)
bar.add_xaxis(team_win_rates['TeamName'].tolist())
bar.add_yaxis("平均胜率", team_win_rates['Win rate'].tolist(), category_gap="60%")
bar.set_global_opts(title_opts=opts.TitleOpts(title="各队伍平均胜率", subtitle=""),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),yaxis_opts=opts.AxisOpts(name="胜率", min_=0, max_=100),visualmap_opts=opts.VisualMapOpts(is_show=False, max_=100, min_=0)
)
bar.render("static/charts/team_win_rates.html")

# 国家分布
# 按照国家进行分组,计算每个国家的选手数量
grouped_data = df.groupby('Country').size()# 将结果转换为 DataFrame,并命名为 'Count'
country_data = grouped_data.reset_index(name='Count')
print(country_data)
country_pie = (Pie(init_opts=opts.InitOpts(theme="macarons")).add("", [list(z) for z in zip(country_data['Country'], country_data['Count'])]).set_global_opts(title_opts=opts.TitleOpts(title=""))
)
country_pie.render("static/charts/country_distribution_chart.html")
主要数据
该模块主要涉及了选手的各方位数据总览情况,能够直观的观察各方面数据突出的选手,其中包括:场均击杀、
场均KDA、场均死亡、场均助攻、辅助视野综合得分、选手平均击杀、选手闪现按键情况

# 场均击杀
sorted_df = df.sort_values(by='Avg kills', ascending=False)
avg_kills = sorted_df[['PlayerName', 'Avg kills']]
avg_kills_top10 = avg_kills[0:10]
print(avg_kills_top10)
# 创建Bar实例,用于构建柱状图
bar = Bar(init_opts=opts.InitOpts(width="600px", height="300px")
)
# 添加x轴数据,即选手姓名
bar.add_xaxis(avg_kills_top10['PlayerName'].tolist())
# 添加y轴数据,即场均击杀数,并设置系列名称为"场均击杀数"
bar.add_yaxis("场均击杀数", avg_kills_top10['Avg kills'].tolist())
# 设置全局配置项
bar.set_global_opts(title_opts=opts.TitleOpts(title="场均击杀榜前十"),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45), # 让x轴标签旋转45度,避免文字重叠),yaxis_opts=opts.AxisOpts(name="场均击杀数"), # 设置y轴名称visualmap_opts=opts.VisualMapOpts(is_show=False, max_=6, min_=4)
)
bar.render("static/charts/avg_kills_top10.html")

# KDA
kda_top10 = df.sort_values(by='KDA', ascending=False)[['PlayerName', 'KDA']][0:10]
print(kda_top10)
bar = Bar(init_opts=opts.InitOpts(width="600px", height="300px")
)
bar.add_xaxis(kda_top10['PlayerName'].tolist())bar.add_yaxis('场均KDA', kda_top10['KDA'].tolist())
# 设置全局配置项
bar.set_global_opts(title_opts=opts.TitleOpts(title="场均KDA前十"),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45), # 让x轴标签旋转45度,避免文字重叠),yaxis_opts=opts.AxisOpts(name="场均KDA"), # 设置y轴名称visualmap_opts=opts.VisualMapOpts(is_show=False, max_=10, min_=6)
)
bar.render("static/charts/kda_top10.html")

# 场均死亡
deaths_top10 = df.sort_values(by='Avg deaths', ascending=False)[['PlayerName', 'Avg deaths']][0:10]
print(deaths_top10)
bar = Bar(init_opts=opts.InitOpts(width="600px", height="300px", theme="macarons"))
bar.add_xaxis(deaths_top10['PlayerName'].tolist())
bar.add_yaxis('场均死亡', deaths_top10['Avg deaths'].tolist())
# 设置全局配置项
bar.set_global_opts(title_opts=opts.TitleOpts(title="场均死亡前十"),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45), # 让x轴标签旋转45度,避免文字重叠),yaxis_opts=opts.AxisOpts(name="场均死亡"), # 设置y轴名称visualmap_opts=opts.VisualMapOpts(is_show=False, max_=6, min_=4)
)
bar.render("static/charts/deaths_top10.html")

# 场均助攻
assists_top10 = df.sort_values(by='Avg assists', ascending=False)[['PlayerName', 'Avg assists']][0:10]
print(assists_top10)
bar = Bar(init_opts=opts.InitOpts(width="600px", height="300px", theme="macarons")
)
bar.add_xaxis(assists_top10['PlayerName'].tolist())bar.add_yaxis('场均助攻', assists_top10['Avg assists'].tolist())# 设置全局配置项
bar.set_global_opts(title_opts=opts.TitleOpts(title="场均助攻前十"),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45), # 让x轴标签旋转45度,避免文字重叠),yaxis_opts=opts.AxisOpts(name="场均助攻"), # 设置y轴名称visualmap_opts=opts.VisualMapOpts(is_show=False, max_=13, min_=10)
)
bar.render("static/charts/assists_top10.html")
其中每分钟视野分数(VSPM)、每分钟赢得的野区分数(每分钟赢得的野区分数)、每分钟控制野区分数(Avg WCPM)、每分钟视野控制分数(Avg VWPM)各自的权重为1,可自行更改

# 辅助野区视野排行
df['custom_sort'] = df['VSPM'] * 25 + df['Avg WPM'] * 25 + df['Avg WCPM'] * 25 + df['Avg VWPM'] * 25
support_top_10 = df.sort_values(by='custom_sort', ascending=False)[['PlayerName', 'VSPM', 'Avg WPM', 'Avg WCPM', 'Avg VWPM', 'custom_sort']][0:10]
print(support_top_10)
# 创建堆叠柱状图
bar_stacked = Bar(init_opts=opts.InitOpts(width="1000px", height="400px", theme='macarons')
)
# 添加 X 轴数据(选手名字)
bar_stacked.add_xaxis(support_top_10['PlayerName'].tolist())
# 添加堆叠柱状图的每一项数据
bar_stacked.add_yaxis("每分钟视野分数", support_top_10['VSPM'].tolist(), stack="stack1")
bar_stacked.add_yaxis("每分钟赢得的野区分数", support_top_10['Avg WPM'].tolist(), stack="stack1")
bar_stacked.add_yaxis("每分钟控制野区分数", support_top_10['Avg WCPM'].tolist(), stack="stack1")
bar_stacked.add_yaxis("每分钟视野控制分数", support_top_10['Avg VWPM'].tolist(), stack="stack1")
# 设置全局配置
bar_stacked.set_global_opts(title_opts=opts.TitleOpts(title="辅助野区视野排行"),yaxis_opts=opts.AxisOpts(name=""),xaxis_opts=opts.AxisOpts(name="选手"),legend_opts=opts.LegendOpts(pos_left="right", orient="vertical"), # 设置图例在左侧
)
# 渲染图表到 HTML 文件
bar_stacked.render("static/charts/support_top_10.html")
各位置场均击杀箱形图:

# 准备箱线图数据
data = [df[df['Position'] == pos]['Avg kills'].tolist() for pos in df['Position'].unique()]
print(data)
boxplot = Boxplot(init_opts=opts.InitOpts(width="600px", height="400px")
)
boxplot.add_xaxis(df['Position'].unique().tolist())
boxplot.add_yaxis("平均击杀数", boxplot.prepare_data(data), itemstyle_opts=opts.ItemStyleOpts(color="black"))
boxplot.set_global_opts(title_opts=opts.TitleOpts(title="不同位置选手平均击杀数分布"),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45) # 此处也是修改为axislabel_opts),yaxis_opts=opts.AxisOpts(name="平均击杀数")
)
boxplot.render("static/charts/avg_kills_distribution.html")

# 闪现数据
flash = df.groupby('FlashKeybind').size()
flash_data = flash.reset_index(name='flash_group')
创建饼图
pie = Pie(init_opts=opts.InitOpts(width="400px", height="400px")
)
# 添加数据,设置标签格式
pie.add("闪现按键使用情况",[list(z) for z in zip(flash_data['FlashKeybind'].tolist(), flash_data['flash_group'].tolist())],radius=["30%", "60%"],label_opts=opts.LabelOpts(formatter="{b}")
)
# 设置标题
pie.set_global_opts(title_opts=opts.TitleOpts(title="闪现按键"))# 渲染到本地文件
pie.render("static/charts/flash.html")
我的主队
由于作者喜欢TheShy选手,所以主队是WBG,但是此次世界赛TheShy选手选择了休息,但是也没有新的主队会,所以主队依然是WBG
共有五个选手的雷达图
六大维度:
- KDA
- KP% (击杀参与率)
- CSPerMin (每分钟补刀数)
- GoldPerMin (每分钟经济)
- DPM (每分钟伤害)
- VSPM (每分钟视野分数)


# 获取选手雷达图的数据
def get_player_render_data(player_name, file_name):player_data = df[df['PlayerName'] == player_name][['KDA', 'KP%', 'CSPerMin', 'GoldPerMin', 'DPM', 'VSPM']].iloc[0]print(player_data)# 雷达图的维度attributes = ['KDA', 'KP%', 'CSPerMin', 'GoldPerMin', 'DPM', 'VSPM']values = player_data.tolist()# 配置雷达图weradar = Radar(init_opts=opts.InitOpts(width="350px", height="350px"))# 定义雷达图的每个维度radar.add_schema(schema=[opts.RadarIndicatorItem(name='KDA', max_=10),opts.RadarIndicatorItem(name='击杀参与率', max_=1),opts.RadarIndicatorItem(name='每分钟补兵', max_=10),opts.RadarIndicatorItem(name='分钟收入金币', max_=500),opts.RadarIndicatorItem(name='分钟伤害', max_=800),opts.RadarIndicatorItem(name='分钟视野分', max_=5)])# 添加数据系列,并设置图例radar.add(player_name,[values],color="blue")# 设置全局选项radar.set_global_opts(title_opts=opts.TitleOpts(title=player_name),legend_opts=opts.LegendOpts(is_show=True, orient="vertical", pos_left="right"))radar.render(file_name)
# 我的主队
get_player_render_data('crisp', 'static/charts/crisp_render_data.html')
get_player_render_data('light', 'static/charts/light_render_data.html')
get_player_render_data('xiaohu', 'static/charts/xiaohu_render_data.html')
get_player_render_data('tarzan', 'static/charts/tarzan_render_data.html')
get_player_render_data('breathe', 'static/charts/breathe_render_data.html')
整体效果
整体效果就是将各个图表集中到了一起,加了一些样式,以一个静态网站来展示




完整效果请访问
index.html页面
相关文章:
Python数据可视化小项目
英雄联盟S14世界赛选手数据可视化 由于本学期有一门数据可视化课程,课程结课作业要求完成一个数据可视化的小Demo,于是便有了这个小项目,课程老师要求比较简单,只要求熟练运用可视化工具展示数据,并不要求数据来源&am…...
Python毕业设计选题:基于python的白酒数据推荐系统_django+hive
开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 白酒管理 系统管理 看板展示 系统首页 白酒详情…...
SQL-leetcode-180. 连续出现的数字
180. 连续出现的数字 表:Logs -------------------- | Column Name | Type | -------------------- | id | int | | num | varchar | -------------------- 在 SQL 中,id 是该表的主键。 id 是一个自增列。 找出所有至少连续出现三次的数字。 返回的…...
Unity中如何修改Sprite的渲染网格
首先打开SpriteEditor 选择Custom OutLine,点击Genrate 则在图片边缘会出现边缘线,调整白色小方块可以调整边缘 调整后,Sprite就会按照调整后的网格渲染了。 如何在UI中使用? 只要在UI的Image组件中选择Use Sprite Mesh 即可 结果࿱…...
跟着 8.6k Star 的开源数据库,搞 RAG!
过去 9 年里,HelloGitHub 月刊累计收录了 3000 多个开源项目。然而,随着项目数量的增加,不少用户反馈:“搜索功能不好用,找不到想要的项目!” 这让我意识到,仅仅收录项目是不够的,还…...
每日一题 345. 反转字符串中的元音字母
345. 反转字符串中的元音字母 简单 class Solution { public:string reverseVowels(string s) {int l 0;int r s.size() - 1;unordered_set<char> st {a,A,E,e,i,I,O,o,U,u};while(l < r){while(l<r && !st.count(s[l]) ){l;}while(l<r &&…...
Stream API 的设计融合了多个经典设计模式
Stream API 的设计融合了多个经典设计模式: 1. 策略模式(Strategy Pattern) 策略模式定义了一个算法的家族,将每个算法封装起来,并使它们可以互换。Stream API 中的每个操作(如 filter(), map()ÿ…...
jmeter混合场景测试,设置多业务并发比例(吞吐量控制器)
jmeter混合场景测试,设置多业务并发比例(吞吐量控制器) 测试目的 为了验证需求提出的性能要求,结合实际可能的高压力场景,较全面的检测系统的性能表现。 测试方法 根据需求调研的业务模型和交易占比,设置不…...
直流有刷电机多环控制(PID闭环死区和积分分离)
直流有刷电机多环控制 提高部分-第8讲 直流有刷电机多环控制实现(1)_哔哩哔哩_bilibili PID模型 外环的输出作为内环的输入,外环是最主要控制的效果,主要控制电机的位置。改变位置可以改变速度,改变速度是受电流控制。 实验环境 【 !】功能简介: 按下KEY1使能电机,按下…...
vue-axios+springboot实现文件流下载
前端vue代码: <template><div class"app-container documentation-container"><div><el-button type"primary" click"downloadFile(test.xlsx)">下载test.xlsx</el-button></div></div> …...
selenium执行js
JS知识 获取元素 document.getElement 移除属性:removeAttribute("xx") 窗口移动:window.scrollTo(0, document.body.scrollHeight)方法 drivier.execute_script(js)场景: 日期选择框,不能输入,只能设置…...
每日算法Day11【左叶子之和、找树左下角的值、路径总和】
404.左叶子之和 算法链接: 404. 左叶子之和 - 力扣(LeetCode) 类型: 二叉树 难度: 简单 思路:要判断一个节点是否为左叶子节点,只能通过其父节点进行判断。 题解: /*** Definition for a binary tree node.* public class Tr…...
分享一下使用 AI 开发个人工具的迭代过程
分享一下使用 AI 开发个人工具的迭代过程:1. 找 gpt/claude 要一个 super shady coder 的人设 prompt;2. 简单介绍项目背景和基础需求给 gemini,生成最初的细化需求;3. 根据细化需求再次分析,完善边界条件,…...
大型语言模型(LLMs)演化树 Large Language Models
大型语言模型(LLMs)演化树 Large Language Models flyfish 下面的图来自论文地址 Transformer 模型(如 BERT 和 GPT-3)已经给自然语言处理(NLP)领域带来了革命性的变化。这得益于它们具备并行化能力&…...
部分背包问题
本节学习解决部分背包问题,部分背包代表物品可以按照一定比例被分割,而后放入背包内.这是十分经典的用贪心算法解决的问题. 问题描述: 给定一些物品,用matrix表示各个物品的属性,第一项表示物品的质量,第二项表示物品的总价值.现有一背包最大承重为M,试求如何让背包中所装物品…...
教师管理系统
大概功能: 1.显示所有教师 2.按姓名查找教师 3.按工号查找教师 4.增加教师 5.删除教师 6.退出 数据会保存到 txt 文件里面 姓名:必须是中文 手机号码:必须是11位,必须是数字 效果展示: 代码展示: Teache…...
Word论文交叉引用一键上标
Word论文交叉引用一键上标 1.进入Microsoft word使用CtrlH快捷键或单击替换按钮 2.在查找内容中输入[^#] 3.鼠标点击,标签为“替换为:”的文本框,注意光标一定要打在图红色方框圈中的文本框中! 4.点击格式选择字体 5.勾选上标…...
集成方案 | Docusign + 蓝凌 EKP,打造一站式合同管理平台,实现无缝协作!
本文将详细介绍 Docusign 与蓝凌 EKP 的集成步骤及其效果,并通过实际应用场景来展示 Docusign 的强大集成能力,以证明 Docusign 集成功能的高效性和实用性。 在当今数字化办公环境中,企业对于提高工作效率和提升用户体验的需求日益迫切。蓝凌…...
Python大数据可视化:基于python大数据的电脑硬件推荐系统_flask+Hadoop+spider
开发语言:Python框架:flaskPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 价格区间界面 用户信息界面 品牌管理 笔记本管理 电脑主机…...
【递归与回溯深度解析:经典题解精讲(下篇)】—— Leetcode
文章目录 有效的数独解数独单词搜索黄金矿工不同的路径||| 有效的数独 递归解法思路 将每个数独的格子视为一个任务,依次检查每个格子是否合法。 如果当前格子中的数字违反了数独规则(在行、列或 33 小方块中重复),直接返回 Fals…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
