Multiple plots with subplot in R

September 8, 2011

(This article was first published on 0xCAFEBABE, and kindly contributed to R-bloggers)

I’m in the middle of creating a poster and wanted to compresss the content by transforming some of the charts into subplots of other charts.

I made a little survey and found that there is a TeachingDemos library in CRAN that fits my needs. Well, the parameterization of the functions is a bit tricky but after a few tries you get used to it.

However, there is a minor flaw in the code of version 2.7: when I wanted to use multiple plots on one layout (e.g., next to each other to use a common legend), it always drew the charts into the first plotting area. A bit of Googling helped, my solution is based on this thread on the R-help list since October, 2010. If you manage to install version 2.8, the problem is solved automatically. On the other side, if you want a quick solution, add the following code segment to your script (so it is shadowing the original function definition).

Only change the first 3 lines of the code, leave the other untouched (you can verify it by diffing this code and entering subplot into the R console).

subplot <- function (fun, x, y = NULL, size = c(1, 1), vadj = 0.5, hadj = 0.5,
inset = c(0, 0), type = c("plt", "fig"), pars = NULL)
# Version 2.7 has a minor issue here:
# old.par <- par(no.readonly = TRUE)
# on.exit(par(old.par))
# type <- match.arg(type)
# Change to this in order to solve the issue
type <- match.arg(type)
old.par <- par( c(type, 'usr', names(pars) ) )
# The remaining part is untouched

if (missing(x))
x <- locator(2)
if (is.character(x)) {
if (length(inset) == 1)
inset <- rep(inset, 2)
x.char <- x
tmp <- par("usr")
x <- (tmp[1] + tmp[2])/2
y <- (tmp[3] + tmp[4])/2
if (length(grep("left", x.char, = TRUE))) {
x <- tmp[1] + inset[1] * (tmp[2] - tmp[1])
if (missing(hadj))
hadj <- 0
if (length(grep("right", x.char, = TRUE))) {
x <- tmp[2] - inset[1] * (tmp[2] - tmp[1])
if (missing(hadj))
hadj <- 1
if (length(grep("top", x.char, = TRUE))) {
y <- tmp[4] - inset[2] * (tmp[4] - tmp[3])
if (missing(vadj))
vadj <- 1
if (length(grep("bottom", x.char, = TRUE))) {
y <- tmp[3] + inset[2] * (tmp[4] - tmp[3])
if (missing(vadj))
vadj <- 0
xy <- xy.coords(x, y)
if (length(xy$x) != 2) {
pin <- par("pin")
tmp <- cnvrt.coords(xy$x[1], xy$y[1], "usr")$plt
x <- c(tmp$x - hadj * size[1]/pin[1], tmp$x + (1 - hadj) *
y <- c(tmp$y - vadj * size[2]/pin[2], tmp$y + (1 - vadj) *
xy <- cnvrt.coords(x, y, "plt")$fig
else {
xy <- cnvrt.coords(xy, , "usr")$fig
if (type == "fig") {
par(fig = c(xy$x, xy$y), new = TRUE)
else {
par(plt = c(xy$x, xy$y), new = TRUE)
tmp.par <- par(no.readonly = TRUE)

There is a second workaround suggested in the aforementioned thread, namely managing par('mfg') by hand before and after executing the subplot() function, but it didn’t work for me. The third option (wait a few days until the CRAN packages are updated to 2.8) seems to take a bit longer. :-) Anyway, it is working so I’m happy.

To leave a comment for the author, please follow the link and comment on their blog: 0xCAFEBABE. offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.


Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)