Saving plots in R as GIFs

14,454

R doesn't have a native GIF graphics driver, mostly (completely?) due to the patent-encumbrances of the GIF format: see http://tolstoy.newcastle.edu.au/R/help/05/02/12809.html .

There is a function in the caTools package (write.gif()) but it is specifically designed for writing images. If you wanted to use it you have to do something hacky to convert your plot to an image first (e.g. save as PNG and then read it back into R as an image). For example:

png("myPlot.png")
plot(rnorm(1000),rnorm(1000))
dev.off()
library(png)
P1 <- readPNG("myPlot.png")
library(caTools)
write.gif(P1,"myPlot.gif")
showGIF <- function(fn) system(paste("display",fn))
showGIF("myPlot.gif")
unlink("myPlot.gif")  ## clean up

?write.gif() has a lot of stuff about color indexing that I didn't read but that might be important for more complex graphs ...

The animation package has a saveGIF() function to save GIFs, but (1) it is designed for saving multi-frame animations (not general graphics), and (2) it does it by calling ImageMagick.

It's easier just to construct that function yourself.

For example:

png("myPlot.png")
plot(rnorm(1000),rnorm(1000))
dev.off()
system("convert myPlot.png myPlot.gif")
unlink("myPlot.png") ## clean up
showGIF("myPlot.gif")
unlink("myPlot.gif") ## clean up

Of course you can either of these in a function if you want to use them regularly.

UPDATE: I spent a while longer on this, to try to get a pure-R solution, but don't yet have a working solution. Suggestions or edits welcome ...

## needs ImageMagick: just for testing ...
showGIF <- function(fn) system(paste("display",fn))

The main function:

saveGIF <- function(fn,verbose=FALSE,debug=FALSE) {
    require(png)
    require(caTools)
    tmpfn <- tempfile()
    on.exit(unlink(tmpfn))
    savePlot(tmpfn,type="png")
    P1 <- readPNG(tmpfn)
    dd <- dim(P1)
    P1 <- aperm(P1,c(3,1,2),resize=TRUE)  ## P1[,1,15]
    dim(P1) <- c(dd[3],prod(dd[1:2]))
    P1 <- t(P1)
    if (verbose) cat("finding unique colours ...\n")
    P1u <- unique(P1)
    rgbMat <- function(x) {
        rgb(x[,1],x[,2],x[,3])
    }
    if (verbose) cat("creating colour index ...\n")
    pp <- paste(P1[,1],P1[,2],P1[,3],sep=".")
    ## make sure factor is correctly ordered
    ind <- as.numeric(factor(pp,levels=unique(pp))) 
    if (verbose) cat("finding colour palette ...\n")
    if (nrow(P1u)>256) {
        if (verbose) cat("kmeans clustering ...\n")
        kk <- kmeans(P1u,centers=256)
        ind <- kk$cluster[ind]
        pal <- rgbMat(kk$centers)
    } else {
        pal <- rgbMat(P1u)
    }
    ## test:
    if (debug) {
        dev.new()
        par(mar=rep(0,4))
        image(t(matrix(ind-1,nrow=dd[1])),col=pal,axes=FALSE,ann=FALSE)
    }
    if (verbose) cat("writing GIF ...\n")
    indmat <- matrix(ind-1,nrow=dd[1])
    storage.mode(indmat) <- "integer"
    write.gif(indmat,fn,col=as.list(pal),scale="never")
}


X11.options(antialias="none")
image(matrix(1:64,nrow=8),col=rainbow(10))
saveGIF("tmp.gif",verbose=TRUE,debug=TRUE)
showGIF("tmp.gif")
Share:
14,454

Related videos on Youtube

Tomas
Author by

Tomas

Updated on September 24, 2022

Comments

  • Tomas
    Tomas over 1 year

    In R, I use function savePlot to save graphs into image files. But my colleague can only open .jpgs and .gifs (probably because he's on vacation, reading emails on his mobile phone). I hate to create jpegs because especially the boxplots looks very ugly (whiskers blurred etc.). But the savePlot function only supports the following types:

    type = c("wmf", "emf", "png", "jpg", "jpeg", "bmp",
                      "tif", "tiff", "ps", "eps", "pdf")
    

    How can I save plot in GIF in R?

    EDIT: if possible, ideal solution should work without installing ImageMagick (so that the R script is easily portable).

  • Tomas
    Tomas over 10 years
    Thank you Ben! I would like a solution that would work without installing ImageMagick (so that the R script is easily portable), but the first solution with write.gif does not work. It produces animated greyscale (!) gif. Seems that the write.gif function is not able to produce optimal palette (i.e. doesn't have the color clustering algorithm to create optimal 256 colour palette).
  • Ben Bolker
    Ben Bolker over 10 years
    it looks like write.gif may have some more options -- did you try scale="never"? It certainly doesn't seem to have colour clustering algorithm, but a relatively simple graphic might not need one ...