NOTICE: You are viewing a page of the openwetware wiki. Our "dewikify" feature makes a wiki page appear as a normal web page. In March 2017, this feature will GO AWAY and this URL will redirect to the source URL on our wiki. We're sorry for the inconvenience.
Notice: The Wilke Lab page has moved to
The page you are looking at is kept for archival purposes and will not be further updated.

Home        Contact        People        Research        Publications        Materials


Creating Publication-Quality Figures

Many different programs can be used to generate figures. Unfortunately, almost all graphing programs have poor default settings. Therefore, if you create a figure without changing the defaults, you can be almost certain that your figure is not ready to be published.

Here are a few general guidelines:

Example of a poorly designed figure.
Example of a poorly designed figure.
An improved version of the same figure.
An improved version of the same figure.

Creating figures with plain R

We produce most of our figures in the lab with R. The advantage of making figures with R is that creation of the figure is tightly integrated with the data analysis process, and that we can script and automate figure creation. The latter point is particularly important for reproducibility; a data file plus associated R script is all that is needed to regenerate the exact published figure.

Below follows an example R script to generate a typical figure. You can use this script as a template to generate similar figures. If you need to place two or more figures next to each other, the simplest way to achieve that with the template script is to make use of the split.screen() function.

require(Hmisc) # for function errbar()

# The data to plot.
mean.zdg <- c( 0.35208113, 0.07153585, -0.04377547, -0.12779811,
    -0.25646981, -0.18000377, -0.17827170, 0.03797358, -0.10975094,
     0.04821887, 0.03103208, 0.12747170, 0.07016604 ) # means
se.zdg <- c( 0.1192534, 0.1421630, 0.1408142, 0.1497453, 0.1508856,
     0.1492282, 0.1563277, 0.1174525, 0.1337940, 0.1261310,
     0.1473556, 0.1263988, 0.1258108 ) # standard errors 
window.start <- c( 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101, 111,
     121 ) # start position of the analysis window (in nucleotides)

# The code to generate the figure. Output file will be "T7_zdg.pdf".
# The option "useDingbats=False" fixes a font problem that some
# open-source pdf readers experience.
pdf( "T7_zdg.pdf", width=4.5, height=4, useDingbats=FALSE )
par( mai=c(0.65, 0.65, 0.1, 0.05), mgp=c(2, 0.5, 0), tck=-0.03 )
plot( window.start, mean.zdg, type= 'l', col='black',
      ylim=c(-0.45, 0.45), axes=FALSE,
      xlab='Window start position (nt)',
errbar( window.start, mean.zdg, mean.zdg+se.zdg, mean.zdg-se.zdg,
        add=TRUE, bg='grey60', pch=18, cex=1, xlab='', ylab='' )
abline( h=0, col='grey60', lty=2 )
axis( 1,
      at=c( 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101, 111, 121 ),
      c(1, NA, 21, NA, 41, NA, 61, NA, 81, NA, 101, NA, 121) )
axis( 2,
      at=c(-.4, -.3, -.2, -.1, 0, .1, .2, .3, .4),
      c(-0.4, NA, -0.2, NA, 0, NA, 0.2, NA, 0.4) )
legend( "topright", "Phage T7", pch=c(18), col=c('black'), bty='n' )
Figure created by the example R script.
Figure created by the example R script.

Notes on using R

g <- g + theme_bw() 
g <- g + opts(panel.grid.minor=theme_blank(), panel.grid.major=theme_blank(), panel.background=theme_blank()) 
g <- g + opts(strip.background=theme_blank(), strip.text.y = theme_text())

Creating figures with ggplot2

Below follows an R script to generate a multivariate figure in R with ggplot2. It demonstrates a few of the points in the previous section.

#Uncomment to install these packages if they are not already installed.

# Load ggplot2 

# Load Cairo graphics devices

# This code generates data with 2 independent variables 'a' and 'b' with 2 levels each,
# one dependent variable 'value', And 20 replicates.
a <- c(20, 37)
b <- c(0.50, 0.80)
num.reps <- 20
value <- outer(a, b, "*")
conditions <- expand.grid(a, b)
num.trials <- length(a) * length(b) * num.reps
A <- data.frame(value=rnorm(num.trials, mean=rep(as.vector(value[]),num.trials), sd=2),
                a=conditions[,1], b=conditions[,2])

#Add data to the graph object, the data object should be of class 'data.frame'
g <- ggplot(data=A)

# Add a layer to the ggplot object. geom_density() will produce a kernel density plot 
# of a single variable on the x-axis. aes() determines the mapping of data to the 
# density plot. In this case we map the 'value' variable in the data to the x-axis of 
# the density plot, split the  'value' variable into groups by the interaction of the
# variables 'a' and 'b', and make each group a different color.
g <- g + geom_density(aes(x=value, group=interaction(a,b), 
                      colour=interaction(a, b, sep=" and ")))

# Here we change the color scale to one that will still be visible when printed in 
# black and white and emphasizes the paired nature of the groupings. 
g <- g + scale_colour_manual(name="conditions", 
                             values=RColorBrewer::brewer.pal(4, "Paired"))

# This line changes various aspects of the plot's appearance to be suited for black 
# and white print.
g <- g + theme_bw()

# Now we remove the background grid.
g <- g + opts(panel.grid.minor=theme_blank(), panel.grid.major=theme_blank(), 

# Now we produce an SVG file.
CairoSVG("overlay.svg", width=4.5, height=4)

There are a number of ways to make plots with half-open borders when using ggplot2. You can use a custom theme as this page demonstrates. In some cases, the following standard theme options work as well:

g <- g + opts(panel.border=theme_blank(), axis.line=theme_segment())

This solution can fail when producing graphics with lots of panels; sometimes these options result in some panels having no borders at all, which can be a problem. When all else fails you can can export the graphics as an SVG file and delete or add borders as needed. A hack to quickly delete lots of borders that has been useful to one user in the past is as follows. Place an awk script named 'open-panels.awk' in your working directory. The script should contain lines something like the following lines.

      i = NF - 15
      {for (j = i + 7; j < i +15; j++)
        $(j) = ""

With the awk script in place, you can then use a system call in R to produce an SVG with half-open borders.

system("awk -f open-panels.awk overlay.svg > overlay-open.svg")
Figure created by the example ggplot2 R script and post-processing.
Figure created by the example ggplot2 R script and post-processing.

A figure similar to the previous one could have been made using base graphics in plain R. Using a package like ggplot2 makes it easier to produce a graphic with multiple panels though. Here's an example.

g <- ggplot(data=A) + geom_density(aes(x=value))

# We make a paneled plot with 'a' varying across the rows and 'b' varying across the 
# columns. The 'label_both' value for the labeller option puts both the variable name
# and the variable value into the panel labels. The default is to just put the value 
# into the label. For including expressions in the labels, use 'labeller=label_parsed'. 
g <- g + facet_grid(a~b, labeller=label_both)

g <- g + theme_bw() + opts(panel.grid.minor=theme_blank(), panel.grid.major=theme_blank(),

# This line removes the background boxes from the panel labels and makes the row panel
# labels horizontally oriented.
g <- g + opts(strip.background=theme_blank(), strip.text.y = theme_text())

CairoSVG( "facets.svg", width=6, height=6)
Panelled figure created by the example ggplot2 R script and post-processing.
Panelled figure created by the example ggplot2 R script and post-processing.

This site is hosted on OpenWetWare