Publication quality plots in R

The trend is slowly moving towards interactive plotting and reproducible research with e.g. knitR (which I fully support), but it seems to me that R/ggplot2 is still the best plotting system for static graphics. That said, ggplot’s stock settings leave a lot to be desired, and I usually find myself having to do a lot of tweaking before a plot is ready to be put on paper. Recently, I got around to actually incorporating most of my usual settings into a theme, which I’m making available in case anyone finds it useful.

Let’s take a look at ggplot’s default settings for a few different plots:
A few things to note:

  • The text is too small.
  • A plot should draw the eye to the data, but the dark grey background is so noisy that the data doesn’t pop out the way it should.
  • The grid lines are likewise too noticeable. They draw the eye away from the data.
  • The color is obviously unsuitable for most publications.

The built in


solves several of these problems, but not all of them, so I’ve put together a simple, minimalist black and white theme that produces plots which are more or less publication ready “out of the box”, save for data specific tweaking. There’s really not much too it — we just do away with most of the unnecessary shading and set the text size to something more legible. Unfortunately, plot color is not “theme-able”, so the greyscale has to be set up manually, but that’s easy. This is what it looks like:
The source code:

theme_pub <- function (base_size = 12, base_family = "") {
  theme_grey(base_size = base_size, 
             base_family = base_family) %+replace% 
    theme(# Set text size
          plot.title = element_text(size = 18),
          axis.title.x = element_text(size = 16),
          axis.title.y = element_text(size = 16, 
                                      angle = 90),
          axis.text.x = element_text(size = 14),
          axis.text.y = element_text(size = 14),
          strip.text.x = element_text(size = 15),
          strip.text.y = element_text(size = 15,
                                      angle = -90),
          # Legend text
          legend.title = element_text(size = 15),
          legend.text = element_text(size = 15),
          # Configure lines and axes
          axis.ticks.x = element_line(colour = "black"), 
          axis.ticks.y = element_line(colour = "black"), 
          # Plot background
          panel.background = element_rect(fill = "white"),
          panel.grid.major = element_line(colour = "grey83", 
                                          size = 0.2), 
          panel.grid.minor = element_line(colour = "grey88", 
                                          size = 0.5), 
          # Facet labels        
          legend.key = element_rect(colour = "grey80"), 
          strip.background = element_rect(fill = "grey80", 
                                          colour = "grey50", 
                                          size = 0.2))

With this defined, it's enough to append


to your plot object. For example, a simple histogram in ggplot2 might be made with

data = data.frame(x = rnorm(100))
p = ggplot(data, aes(x = x)) +

to apply the theme, simply define the theme function and write

data = data.frame(x = rnorm(100))
p = ggplot(data, aes(x = x)) +
    geom_histogram() +

Unfortunately, ggplot will still, by default, label different conditions by color, rather than with different shades of grey. To fix this, use one of

scale_fill_grey(start = 0, end = .9)
scale_color_grey(start = 0, end = .9)

depending on your plot.