[R] minimizing device-dependent code in graphics scripts

Duncan Murdoch murdoch.duncan at gmail.com
Thu Oct 27 16:32:27 CEST 2011


On 27/10/2011 10:13 AM, Michael Friendly wrote:
> 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);
> plot(1:10)
> dev.off()
>
> png(file='test02.png', width=600, height=600);
> plot(10:1)
> dev.off()
> ...
>
>
> - 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.)

I use Sweave, more or less as you describe at the top:  I fiddle with 
the graphs on screen first, then when they're fine, I put the code into 
the document.  Mostly the documents use PDF figures, but it's a global 
change at the top if I want something else.  Since all the fiddling is done
on screen, I don't have the issue of Sweave overhead being a problem 
during development (and it's generally pretty low overhead, as long
as I don't put long computations into the documents).

But if I wanted to avoid device calls in scripts, I'd probably do what 
you did below.

Duncan Murdoch

> 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='')
>     switch(type,
>            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()
> }
>
>
> TESTME<- FALSE
>
> if(TESTME) {
>
> # set global image name and starting number
> imgname<- 'test'
> imgnum<- 1
> imgtype<- NULL   # screen output
>
> img()
> plot(1:10, main=paste("imgtype:", imgtype))
> img.off()
>
> imgtype<- "pdf"
> img()
> plot(10:1, main=paste("imgtype:", imgtype))
> img.off()
>
> }
>
>
>
>



More information about the R-help mailing list