如何动画展示亚特兰大猎鹰队胜场趋势线与折线散点图?
问题描述
我想要制作一个同时展示趋势线、散点图和折线图的动画图表,用来呈现亚特兰大猎鹰队历年的胜场数。我的代码如下:
df3 <- nfl_data |> group_by(team) |> summarize( year, wins ) df3 <- df3 |> filter(team == 'Atlanta Falcons') df3 graph4 <- ggplot(df3, aes(year, wins)) + geom_line(color = "aquamarine4", linewidth = 1.25) + geom_point(color = "aquamarine4", size = 3) + labs(x = 'Year', y= 'Wins') + scale_x_continuous(breaks = df3$year) + scale_y_continuous(limits = c(0, 16), breaks = seq(0, sum(df3$wins), 2)) + geom_smooth(method = lm, se = FALSE, color = "orange2") animated_plot <- graph4 + transition_reveal(year) + ease_aes('linear') + labs(title = 'Atlanta Falcons') + shadow_mark() + view_follow(fixed_y = TRUE) animate(animated_plot, renderer = gifski_renderer(), height = 800, width = 1200, fps = 30, duration = 20, end_pause = 100, res = 100)
运行代码时,geom_smooth行总是抛出如下错误:
Error in
$<-.data.frame(*tmp*, "group", value = "") :
replacement has 1 row, data has 0
我已经尝试了各种方法排查,数据里没有NA值,且都是数值型数据,请问该如何解决?
以下是可复现的样本数据:
structure(list(index = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), year = c(2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000), team = c("Los Angeles Chargers", "Arizona Cardinals", "Cleveland Browns", "Atlanta Falcons", "Cincinnati Bengals", "Chicago Bears", "Dallas Cowboys", "New England Patriots", "San Francisco 49ers", "Seattle Seahawks", "Carolina Panthers", "Jacksonville Jaguars", "Kansas City Chiefs", "Buffalo Bills", "Washington Commanders", "Detroit Lions", "Green Bay Packers", "New York Jets", "Pittsburgh Steelers", "Indianapolis Colts"), wins = c(1, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10), losses = c(15, 13, 13, 12, 12, 11, 11, 11, 10, 10, 9, 9, 9, 8, 8, 7, 7, 7, 7, 6), ties = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), win_percentage = c(0.063, 0.188, 0.188, 0.25, 0.25, 0.313, 0.313, 0.313, 0.375, 0.375, 0.438, 0.438, 0.438, 0.5, 0.5, 0.563, 0.563, 0.563, 0.563, 0.625 ), points_for = c(269, 210, 161, 252, 185, 216, 294, 276, 388, 320, 310, 367, 355, 315, 281, 307, 353, 321, 321, 429), points_against = c(440, 443, 419, 413, 359, 355, 361, 338, 422, 405, 310, 327, 354, 350, 269, 307, 323, 321, 255, 326), net_points = c(-171, -233, -258, -161, -174, -139, -67, -62, -34, -85, 0, 40, 1, -35, 12, 0, 30, 0, 66, 103), home_record = c("1 - 7 - 0", "3 - 5 - 0", "2 - 6 - 0", "3 - 5 - 0", "3 - 5 - 0", "3 - 5 - 0", "3 - 5 - 0", "3 - 5 - 0", "4 - 4 - 0", "3 - 5 - 0", "5 - 3 - 0", "4 - 4 - 0", "5 - 3 - 0", "5 - 3 - 0", "4 - 4 - 0", "4 - 4 - 0", "6 - 2 - 0", "5 - 3 - 0", "4 - 4 - 0", "6 - 2 - 0"), div_record = c("1 - 7 - 0", "2 - 6 - 0", "2 - 8 - 0", "3 - 5 - 0", "2 - 8 - 0", "3 - 5 - 0", "3 - 5 - 0", "2 - 6 - 0", "1 - 7 - 0", "3 - 5 - 0", "4 - 4 - 0", "5 - 5 - 0", "5 - 3 - 0", "2 - 6 - 0", "3 - 5 - 0", "3 - 5 - 0", "5 - 3 - 0", "6 - 2 - 0", "5 - 5 - 0", "5 - 3 - 0"), last_5_record = c("1 - 4 - 0", "0 - 5 - 0", "0 - 5 - 0", "1 - 4 - 0", "2 - 3 - 0", "2 - 3 - 0", "1 - 4 - 0", "2 - 3 - 0", "3 - 2 - 0", "2 - 3 - 0", "3 - 2 - 0", "3 - 2 - 0", "2 - 3 - 0", "1 - 4 - 0", "1 - 4 - 0", "2 - 3 - 0", "4 - 1 - 0", "2 - 3 - 0", "4 - 1 - 0", "3 - 2 - 0")), row.names = c(NA, -20L), class = c("tbl_df", "tbl", "data.frame"))
问题原因与解决方法
核心问题分析
- 数据维度不足:样本数据仅包含2000年的记录,过滤后
df3只有1行数据,而线性趋势线(lm方法)至少需要2个数据点才能拟合,这直接导致geom_smooth运行失败。 - 动画渲染冲突:
transition_reveal逐帧渲染时,初始帧只有单个数据点,geom_smooth尝试拟合趋势线时会触发空数据帧的错误。 - 数据处理逻辑错误:
summarize调用未添加聚合逻辑,直接保留year和wins会导致数据重复,无法正确按年份聚合球队胜场。
修正后的代码
library(tidyverse) library(gganimate) # 模拟亚特兰大猎鹰队2000-2020年的胜场数据(替换为你的真实多年数据) set.seed(123) df3 <- tibble( year = 2000:2020, team = "Atlanta Falcons", wins = sample(4:14, size = 21, replace = TRUE) ) # 绘制基础图表 graph4 <- ggplot(df3, aes(year, wins)) + geom_line(color = "aquamarine4", linewidth = 1.25) + geom_point(color = "aquamarine4", size = 3) + labs(x = '年份', y= '胜场数', title = '亚特兰大猎鹰队历年胜场趋势') + scale_x_continuous(breaks = seq(2000, 2020, 5)) + scale_y_continuous(limits = c(0, 16), breaks = seq(0, 16, 2)) + # 提前计算全局趋势线,避免逐帧拟合的错误 geom_abline( slope = coef(lm(wins ~ year, data = df3))[2], intercept = coef(lm(wins ~ year, data = df3))[1], color = "orange2", linewidth = 1 ) # 创建动画 animated_plot <- graph4 + transition_reveal(year) + ease_aes('linear') + shadow_mark() + view_follow(fixed_y = TRUE) # 渲染动画 animate(animated_plot, renderer = gifski_renderer(), height = 800, width = 1200, fps = 30, duration = 10, end_pause = 30, res = 100)
关键修改说明
- 补充有效数据:确保数据包含至少2个年份的记录,这是拟合趋势线的基础;如果你的真实数据只有单年记录,建议移除趋势线相关代码。
- 替换趋势线实现:用
geom_abline替代geom_smooth,提前计算全局线性拟合参数,避免动画逐帧渲染时因数据点不足导致的错误。 - 优化轴刻度:调整
scale_x_continuous的刻度间隔,避免年份过多导致重叠;scale_y_continuous固定为0-16区间,符合NFL赛季胜场的合理范围。
内容的提问来源于stack exchange,提问作者albh37
相关产品推荐
相关产品推荐

