Search code examples
rggplot2animationdata-visualizationgif

(R) Error: Aesthetics must be either length 1 or the same as the data (6): x and y


I am working with the R programming language. I am trying to follow the instructions from this tutorial over here (https://www.nagraj.net/notes/gifs-in-r/) for animating 'gifs" in R.

Using the built in "mtcars" dataset, I made the two following graphs:

library(ggplot2)

#graph 1
LINES <- data.frame(ind = 1, Startx=c(1,1,1,3,5,6),#horiz lines then vert lines
                    Starty=c(15,20,35,7,7,7),
                    Endx=c(3,5,6,3,5,6),
                    Endy=c(15,20,35,15,20,35))
a = ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point()+
  geom_segment(aes(x=Startx,y=Starty,xend=Endx,yend=Endy),data=LINES)+
  coord_cartesian(ylim=c(9,36),xlim = c(1.5,6.2))


#graph 2
LINES_1 <- data.frame(ind = 2, Startx=c(2,2,2,4,6,7),#horiz lines then vert lines
                    Starty=c(16,21,36,8,8,8),
                    Endx=c(4,6,7,4,6,7),
                    Endy=c(16,21,36,16,21,36))

b = ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point()+
  geom_segment(aes(x=Startx,y=Starty,xend=Endx,yend=Endy),data=LINES_1)+
  coord_cartesian(ylim=c(9,36),xlim = c(1.5,6.2))

Now, I am trying to follow the instructions from the tutorial and turn these two graphs into an "animation gif":

#create joint dataset 
Lines_frame = rbind(LINES, LINES_1)

library(magick)

## create a directory to which the images will be written


dir_out <- file.path(tempdir(), "tx-sales")
dir.create(dir_out, recursive = TRUE)

for (y in Lines_frame$ind) {
  
  p <-
    Lines_frame %>%
    filter(ind == y) %>%
    ggplot(aes(mtcars$wt,mtcars$mpg)) 
    theme_minimal() +
    labs(x = "wt", y = "mpg")
  
  fp <- file.path(dir_out, paste0(y, ".png"))
  
  ggsave(plot = p, 
         filename = fp, 
         device = "png")

}


## list file names and read in
imgs <- list.files(dir_out, full.names = TRUE)
img_list <- lapply(imgs, image_read)

## join the images together
img_joined <- image_join(img_list)

## animate at 2 frames per second
img_animated <- image_animate(img_joined, fps = 2)

## view animated image
img_animated

## save to disk
image_write(image = img_animated,
            path = "tx-sales.gif")

But this returns the following error:

Saving 3.55 x 4.2 in image
Error: Aesthetics must be either length 1 or the same as the data (6): x and y
Run `rlang::last_error()` to see where the error occurred.

Can someone please show me what I am doing wrong? Is there an easier way to do this?

Thanks


Solution

  • library(gganimate)
    
    # add an id row so that gganimate knows which line in the first 
    #   frame matches the ones in the 2nd
    Lines_frame = rbind(LINES, LINES_1) %>%
      group_by(ind) %>% mutate(id = row_number()) %>% ungroup()
    
    ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() +
      geom_segment(aes(x=Startx,y=Starty,xend=Endx,yend=Endy, group = id),
                   data=Lines_frame)+
      coord_cartesian(ylim=c(9,36),xlim = c(1.5,6.2)) +
      transition_reveal(ind)
    

    enter image description here

    There are a few transition options. For instance, you could alternate back and forth between the two states with transition_states and make the movement tween with a bounce, because why not:

    enter image description here

    # wrapping in `animate()` to access its parameters, like frames per second (fps)
    animate(
      ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point()+
      geom_segment(aes(x=Startx,y=Starty,xend=Endx,yend=Endy),
                   data=Lines_frame)+
      coord_cartesian(ylim=c(9,36),xlim = c(1.5,6.2)) +
      transition_states(ind, state_length = 0.2) + 
      ease_aes('bounce-in'),
      fps = 20, nframes = 200, height = 400, width = 600)