15

I'm interested in trying to create simple corner labels for a multipanel figure I am preparing in ggplot. This is similar to this previously asked question, but the answers only explained how to include a label at the top of the plot, not produce a corner label in the format required by many journals. I hope to replicate something similar to the plotrix function corner.label() in ggplot2.

Here is an example using plottrix of what I would like to recreate in ggplot2.

require(plotrix)

foo1<-rnorm(50,25,5)
foo2<-rpois(50,25)
foo3<-rbinom(50,25,0.5)
foo4<-rnbinom(50,25,0.5)

par(mfrow=c(2,2))
hist(foo1)
corner.label(label='a',figcorner=T)
hist(foo2)
corner.label(label='b',figcorner=T)
hist(foo3)
corner.label(label='c',figcorner=T)
hist(foo4)
corner.label(label='d',figcorner=T)

This produces the following:

enter image description here

Thanks for any help in advance!

Henrik
  • 65,555
  • 14
  • 143
  • 159
Thraupidae
  • 665
  • 2
  • 5
  • 14
  • Can you clarify what exactly the labeling should look like? Do you just need the facet labels all shoved to the left? Or do you need to remove the facet label ribbons entirely? – joran Jul 10 '13 at 16:51
  • I just need to justify the labels to the upper-left-hand corner of each panel. I'm not sure what you mean by removing the facet label ribbons.. – Thraupidae Jul 10 '13 at 16:52
  • Ok, then see `?theme` and set the hjust for `strip.text`. – joran Jul 10 '13 at 16:53

4 Answers4

21

Two recent changes have made this a lot easier:

  • The latest release of ggplot2 has added the tag caption which can be used to label subplots.
  • The package patchwork makes it really easy to plot multiple ggplot objects. https://github.com/thomasp85/patchwork

This means that no altering of grobs is required. Adapting the reproducible example provided by Kev:

library(ggplot2)
# install.package("patchwork")
library(patchwork)

a <- 1:20
b <- sample(a, 20)
c <- sample(b, 20)
d <- sample(c, 20)
mydata   <- data.frame(a, b, c, d)

myplot1  <- ggplot(mydata, aes(x=a, y=b)) + geom_point() + labs(tag = "A")
myplot2  <- ggplot(mydata, aes(x=b, y=c)) + geom_point() + labs(tag = "B")
myplot3  <- ggplot(mydata, aes(x=c, y=d)) + geom_point() + labs(tag = "C")
myplot4  <- ggplot(mydata, aes(x=d, y=a)) + geom_point() + labs(tag = "D")

myplot1 + myplot2 + myplot3 + myplot4

enter image description here

Extension: Changing Style:

If you want to change the labelling style, you can either set this individually for each plot or set a theme default. I would recommend the second approach. Add the following line before you build your plots to make the font bold and blue

ggplot2::theme_update(plot.tag = element_text(face = "bold", colour = "blue"))

For more information on customising the theme of ggplot2, see here.

Michael Harper
  • 14,721
  • 2
  • 60
  • 84
13

I had the same problem and came up with the following solution, which is a bit different:

loading r packages

library(ggplot2)
library(grid)
library(gridExtra)

example data

a <- 1:20
b <- sample(a, 20)
c <- sample(b, 20)
d <- sample(c, 20)

create a data frame

mydata   <- data.frame(a, b, c, d)

create example plots

myplot1  <- ggplot(mydata, aes(x=a, y=b)) + geom_point()
myplot2  <- ggplot(mydata, aes(x=b, y=c)) + geom_point()
myplot3  <- ggplot(mydata, aes(x=c, y=d)) + geom_point()
myplot4  <- ggplot(mydata, aes(x=d, y=a)) + geom_point()

set corner labels

myplot1 <- arrangeGrob(myplot1, top = textGrob("A", x = unit(0, "npc")
         , y   = unit(1, "npc"), just=c("left","top"),
         gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))

myplot2 <- arrangeGrob(myplot2, top = textGrob("B", x = unit(0, "npc")
         , y = unit(1, "npc"), just=c("left","top"),
         gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))

myplot3 <- arrangeGrob(myplot3, top = textGrob("C", x = unit(0, "npc")
        , y  = unit(1, "npc"), just=c("left","top"),
        gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))

myplot4 <- arrangeGrob(myplot4, top = textGrob("D", x = unit(0, "npc")
        , y = unit(1, "npc"), just=c("left","top"),
        gp=gpar(col="black",    fontsize=18, fontfamily="Times Roman")))

plotting all plots on one page

grid.arrange(myplot1, myplot2, myplot3, myplot4, ncol = 2)

corner label

Kev
  • 425
  • 3
  • 8
  • 1
    This is great. This is much simpler and more generally applicable and easier to implement than the accepted solution IMO. Thanks! – DeanAttali Nov 16 '15 at 12:38
6

An example:

d <- data.frame(x = runif(16),
                y = runif(16),
                grp = rep(letters[1:4],each = 4))

ggplot(d,aes(x = x,y = y)) + 
facet_wrap(~grp) + 
geom_point() + 
theme(strip.text = element_text(hjust = -0.05),
      strip.background = element_blank())

enter image description here

joran
  • 169,992
  • 32
  • 429
  • 468
  • Is there any way to have the labels outside the plot/axes region? Similar to the 'figcorner=T' option in corner.label()? – Thraupidae Jul 10 '13 at 16:58
  • @Thraupidae You can set the `hjust` to be negative, but then b and d will drift into the other panels. – joran Jul 10 '13 at 16:59
  • @Thraupidae See my edit. I think that's closer to what you're after. (And should explain why I asked about the facet ribbons.) – joran Jul 10 '13 at 17:03
  • OK and to prevent the drifting into other panels I suppose you just have to mess with the spacing using plot.margin? – Thraupidae Jul 10 '13 at 17:03
  • Ah, yes that looks very close to what I was hoping with the facet ribbons removed. Thanks! – Thraupidae Jul 10 '13 at 17:06
1

Here's a solution using a custom labeller function. This doesn't invovle any manipulations to the data. Currently it only works with 1-dimensional facets (facet_wrap). I'm still working on how to increment along a 2-D grid...

  1. Define the labeller function

    make_labelstring <- function(mypanels) {
      mylabels <- sapply(mypanels, 
                         function(x) {LETTERS[which(mypanels == x)]})
    
      return(mylabels)
    }
    
    label_panels <- ggplot2::as_labeller(make_labelstring)
    
  2. Pass label_panels as the labeller to facet_wrap

    library(ggplot2)
    data("diamonds")
    
    # create a faceted plot
    ggplot(data = diamonds, aes(x = depth, y = price)) +
      geom_point() +
      facet_wrap(~cut, labeller = label_panels) +
      theme(strip.text = element_text(hjust = -0),
            strip.background = element_blank())
    
DonJ
  • 923
  • 11
  • 18