0

I am creating a plot using ggplot::facet_wrap() and I wonder how to automatically add numbers/letters to the label/title of each panel?

gridExtra and complot solutions are not what I am looking for. It is more related to this SO post: https://stackoverflow.com/a/52217208/10264278, especially the alternative using the stickylabeller package. This package could be perfect but it seems not maintained anymore (I get package ‘stickylabeller’ is not available for this version of R message when loading it, R version 4.0.5 (2021-03-31)).

Is it possible to acheive something similar to stickylabeller::label_glue() with labeller() function? Ideally I would like to avoid editting my data prior to the plotting process. Reason for that is I would like to be able to quickly change the labels e.g. switch from (a), (b) to 1., 2..

What I get:

library(ggplot2)

ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_wrap(. ~ am) +
  theme_bw(base_size = 12)

Here is the expected output (without the am = is fine):

enter image description here

Paul
  • 2,850
  • 1
  • 12
  • 37

2 Answers2

1

Start by defining a look-up of the labels, and then call in the facet_wrap() statement as here:

library(ggplot2)

levels <- sort(unique(mtcars$am))
labels <- c(glue::glue("({LETTERS[levels+1]}) am = {levels}", collapse = ""))
names(labels) <- levels

ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_wrap(. ~ am, labeller = labeller(am = labels)) +
  theme_bw(base_size = 12)

enter image description here

It is also possible to make custom labelling function that can be more flexible although they might produce unexpected outputs in other cases, they seems enough here:

letters_lab <- function(x){glue::glue("({letters[factor(x)]}) {x}")}
number_lab <- function(x){glue::glue("({as.integer(factor(x))}) {x}")}

library(ggplot2)
ggplot(data = iris) +
  facet_grid(.~Species, labeller = labeller(Species = number_lab))

ggplot(data = iris) +
  facet_grid(.~Species, labeller = labeller(Species = letters_lab))

ggplot(mtcars, aes(qsec, mpg)) + 
  facet_wrap(. ~ am, labeller = labeller(am = letters_lab))

Paul
  • 2,850
  • 1
  • 12
  • 37
Tech Commodities
  • 1,884
  • 6
  • 13
  • Thanks for your answer, it works but I am looking for something that does not require to create that lookup table. The reason is that, if you change variables used for facetting, you will have to make another lookup table wich is, sometimes very long :p – Paul Sep 17 '21 at 06:08
  • However, I guess it is possible to create a function that makes it easier to edit those labels. – Paul Sep 17 '21 at 06:11
  • 1
    That makes sense. Dynamic table isn't too difficult, but requires a little `glueing`. I've updated my solution. The stickylabeller looks goods. I'd not come across it before. – Tech Commodities Sep 17 '21 at 09:36
  • 1
    I was able to make the expected output but changing very little of your code with the `glue::glue()` functions. To make it re-usable across plots, I made more general functions like `letters_lab <- function(x){glue::glue("({letters[factor(x)]}) {x}")}` or `number_lab <- function(x){glue::glue("({as.integer(factor(x))}) {x}")}` and used them like so `facet_grid(.~Species, labeller = labeller(Species = number_lab))`. – Paul Sep 17 '21 at 12:29
  • Nice. I'm always pleased to find better ways of doing things. – Tech Commodities Sep 17 '21 at 14:10
1

in case you want to use stickylabeller, you still can by using the github version.

devtools::install_github("rensa/stickylabeller")
library(ggplot2)

ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_wrap(. ~ am, labeller = stickylabeller::label_glue('({.n}) am = {am}')) +
  theme_bw(base_size = 12) 

enter image description here

mnist
  • 6,571
  • 1
  • 18
  • 41
  • Ooooh what a nice trick! I did not know about this possibility. I'll use this until we find something that does not rely on a (not so) old package :) Many thanks! – Paul Sep 17 '21 at 06:10