Making an animated ggplot

I decide to talk about how I make my awesome blog banner in this first post. 😄

Why this banner ?

It’s a french wordplay with my family name Sauder => Saut d’R (R jump in english). That’s why I decided to make a banner with the R-logo jumping on some (so cool) stickers. I choose stickers of packages that I use to do this animated ggplot.

Which packages ?

library(tidyverse)

# install.packages("devtools")
# devtools::install_github("GuangchuangYu/ggimage")
# devtools::install_github('thomasp85/gganimate')

library(ggimage)
library(magick)
library(gganimate)

Firstly, I always use the tidyverse 📦, because it contains dplyr, ggplot2, purrr… and some other unavoidable packages.

Then, to deal with images, my favorite package is magick, an other unavoidable package ! It allows to read/write/transform/convert images, and to make some beautiful GIF too. See the vignette for more informations, it’s really cool.

To replace ggplot2 points by some images, I find the ggimage package. And to animate these images, the gganimated package.

Jumping trajectory

This part is not very interesting and you probably do this better, but it’s just about describing jumps with data.

x0 <- -8:8
y <- rep((-x0^2)/100 +1 ,3 )
y <- y + seq(0,3, length.out = length(y))
y <- c(y, rev(y))

# just to have a look
plot(y)

Get images and tidy data

Firstly, a tibble (a tidy data.frame if you don’t know yet) with the R trajectory y, the abscissa x and x1 which will serve to animate R, and the R logo url directory in image.

ly <- length(y)

# first tibble for R trajectory
d <- tibble(
  x = 1:ly,
  x1 = 1:ly,
  y = y,
  image = rep("https://www.r-project.org/logo/Rlogo.png",ly)
)

Then I decide to make a local copy of the R logo image, resizing it at 200px for witdh, because even if ggimage can deal with url images, it took a long time to do this with the 102 images. So I use the magick package to read, scale, and write the R logo.

#local copy of Rlogo
"https://www.r-project.org/logo/Rlogo.png" %>%
  image_read() %>%
  image_scale("200") %>%
  image_write("Rlogo.png")

I add the column image2 to the tibble with the name of the R logo file.

d <- d %>%
  mutate(image2 = rep("Rlogo.png",ly))

Display and animate the R logo

Now we have all we need to animate the R logo. So let’s test this !

Firstly just with geom_image :

options(gganimate.dev_args = list(width = 400, height = 300))

gg <- ggplot(d, aes(x, y)) +
  geom_image(aes(image=image2), size=.1 , by = 'width')

gg

It seems to work, so now, let’s animate this logo, after quiting lines and grey background with theme_nothing. For now, I test the “linear” ease but others are available and describe in the function ease_aes help.

gg <- gg +
  theme_nothing() +
  transition_time(x1) +
  ease_aes('linear')

gg

Add the stickers on the plot

Now let’s add the stickers. I make an other tibble to deal with a different aes in ggplot. I put the url directory of some beautiful stickers.

x3 = seq(0,ly, by = length(x0))
y3 = c(0.36,d$y[x3])
y3 = y3 - 0.4

d2 <- tibble(
  x3 = x3+2,
  y3 = y3,
  hex = c(
    #"https://github.com/rstudio/hex-stickers/blob/main/PNG/blogdown.png",
    "https://raw.githubusercontent.com/rstudio/hex-stickers/main/PNG/blogdown.png",
    #"https://github.com/rstudio/hex-stickers/raw/master/PNG/blogdown.png",
    "https://raw.githubusercontent.com/rstudio/hex-stickers/main/PNG/devtools.png",
    "https://raw.githubusercontent.com/rstudio/hex-stickers/main/PNG/tibble.png",
    "https://raw.githubusercontent.com/rstudio/hex-stickers/main/PNG/pipe.png",
    #"https://github.com/thomasp85/gganimate/raw/master/man/figures/logo.png",
    "https://github.com/thomasp85/gganimate/raw/main/man/figures/logo.png",
    "https://raw.githubusercontent.com/rstudio/hex-stickers/main/PNG/tidyverse.png",
    "https://raw.githubusercontent.com/rstudio/hex-stickers/main/PNG/ggplot2.png"
  )
)

Now the part using magick to locally copy the images. To process all the images at once, I use the map2_chr function of the purrr package

hex2 <- d2$hex %>%
  image_read() %>%
  image_scale("200")

hex2 il a tibble, so I transform it in a list to give it to map2_chr. Why map2_chr and not just map2 ? Because I want characters 😄

You can do the same with map2 if you unlist the result.

hex3 <- map2_chr(as.list(hex2), basename(d2$hex), image_write)

d2 <- d2 %>%
  mutate(hex3 = hex3)

Once the column with the files names added to the tibble, we can plot it. I just have to change ylim of the ggplot because min(y3) < min(y)

gg <- gg +
  ylim(min(y3)-0.2,max(y)) +
  geom_image(data = d2, aes(x=x3, y=y3, image = hex3), size = .1, by = 'height')

gg

Yes ! It’s better like this. If you love the result you can save it with anim_save.

anim_save("saut_dR.gif")

I remove images locally copied.

unlink(c("Rlogo.png", hex3))

That’s all for today 💋

 Share!

 
comments powered by Disqus