Search code examples
ranimationggplot2plotgganimate

How to control appearance of flashing dots in gganimate


Say that I have these data that I want to animate with ggplot2+gganimate.

library(ggplot2)
library(gganimate)

data <- data.frame(day = c(1:5, 1:5), 
    x = c(rep(2,5), rep(4, 5)), 
    y=c(rep(1, 5), rep(2, 5)))

data <- data[c(1:2, 4:10),]

The goals of the animation/question are to

No. 1. have flashing red dots for each day+x+y dot that is in the dataset (meaning there is an observation for that day+x+y). The flash should be very brief. After it flashes, it should go to the background color (controlled by shadow_mark) of black. Note that I do not want dots to float around, only stay where they are (see solution to this question: How to make dots in gganimate appear and not transition).

No. 2. I also want the dots to flash beginning exactly when their day begins. Here is code that does only part of what I want, but fails to (fully) address numbers 1 and 2:

ggplot(data, aes(x,y, group=interaction(x,y))) +
    geom_point(color="red", size=3) +
    transition_time(day) +
    shadow_mark(color="black", size=3) +
    theme(plot.subtitle = element_text(hjust = 0.7)) +      
    labs(subtitle = paste('day: {frame_time}'))  -> a

anim_save("test.gif", a, end_pause=6, width = 400, height = 450, duration=15)

Here is the resulting animation:

enter image description here

This has two problems that I hope to get resolved:

  1. The dots do not only flash momentarily, but flash much too long. In other words, I would like to see a red dot briefly, then black dot, then red dot, etc.
  2. There is also a problem with when the flash begins. This is illustrated when the dot turns to black (because data is missing day 3 for the (x=2,y=1) dot) as expected. However it turns to black partway through day 3 and turns back to red partway through day 4, but I would like it to turn to black exactly at when day 3 begins and flash red exactly when day 4 begins. Note that I am not sure if this time misalignment is caused by transition_time behavior or the subtitle frame_time behavior or something else.

Any suggestions?


Solution

  • Here's an approach where the data is prepped to give 25 frames to each day, where the color is made to flash for just the first of those:

    library(dplyr); library(tidyr)
    f_per_day <- 25
    animate(
      data %>%
        uncount(f_per_day, .id = "frame") %>%
        mutate(time = day + (frame-1)/f_per_day) %>%
    
        ggplot(aes(x, y, color = frame == 1)) +
        geom_point(size = 3) +
        scale_color_manual(values = c("black", "red"), guide = F) +
        theme(plot.subtitle = element_text(hjust = 0.7)) +      
        labs(subtitle = paste('day: {floor(frame_time*10)/10}')) +
        transition_time(time),
    
      width = 400, 
      height = 450, 
      fps = 25, 
      type = "cairo")
    

    enter image description here