[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);
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.)
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()
}
--
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