如何用ggplot绘制FiveThirtyEight风格的球队概率热力图?
实现FiveThirtyEight风格的球队概率热力图(ggplot版)
问题描述
现有包含球队名称、积分、前两名晋级概率(İlk_iki)、季后赛概率(Playoff)、降级概率(Küme_Düşme)的数据集,需用ggplot绘制类似FiveThirtyEight风格的热力图,展示各球队不同晋级/降级概率的分布。
数据集
df <- structure(list(Team = c("Eyupspor", "Samsunspor", "Keciorengucu", "Bodrumspor", "Bandirmaspor", "Pendikspor", "Boluspor", "Rizespor", "Sakaryaspor", "Goztepe", "Manisa", "Adanaspor", "Altay", "Tuzlaspor", "Erzurumspor", "Altinordu", "Malatyaspor", "Denizlispor", "Genclerbirligi" ), Points = c(41, 38, 36, 35, 34, 34, 33, 31, 31, 28, 28, 22, 19, 19, 18, 16, 13, 12, 10), İlk_iki = c(0.666, 0.592, 0.211, 0.161, 0.126, 0.169, 0.012, 0.052, 0.008, 0, 0.002, NA, NA, NA, NA, NA, NA, NA, NA), Playoff = c(0.996, 0.988, 0.908, 0.875, 0.818, 0.881, 0.388, 0.694, 0.261, 0.061, 0.126, 0.004, 0, 0, 0, NA, NA, NA, NA), Küme_Düşme = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.024, 0.093, 0.163, 0.228, 0.751, 0.865, 0.907, 0.969)), row.names = c(NA, 19L), class = "data.frame")
解决方案
要实现目标,需完成数据整理和ggplot绘图两个核心步骤,同时借助ggthemes包实现FiveThirtyEight的风格:
1. 加载依赖包
library(tidyverse) library(scales) library(ggthemes)
2. 数据预处理
将宽格式数据转为长格式,按积分从高到低排序球队,并把概率转为百分比格式:
df_long <- df %>% # 按积分降序排序球队,确保热力图从上到下积分递减 arrange(desc(Points)) %>% mutate(Team = factor(Team, levels = Team)) %>% # 转长格式,提取概率类型和对应数值 pivot_longer(cols = c(İlk_iki, Playoff, Küme_Düşme), names_to = "Prob_Type", values_to = "Probability") %>% # 过滤NA值,仅保留有效概率数据 filter(!is.na(Probability)) %>% # 概率转百分比,保留1位小数,用于文本显示 mutate(Prob_Pct = percent(Probability, accuracy = 0.1))
3. 绘制FiveThirtyEight风格热力图
ggplot(df_long, aes(x = Prob_Type, y = Team)) + # 绘制热力图色块,调整边框和透明度 geom_tile(aes(fill = Probability), color = "white", alpha = 0.8) + # 在色块上显示百分比文本 geom_text(aes(label = Prob_Pct), color = "black", size = 3.5) + # 设置颜色渐变:低概率浅蓝,高概率深红(匹配FiveThirtyEight风格) scale_fill_gradient(low = "#cce7f5", high = "#e31a1c", limits = c(0,1)) + # 应用FiveThirtyEight主题 theme_fivethirtyeight() + # 自定义坐标轴标签和标题 labs(title = "球队晋级/降级概率热力图", x = "概率类型", y = "球队", fill = "概率") + # 调整坐标轴文本方向和主题细节 theme(axis.text.y = element_text(size = 10), axis.text.x = element_text(size = 11), plot.title = element_text(size = 14, face = "bold"), legend.position = "bottom")
效果说明
- 球队按积分从高到下排列,符合联赛排名逻辑
- 色块颜色深浅对应概率高低,直观展示各球队不同场景的概率分布
- 文本直接标注百分比,避免用户额外换算
- 整体风格匹配FiveThirtyEight的简约、信息优先设计
内容的提问来源于stack exchange,提问作者Emre Toros
相关产品推荐
相关产品推荐

