Producing graphs for inclusion in reports and slides

Frank E Harrell Jr (fharrell@virginia.edu)
Sat, 24 Jan 1998 10:56:31 -0500


>From time to time S-PLUS users ask about how best to produce graphics
for inclusion in reports, presentations, etc. I don't know which way is the
best, but there are functions in my Hmisc library (in statlib) that are helpful.
These functions set up nice defaults for fonts, character sizes, tick marks,
axis labeling, etc. that are more 'publication quality.' They solve a few simple
problems such as reducing wasted space between tick marks and axis
labels. ps.slide uses Times-Roman font. Here they are:

ps.slide - for postscript output (supports 4 media, e.g., 35mm format, 5x7", full page)
win.side - for Windows metafiles
gs.slide - for S-PLUS 4.0 graph sheets

I use LaTeX for most reports and talks and have a series of standard LaTeX 'newcommands' for
bringing in postscript files. gs.slide is especially good for cut-and-paste into Word.

Antonio Possolo and I have also written the functions at the end of this note. I use
setps(graphname.not.in.quotes) for making small graphs to use in book manuscripts.
I do not have further documentation for these 2 functions. Happy plotting.
---------------------------------------------------------------------------
Frank E Harrell Jr
Professor of Biostatistics and Statistics
Director, Division of Biostatistics and Epidemiology
Dept of Health Evaluation Sciences
University of Virginia School of Medicine
http://www.med.virginia.edu/medicine/clinical/hes/biostat.htm

#setps <- function(filename, w=4.5, h=4, b=5, type="symbol", mgp=c(1.5,.5,0),
# lwd=1,leftlines=0)
#{ #was w=6 h=4 mgp=c(1.5,.3,0)
# if(type=="char") filename <- paste(filename,".ps",sep="") else
# filename <- paste(substitute(filename),".ps",sep="")
# postscript(filename, horizontal=F, width=w, height=h)
# par(mar=c(b,4,1,0),mgp=mgp,lwd=lwd)
# invisible() }
setps <- function(filename, w=0, h=3, pointsize=10, sublines=0, toplines=0,
type="symbol",lwd=2, font="Times-Roman",leftlines=0)
{
if(type=="char") filename <- paste(filename,".ps",sep="") else
filename <- paste(substitute(filename),".ps",sep="")
psfig(filename, h=h, w=w, ratio=1.4,
pointsize=pointsize,sublines=sublines,toplines=toplines,
lwd=lwd,font=font,leftlines=0)
invisible() }

#Changed after submission to s-news: pointsize=NULL
#Antonio likes the default
#ratio of width/height to be the "golden ratio", which is the default.
#I often prefer a smaller ratio of 1.4. If exactly one of (width, height)
#is zero, the "ratio" is used to replace it based on the one specified.
#For a single figure in the plot I usually use psfig(filename,height=3).
#For a single figure in the plot I usually use psfig(filename,height=3).
#The logic in psfig assumes that one figure is being drawn, i.e., that
#par(mfrow=c(1,1)) is in effect. It will work for multiple plots if you
#set pointsize to something like 9.
#sublines specifies the number of extra lines to leave at the bottom of
#the plot for subtitles.
#
# I include an S function that sets the stage for EPS graphics
#generation that will be incorporated by TeX (LaTeX, etc.), and that
#does a little of what you want, by hand, not in the smart way you
#envision.
# Note that this function intentionally disallows main titles, with
#the understanding that they will be part of the figure's caption,
#which TeX itself generates. You may like to use it as starting point
#to get something that suits your needs.
#
# - Antonio Possolo
#
# Applied Mathematics & Statistics
# The Boeing Company
# antonio@atc.boeing.com
#
#
#Added else scale <- FEH 8Sep92, also added arg "ratio",
#commented out warning message for omitting main title,
#added arg sublines, pointsize
#may want to specify pointsize=9 if multiple plots used
#added lwd FEH 27Oct92
#added toplines FEH 18Oct93
#override fonts spec to ps.options because of bug - FEH 21Apr94
#added bty="l" FEH 24Aug94
#added leftlines FEH 26Aug94
#added onefile 27Feb95
#Doug Bates just does this:
#a) use postscript(filename, height=xx, width=yy, pointsize=10)
#b) change the figure's region on the page by using
# par (mar=c(3.5, 3.5, 1.5, 0.5)) ## for example and perhaps also
# par (mgp=c(2.5, 0.5, 0))
#
"psfig"<-
function(file = "", width = 0, height = 0, ratio= (1 + sqrt(5))/2,
font = "Times-Roman", pointsize=NULL, sublines=0,
toplines=0, leftlines=0, lwd=0.5, bty="l", onefile=F)
{
# POSTSCRIPT FIGURE MAKER
# for incorporation into TeX using PSFIG or BoxedEPSF.
# The strategy is to create a pleasant aspect ratio,
# while minimizing white space around the figure.
#
# Aspect ratio is Golden Ratio
# Standard width is 30 picas = 30*12/(72.27) inches
StandardWidth <- (30 * 12)/(72.27)
StandardHeight <- StandardWidth/ratio
StandardPointSize <- 9
if ( width == 0 & height == 0 )
{
width _ StandardWidth
height _ StandardHeight
scale _ 1
}
if ( width > 0 & height == 0 )
{
height <- width/ratio
scale <- width/StandardWidth
}
if ( width == 0 & height > 0 )
{
width <- height*ratio
scale <- width/StandardWidth
}
else scale <- max(width/StandardWidth,height/StandardHeight)
if(is.null(pointsize)) pointsize <- round(scale * StandardPointSize)
#
# FONTS & FONT SELECTION
#
# 1 Helvetica 19 Bookman-DemiItalic
# 2 Courier 20 Bookman-Light
# 3 Times-Roman 21 Bookman-LightItalic
# 4 Helvetica-Oblique 22 Helvetica-Narrow
# 5 Helvetica-Bold 23 Helvetica-Narrow-Bold
# 6 Helvetica-BoldOblique 24 Helvetica-Narrow-BoldOblique
# 7 Courier-Oblique 25 Helvetica-Narrow-Oblique
# 8 Courier-Bold 26 NewCenturySchlbk-Roman
# 9 Courier-BoldOblique 27 NewCenturySchlbk-Bold
# 10 Times-Italic 28 NewCenturySchlbk-Italic
# 11 Times-Bold 29 NewCenturySchlbk-BoldItalic
# 12 Times-BoldItalic 30 Palatino-Roman
# 13 Symbol 31 Palatino-Bold
# 14 AvantGarde-Book 32 Palatino-Italic
# 15 AvantGarde-BookOblique 33 Palatino-BoldItalic
# 16 AvantGarde-Demi 34 ZapfChancery-MediumItalic
# 17 AvantGarde-DemiOblique 35 ZapfDingbats
# 18 Bookman-Demi
#
ps.fonts <- if(under.unix)ps.options()$fonts else ps.fonts
if(is.number(font)) {
fontNumber <- font
if(fontNumber < 1 | fontNumber > length(ps.fonts)) {
fontNumber <- 1
cat(paste(
"\tPSFIG WARNING: Font requested is not available\n",
"\t\tSubstituted by Helvetica\n"))
}
}
else {
fontName <- font
fontNumber <- match(fontName, ps.fonts)
if(is.na(fontNumber)) {
fontNumber <- 1
cat(paste(
"\tPSFIG WARNING: Font requested is not available\n",
"\t\tSubstituted by Helvetica\n"))
}
}
if(under.unix)
postscript(file = file, horizontal = F, width = width, height = height,
pointsize = pointsize, fonts=ps.fonts[fontNumber], font = 1,
maximize=T, onefile=onefile, print.it=F)
# was font=fontNumber, fonts omitted - bug
else
postscript(file = file, horizontal = F, width = width, height = height,
pointsize = pointsize, fonts=ps.fonts[fontNumber], font = 1)
#
# PLOT DESIGN
# Lines are 1pt wide, which is half standard width
# (LWD is interpreted in units of 1/36 inch
# LWD=0 yields the thinnest possible line on the device)
# Axis labels closer to axes than default
# (MGP: margin line for the axis title, axis labels,
# and axis line in units of MEX)
# Margin widths narrower than default
# (MAR: bottom, left, top, right)
par(lwd = lwd, mgp = c(2, 0.5, 0),
mar = c(3+sublines+.25*(sublines>0), 3+leftlines, 1+toplines, 1) +
0.10000000000000001, bty=bty)
# SMO is number of rasters that the piecewise linear
# approximation to a curve is allowed to differ from the exact
# position of the curve.
par(smo = 0) # PLOTTING SYMBOL
# PCH selects plotting characters from Standard Encoding
# (PostScript Language Reference Manual, p.252)
# 168 = currency
# 180 = centered period
# 183 = bullet (with a negative font parameter yields a circle)
par(pch = 183) #
# MAIN TITLE not allowed: plot will be described in figure caption,
# handled by TeX itself.
# cat(paste("\tPSFIG WARNING:", "Do not use high-level parameter MAIN\n",
# "\t\tFigure caption should be created within LaTeX\n")) #
invisible()
}