[R] minimizing device-dependent code in graphics scripts

Michael Friendly friendly at yorku.ca
Thu Oct 27 16:13:49 CEST 2011

Here is a common scenario that I and probably others often face:

- I write a script, test.R, to produce some graphs, viewing them 
on-screen and tinkering until they look right
- I want to save image files (e.g., .png), so I wrap each plot in device 
driver calls, e.g.,

png(file='test01.png', width=600, height=600);

png(file='test02.png', width=600, height=600);

- Then I want to include those graphs in a document, so maybe I want 
them in .pdf or .eps format.  So I have
to modify all the device calls to pdf() or postscript(), changing the 
filenames and perhaps other options.
If I want those graphs to be squentially numbered with filenames like 
'test%02d' and insert a new graph
in the sequence, I have to edit all the filenames after the insertion.
There has to be an easier way.  (I know I could use Sweave, but that 
introduces another layer that I want to
avoid while I'm developing plots.)

This contrasts strongly with what I've done for many years with SAS:  I 
use *no* device-dependent code in .sas
files, but instead use a collection of device-independent macros that 
respond to a global macro variable, DEVTYP.
On linux, a custom (perl) script sets this as an environment variable 
used by these macros, so I can run test.sas at the
command line via

% alias s=mysas
% s -b -d eps test
% s -d pdf test
% s -v -d png test

and get test1.eps, test2.eps, ... etc. where the basename of the image 
files is automatically set to something
like 'test%01d'.  The -v option opens each of the generated graphics 
files in an appropriate viewer (gs, display, xpdf, etc.)
The -b option for .eps files runs a bbfix script to adjust bounding 
boxes on .eps files.

I don't need anything this elaborate for R, but it's a long way from 
what I do with SAS vs what I do currently with R.
Perhaps other have some partial solutions for this general problem 
they'd be willing to share.

For what it's worth, here is an initial sketch of one approach, using 
two general functions, img() and img.off().
Perhaps others could help improve it.

############  img.R ###################
# shorthand for eps()
eps <- function(file="Rplot.eps", horizontal=FALSE, paper="special", 
height=6, width=6, ...) {
     postscript(file=file, onefile=FALSE, horizontal=horizontal, 
paper=paper, height=height, width=width,...)

img <- function(file, type,
                 height=6, width=6, res=100, units="in", ...) {

     # handle image types
     types <- c("bmp", "eps", "jpg", "pdf", "png")
     if (missing(type)) {
         if (exists("imgtype")) {
             if (is.null(imgtype)) return() else type <- imgtype
     else {
         t <- match(type, types, nomatch=0)
         if(t > 0) type <- types[t] else stop("unknown file type")

     if (exists("imgnum") imgnum <<- imgnum+1
     else imgnum <<- 1

# TODO: Handle global imgnum in filename
     if (missing(file)) {
         file <- if(exists("imgname")) paste(imgname, '%03d', sep='') 
else "Rplot%03d"
     filename <- paste(file, '.', type, sep='')
          bmp = bmp(filename, height=height, width=width, res=res, 
units=units, ...),
          eps = eps(filename, height=height, width=width, ...),
          jpg = jpeg(filename, height=height, width=width, res=res, 
units=units, ...),
          pdf = pdf(filename, height=height, width=width, ...),
          png = png(filename, height=height, width=width, res=res, 
units=units, ...)

img.off <- function() {
     if (exists("imgtype") & !is.null(imgtype)) dev.off()


if(TESTME) {

# set global image name and starting number
imgname <- 'test'
imgnum <- 1
imgtype <- NULL   # screen output

plot(1:10, main=paste("imgtype:", imgtype))

imgtype <- "pdf"
plot(10:1, main=paste("imgtype:", imgtype))


Michael Friendly     Email: friendly AT yorku DOT ca
Professor, Psychology Dept.
York University      Voice: 416 736-5115 x66249 Fax: 416 736-5814
4700 Keele Street    Web:   http://www.datavis.ca
Toronto, ONT  M3J 1P3 CANADA

More information about the R-help mailing list