How do I animate this graph so that it displays my trendline along with my points and line graph?

73 views Asked by At

My code looks like this:

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)`

I am trying to print out the Atlanta Falcons' wins and their trend line over time with an animation, but I always get this error on the geom_smooth line of code:

Error in $<-.data.frame(*tmp*, "group", value = "") : replacement has 1 row, data has 0

I have tried every resource to figure this out! There are no NA values and there are numeric values in the data frame. What do I do?

Here is a reproducible sample:

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"))
1

There are 1 answers

0
L Tyrone On

Here is a repex based on your dput(). I generally find it easier to make data work for ggplot() etc., rather than trying to get plots to accommodate data. In other words, instead of creating conditional means on-the-fly, in your case it is easier to calculate them first and add those values to your df.

To that end, the transformr package is ideal. I realise you probably want a static geom_smooth() line rather than an animated one, but this should at least get you on the right track. Note the FPS has been reduced to keep the file size small:

library(gganimate)
library(transformr)

set.seed(1) # for reproducibility of example df
df3 <- data.frame(year = 2000:2023,
                  wins = sample(1:10, 24, replace = TRUE))

# Calculate conditional means and add to df3
smooth_values <- predict(lm(wins ~ year, df3))
df3$smooth_values <- smooth_values

# Plot data
animated_plot <- ggplot(df3, aes(x = year, y = wins)) +
  geom_line(aes(y = wins), 
            colour = "aquamarine4",
            linewidth = 1.25) +
  geom_point(colour = "aquamarine4",
             size = 3) +
  geom_line(aes(y = smooth_values),
            colour = "orange",
            linewidth = 1.25) +
  transition_reveal(year) +
  ease_aes("linear") +
  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)) +
  theme(axis.text.x = element_text(angle = 90))

animate(animated_plot, 
        renderer = gifski_renderer(), 
        height = 800, 
        width = 1200, 
        fps = 10, 
        duration = 20, 
        end_pause = 100, 
        res = 100)

result