This code is designed to generate a 3D plot using the wireframe() function in the lattice package, and export it to an animated image performing an orbital rotation. Whilst I found a multitude of ways of making interactively rotatable 3D figures within R, I could not find a satisfying workflow for exporting them. So here we are.

The following packages are required:

library(lattice)
library(animation)
## Warning: package 'animation' was built under R version 3.2.4

Our first job is of course to create the graph in question. This can be any graph plotted using wireframe() - for demonstration purposes, I will use the volcano data that comes with R.

wireframe(volcano, shade = TRUE,distance=0,
        screen=list(z=50,x=-60),
        xlab="",ylab="",zlab="",scales=list(draw=FALSE))

You can of course use any plot made by lattice in place of this (either with the wireframe() or cloud() function). The important bits to note here are distance=0 and screen=list(z=50,x=-60). Distance is essentially the perspective of the whole thing. If not specified, R will recalculate it each rotation, which can lead to an odd effect. Screen refers to the angle that the graph is viewed from. In this case, the z value here will be what we vary (so as to rotate the graph around its vertical axis).

Our goal here is to write a function that will generate successive graphs, each at a different stage of rotation. The animation package will then stick these together into our final output. The function’s main form is very similar to the graph-generating code above.

draw.plot <- function(angles)
{
  for(i in 1:length(angles))
  {
    print(wireframe(volcano, shade = TRUE,distance=0,
        screen=list(z=angles[i],x=-60),
        xlab="",ylab="",zlab="",scales=list(draw=FALSE)))
    setTxtProgressBar(txtProgressBar(style=3),i/length(angles))
  }
}

As you can see, the function takes a vector (called “angles”) and prints a series of plots, for each element in “angles”. For each element, that value is used as the perspective on the Z axis. Thus, we must define our “angles” vector to go from 1 to 360 to have a nicely looping animation. I also added a progress bar, since more complex graphs can take time to render each frame, so it’s nice to see everything hasn’t just frozen up.

angles <- seq(from=1,to=360,by=1)

The “by” part of this sequence is important - it’s essentially the number of steps along the rotation. Smaller values give slower but smoother rotation. 1 is as good of a starting point as any.

Finally, we call the saveGIF() function from the animation package. This takes our plot-generating function (with the vector of angles as its argument) and combines the plots generated into a single animation. Arguments of note include:

Interval – The number of seconds to display each frame for. I chose 1/30, as this gives a fairly standard framerate of 30fps.

movie.name – This is extra-important as it specifies not only the name but also the output file format (which must be in upper case). The function is always called saveGIF(), but you can use this argument to get it to render a GIF, MP4, HTML etc.

ani.height & ani.width – These specify the dimensions of the finished animation, in pixels.

One thing of note - you need to have ImageMagick (a seperate program) installed in order for this to work, as that’s the real workhorse that combines the images into an animation.

saveGIF(draw.plot(angles), interval = 1/30, movie.name="output.GIF",
          ani.height=640,ani.width=640)
## [1] TRUE

And there you have it! There is a 3D gif/video ready to be uploaded to social media, or embedded in a webpage, or whatever. For some reason, the R Markdown version has a pink background - it will be white on the actual gif, I assure you! Thanks for reading - if you have any suggestions, I’m happy to listen!