Common main title of a figure panel compiled with par(mfrow)

88,403

Solution 1

This should work, but you'll need to play around with the line argument to get it just right:

par(mfrow = c(2, 2))
plot(iris$Petal.Length, iris$Petal.Width)
plot(iris$Sepal.Length, iris$Petal.Width)
plot(iris$Sepal.Width, iris$Petal.Width)
plot(iris$Sepal.Length, iris$Petal.Width)
mtext("My 'Title' in a strange place", side = 3, line = -21, outer = TRUE)

enter image description here

mtext stands for "margin text". side = 3 says to place it in the "top" margin. line = -21 says to offset the placement by 21 lines. outer = TRUE says it's OK to use the outer-margin area.

To add another "title" at the top, you can add it using, say, mtext("My 'Title' in a strange place", side = 3, line = -2, outer = TRUE)

Solution 2

You can use the function layout() and set two plotting regions which occurs in both columns (see the repeating numbers 1 and 3 in the matrix()). Then I used plot.new() and text() to set titles. You can play with margins and heights to get better representation.

x<-1:10
par(mar=c(2.5,2.5,1,1))
layout(matrix(c(1,2,3,4,1,5,3,6),ncol=2),heights=c(1,3,1,3))
plot.new()
text(0.5,0.5,"First title",cex=2,font=2)
plot(x)
plot.new()
text(0.5,0.5,"Second title",cex=2,font=2)
hist(x)
boxplot(x)
barplot(x)

enter image description here

Solution 3

The same but in bold can be done using title(...) with the same arguments as above:

title("My 'Title' in a strange place", line = -21, outer = TRUE)

Solution 4

Here's another way to do it, using the line2user function from this post.

par(mfrow = c(2, 2))
plot(runif(100))
plot(runif(100))
text(line2user(line=mean(par('mar')[c(2, 4)]), side=2), 
     line2user(line=2, side=3), 'First title', xpd=NA, cex=2, font=2)

plot(runif(100))
plot(runif(100))
text(line2user(line=mean(par('mar')[c(2, 4)]), side=2), 
     line2user(line=2, side=3), 'Second title', xpd=NA, cex=2, font=2)

centered_titles

Here, the title is positioned 2 lines higher than the upper edge of the plot, as indicated by line2user(2, 3). We centre it by offsetting it with respect to the 2nd and 4th plots, by half of the combined width of the left and right margins, i.e. mean(par('mar')[c(2, 4)]).


line2user expresses an offset (number of lines) from an axis in user coordinates, and is defined as:

line2user <- function(line, side) {
  lh <- par('cin')[2] * par('cex') * par('lheight')
  x_off <- diff(grconvertX(0:1, 'inches', 'user'))
  y_off <- diff(grconvertY(0:1, 'inches', 'user'))
  switch(side,
         `1` = par('usr')[3] - line * y_off * lh,
         `2` = par('usr')[1] - line * x_off * lh,
         `3` = par('usr')[4] + line * y_off * lh,
         `4` = par('usr')[2] + line * x_off * lh,
         stop("side must be 1, 2, 3, or 4", call.=FALSE))
}
Share:
88,403
ECII
Author by

ECII

Updated on October 15, 2021

Comments

  • ECII
    ECII over 2 years

    I have a compilation of 4 plots drawn together with par(mfrow=c(2,2)). I would like to draw a common title for the 2 above plots and a common title for the 2 below panels that are centered between the 2 left and right plots.

    Is this possible?

  • ECII
    ECII over 11 years
    Fantastic. Thank you. I didn't know that mtext can use negative values.
  • A5C1D2H2I1M1N2O1R2T1
    A5C1D2H2I1M1N2O1R2T1 over 11 years
    You get my vote here. I think layout is definitely the way to go, but wanted to show the mtext option too.
  • A5C1D2H2I1M1N2O1R2T1
    A5C1D2H2I1M1N2O1R2T1 over 11 years
    @ECII, No problem. In general, though, I would think that you would approach this using layout, as demonstrated in @Didzis's answer.
  • Skiptoniam
    Skiptoniam over 6 years
    Nice one @jbaums