There are a number of ways to make multi-panel figures in R. Probably the easiest and most commonly used method is to set par(mfrow=c(r,c))
to the number of rows (r
) and columns (c
) you would like to use for your figure panels (Note: par(mfcol=c(r,c))
produces the same thing, only it renders the figures by column rather than by row). Other methods include par(fig=c(x1,x2,y1,y2), new=T)
and layout(mat)
, but these will be for another post.
What I found challenging was putting a label in a consistent location on each of the panels. Using the text()
function would be the go-to function for this, but the default coordinate system used in the text()
is the plot’s coordinate system, and you’ll have to set an additional plotting option (par(xpd)
) to plot outside of the figure region.
Since I regularly make multi-panel figures, I decided to write a wrapper function around text()
that can easily and consistently place a label on a generated plot without having to worry about plotting coordinates. Below is the function (Note: You can find the code and an example of its usage on bitbucket https://bitbucket.org/ggg121/r_figure_letter.git)
put.fig.letter <- function(label, location="topleft", x=NULL, y=NULL, offset=c(0, 0), ...) { if(length(label) > 1) { warning("length(label) > 1, using label[1]") } if(is.null(x) | is.null(y)) { coords <- switch(location, topleft = c(0.015,0.98), topcenter = c(0.5525,0.98), topright = c(0.985, 0.98), bottomleft = c(0.015, 0.02), bottomcenter = c(0.5525, 0.02), bottomright = c(0.985, 0.02), c(0.015, 0.98) ) } else { coords <- c(x,y) } this.x <- grconvertX(coords[1] + offset[1], from="nfc", to="user") this.y <- grconvertY(coords[2] + offset[2], from="nfc", to="user") text(labels=label[1], x=this.x, y=this.y, xpd=T, ...) }
Simply source the code at the start of your R script and you’re good to go. For convenience, the wrapper function allows you to use text-based locations for common figure-label locations akin to the keyword functionality in the legend()
function. Also, additional parameters can be passed to text()
through this function. Below is an example.
# Source the legend function file source("put_fig_letter.r") # Set the seed set.seed(1234) # Generate a data point to plot x <- matrix(rnorm(60), ncol=6) y <- matrix(rnorm(60), ncol=6) # Apply a random scale to each column x <- apply(x, 2, function(x) x*runif(1)*10) y <- apply(y, 2, function(x) x*runif(1)*10) # Setup multiple plot regions par(mfrow=c(2,3), mar=c(5,4,1.5,1)+0.1) # You can feed an (x,y) location to put the figure # letter if you like, or you can use a predefined # location by name kind of like legend() my.locations <- c("topleft", "topcenter", "topright", "bottomleft", "bottomcenter", "bottomright") # Make the plots and append a figure letter to each # Note: put.fig.letter() sends additional parameters to # the text() function. for(i in 1:6) { plot(x[,i], y[,i], pch=16, xlab="x", ylab="y") my.label <- paste(letters[i], ".", sep="") put.fig.letter(label=my.label, location=my.locations[i], font=2) }
And here’s the resulting figure: