Search code examples
rggplot2gganimate

animating only one line and two static lines in a plot with gganimate


I want to animate some data as a black line that is circumscribed by two static red lines. The static lines are UP and DOWN. My animated data is in y and the timeline is x.

I tried a lot - with transition_components() and transition_layers() - but nothing worked... but perhaps I had some failures in my code I'm not sure... How to assign color to lines I found Changing line colors with ggplot() but my handling isn't proper...

My gganimate code that has to be completed:

# load the needed packages
library(gifski)
library(ggplot2)
library(gganimate)
theme_set(theme_bw())

# add the time vector x
### 10.1 seconds with timestep 0.1 seconds
x=rep(seq(from=0,to=10,by=0.1),times=3)

# y should be the line in the plot which should be animated
y=c(seq(from=0,to=10,length.out=which(round(x,1)==2)[1]),rep(10,times=which(round(x,1)==5)[1]-which(round(x,1)==2)[1]),10*0.95^(seq(from=1,by=1,length.out=50)))

# UP and DOWN should be static lines in the animated plot
### there shouldn't be a "linemoving" from left to rigth side of the plot
UP=c(seq(from=1,to=12,length.out=which(round(x,1)==1.8)[1]),
    rep(12,times=which(round(x,1)==5.5)[1]-which(round(x,1)==1.8)[1]),
    seq(from=12,to=4,length.out=length(seq(from=0,to=10,by=0.1))-which(round(x,1)==1.8)[1]-(which(round(x,1)==5.5)[1]-which(round(x,1)==1.8)[1]))
    )
DOWN=c(seq(from=0,to=8,length.out=which(round(x,1)==2.2)[1]),
    rep(8,times=which(round(x,1)==4.5)[1]-which(round(x,1)==2.2)[1]),
    seq(from=8,to=1,length.out=length(seq(from=0,to=10,by=0.1))-which(round(x,1)==2.2)[1]-(which(round(x,1)==4.5)[1]-which(round(x,1)==2.2)[1]))
    )


value=c(y,UP,DOWN)
h=length(seq(from=0,to=10,by=0.1))
variable=c(rep("y", h), rep("UP", h), rep("DOWN", h) )

# the dataframe with the three columns
df=data.frame(x, variable, value)

p=ggplot(df, aes(x=x, y=value, group=variable, colour=variable ) ) + geom_line(size=2) + scale_color_manual(values=c("black", "red", "red")) # I want that y is a black line and UP and DOWN are red lines

# x is my time variable in the dataframe
p2=p + transition_reveal(x)

# animating p2
animate(p2)

The finished plot should look like this pictureenter image description here

To me here are arising some questions:

  1. How can I achieve that only my black line (y vector) is animated and the two black lines (UP and Down) remain static
  2. Assigning the color to the lines in a proper way
  3. Where is my gif saved
  4. Is it needed that all my lines are defined from the beginning of the timeline x? Or is it possible to start the UP vector at x[10]=0.9 seconds.

Solution

  • Question 1 is the trickiest. You need to organize your data such that the x values for your two static lines have a different name (such as static_x), and do not have any actual x values. It's probably easiest to split df into two different frames to do this:

    df_y <- df[variable == "y", ]
    df_not_y <- df[variable != "y",]
    df_not_y$static_x <- df_not_y$x
    df_not_y <- df_not_y[names(df_not_y) != "x"]
    

    Then, to handle question 4, we will remove all values of the variable UP before 1 second:

    df_not_y$value[df_not_y$static_x < 1 & df_not_y$variable == "UP"] <- NA
    

    Now we can plot. We want two geom_line calls, one for the static variables and one for the moving variable. To answer question 2, we assign the colours by name inside scale_color_manual so that we ensure the levels are correct.

    p <- ggplot(df_y, aes(x = x, y = value, colour = variable)) + 
          geom_line(aes(x = static_x), data = df_not_y, size = 2) +
          geom_line(size = 2) +
          scale_color_manual(values = c(UP = "red", y = "black", DOWN = "red"))
    
    p2 <- p + transition_reveal(x)
    
    animate(p2)
    

    enter image description here

    That leaves question 3. In this case, I simply right clicked on the viewer panel and selected "save image", but you can also do gganimate::anim_save("mygif.gif", last_animation()) if you find this more convenient.