Days 20-21: Cat GIFs. Irises. Magick

Right. So I was working on a post talking about my efforts to learn more about non-standard evaluations, expressions, scoping rules and other scary things about R that I don’t really understand as well as I should (I’ve been reading this for some reason) but then the awesome Lisa Williams tweeted this:

… so naturally now I MUST LEARN THIS SORCERY.

Clicking through the links leads me to this post from Daniel Hadley. I’ve never used the magick package before, but I think I’ve incidentally interacted with it while trying to work out animations and some other image processing things? Anyway, I set myself a simple task.

In real life cats and irises don’t get along but I don’t care. I want to add a cat gif to a plot of the famous iris data, so that’s my task. Turns out to be surprisingly painless!

First, I load packages, draw a simple ggplot image, and save it as iris.png:


ggplot(iris, aes(x=Petal.Width, y=Sepal.Width, colour = Species)) + 
  geom_point() + theme_bw() +
  ggsave(filename ="iris.png", width = 5, height = 4, dpi = 300)

Next, I find a cat gif. Looking at the Daniel Hadley post suggests what I need to do next is read the iris pic in along with the cat gif…

irispic <- image_read("iris.png") 
catgif <- image_read("1V7a.gif")

From what I understand from skimming the vignette, we aren’t literally loading anything into R here. The magick package is just a wrapper to the Magick++ library, and all the processing is being done outside of R

Anyway from here it’s surprisingly straightforward. The image_composite function allows you to compose two images together in a variety of different ways. What’s nice is that it operates on vectorised input. The irispic image is just one image but catgif is an animated gif with 58 frames…

> head(image_info(catgif))
  format width height colorspace matte filesize density
1    GIF   500    282       sRGB  TRUE   565642   72x72
2    GIF   500    282       sRGB  TRUE   565642   72x72
3    GIF   500    282       sRGB  TRUE   565642   72x72
4    GIF   500    282       sRGB  TRUE   565642   72x72
5    GIF   500    282       sRGB  TRUE   565642   72x72
6    GIF   500    282       sRGB  TRUE   565642   72x72

… so if I feed in irispic as the background image and catgif as the composite image, and it will overlay each frame of the cat gif onto the iris picture background.

Because the irispic image is bigger I specify an offset to move the cat where we want it:

frames <- image_composite(irispic, catgif, offset = "+70+800")

Finally, stitch the frames together as an animation, and write it to a new gif…

animation <- image_animate(frames, fps = 10)
image_write(animation, "iriscat.gif")

The last step takes ages, which I think is happening because magick is lazy? If I’ve understood this right, it doesn’t actually do anything until it really needs to, so it’s only at the time I tell it to write something that it starts processing?? I should probably read the docs.


Danielle Navarro
Associate Professor of Cognitive Science