Animating 2D random walk trajectory with ggplot in R

194 views Asked by At

I'm trying to create an animation that shows the trajectory of a random walk on the (x,y) plane over time. Each 'step' is a move in either the vertical or horizontal direction, never both. For example, if you start at (0,0) you have only four options: (0,1), (0,-1), (1,0), (-1,0); you can never go from (0,0) to (1,1) in one step.

I've written the random walk generating function to ensure that steps can only be taken across one axis at a time. Here is a regular ggplot without animation of one of these random walks using geom_path() and geom_point():

Random walk with T=100

When I try to animate the walk, however, it shows diagonal lines connecting the points which is impossible.

Animated trajectory

I can't figure out why this is happening. I've tried using geom_line() instead but that doesn't seem to fix the issue. The code for the animation is below:

ggplot(df,aes(x=x,y=y)) + 
  geom_path() +
  geom_point() +
  transition_reveal(along=ite) + # ite: numerical ordered variable in df representing the time from 0:n
  scale_x_continuous(breaks = seq(min(df$x), max(df$x), by = 1)) +
  scale_y_continuous(breaks = seq(min(df$y), max(df$y), by = 1)) +
  coord_fixed() +
  theme(panel.grid.minor = element_blank())
1

There are 1 answers

0
chemdork123 On BEST ANSWER

The number of frames in your animation are smaller than the number of states you are revealing along ite. This means that at least every once in a while, transition_reveal() must "skip" across a few states of ite and this results in sometimes drawing a diagonal line.

Increase the frames in your animation to match the number of steps for ite. You can specify that in animate() when showing your animation or anim_save() when saving.

Example and Solution

Here's a demonstration using my own random walk function that works as you describe.

Note that it's useful to use {frame_along} within one of the labels in the plot that can be used to follow the particular state which is being shown.

library(ggplot2)
library(gganimate)

walk <- function(steps) {
  x <- vector(length=steps)
  y <- vector(length=steps)
  x[1] <- 0
  y[1] <- 0
  direction <- 0
  amt <- 0
  for (i in 2:steps) {
    direction <- rbinom(1, 1, 0.5)
    amt <- sample(c(-1,1), 1)
    if(direction==0) {
      x[i] <- x[i-1] + amt
      y[i] <- y[i-1]
    }
    else{
      x[i] <- x[i-1]
      y[i] <- y[i-1] + amt
    }
  }
  return(data.frame(x,y, ite=1:steps))
}

df <- walk(200)

p <- 
  ggplot(df, aes(x,y)) +
  geom_path() + geom_point() +
  labs(title="it: {frame_along}") +  # meant to write ite, but ok
  theme_bw()

a <- p + transition_reveal(along=ite)

Here's the plot without animation.

enter image description here

Here's the animation. Note how the value for ite ("it: ##") is sometimes "jumping" across a few values.

enter image description here

To fix, you can specify nframes= within animate() instead of just calling a directly. You will note in the output that the value for ite is incrementing every state now and not skipping. This is why you always have the straight lines.

animate(a, nframes=200)

enter image description here