Search code examples
rggplot2labelsymbolssuperscript

how can I use math expressions in ggplot2 facet labels


In the following plot, I would like to replace "d" by delta, include a per mil symbol at the end, and use superscripts in: d13C, d15N and d34S.I got it when I use a biplot (e.g. plot + ylab(expression(paste(delta^{15}, "N (\u2030)")))). However, in the attached plot, I'm using facet_grid, which may change the way to get it. Here is the script used:

group.violin<-ggplot(group.data, aes(x=Culture2, group = Culture2, y=value)) +
  stat_summary(aes(x = Culture2, y = value, color= Species, group = Species), fun = "mean", 
               geom = "line", lwd = 2, alpha = 0.5)+
  stat_summary(geom="point")+
  geom_violin(aes(x = Culture2, y = value, fill = Species), alpha = 0.4, color = NA)+
  geom_point(aes(x = Culture2, y = value, fill = Species), size = 3, color = "black", pch = 21,
             position = position_jitter(width = 0.05, seed = 12))+
  facet_grid(variable ~ Species, scales = "free_y") +
  xlab("")+ 
  ylab("")+
  theme_classic()+
  theme(strip.background = element_rect(colour = "black", fill = "grey85", size = 0.1),
        panel.border=element_rect(colour="black",size = 0.1, fill = NA),
        panel.spacing = unit(0.3, "lines"),
        axis.text.y = element_text(size = 12, colour = "black"),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        legend.position = "bottom",
        legend.text=element_text(size=12, face="italic"),
        legend.title=element_text(size=12,face="bold"),
        strip.text.x=element_text(size=12,face="bold.italic"),
        strip.text.y=element_text(size=12,face="bold"))

Thank you enter image description here

enter image description here


Solution

  • We can use sub to change your variable to be the labels you expect, then add labeller=label_parsed to the call to facet_grid.

    Using my sample data (below), original plotting code:

    original plot with no plotmath facet labels

    group.data |>
      transform(
        variable2 = sub("d([0-9]+)(.*)", "delta^{\\1}*'\\2 (\u2030)'", variable)
      ) |> 
      ggplot(aes(x=Culture2, group = Culture2, y=value)) +
      stat_summary(aes(x = Culture2, y = value, color= Species, group = Species), fun = "mean", 
                   geom = "line", lwd = 2, alpha = 0.5)+
      stat_summary(geom="point")+
      geom_violin(aes(x = Culture2, y = value, fill = Species), alpha = 0.4, color = NA)+
      geom_point(aes(x = Culture2, y = value, fill = Species), size = 3, color = "black", pch = 21,
                 position = position_jitter(width = 0.05, seed = 12))+
      facet_grid(variable2 ~ Species, scales = "free_y", labeller = label_parsed) +
      xlab("")+ 
      ylab("")+
      theme_classic()+
      theme(strip.background = element_rect(colour = "black", fill = "grey85", size = 0.1),
            panel.border=element_rect(colour="black",size = 0.1, fill = NA),
            panel.spacing = unit(0.3, "lines"),
            axis.text.y = element_text(size = 12, colour = "black"),
            axis.title.x = element_blank(),
            axis.title.y = element_blank(),
            legend.position = "bottom",
            legend.text=element_text(size=12, face="italic"),
            legend.title=element_text(size=12,face="bold"),
            strip.text.x=element_text(size=12,face="bold.italic"),
            strip.text.y=element_text(size=12,face="bold"))
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    # No summary function supplied, defaulting to `mean_se()`
    

    same plot with plotmath facet labels

    Unfortunately, this drops the bold/italic formatting you themed into the facet labels, so we need to be clearer on those. Further, having bold-italic in the facet strips and just italic in the other poses a small problem ... but I'll hack it into place by using plotmath-like "bolditalic(..)" expressions (strings) for everything, and then remove the bold portion of that string for just the legends.

    For this step, we'll transform Species as well, then add scale_colour_discrete and _fill_ hacks using scales::label_parse for the labels= argument.

    group.data |>
      transform(
        variable2 = sub("d([0-9]+)(.*)", "bold(delta^{\\1}*'\\2 (\u2030)')", variable),
        Species = sprintf("bolditalic(%s)", Species)
      ) |> 
      ggplot(aes(x=Culture2, group = Culture2, y=value)) +
      stat_summary(aes(x = Culture2, y = value, color= Species, group = Species), fun = "mean", 
                   geom = "line", lwd = 2, alpha = 0.5)+
      stat_summary(geom="point")+
      geom_violin(aes(x = Culture2, y = value, fill = Species), alpha = 0.4, color = NA)+
      geom_point(aes(x = Culture2, y = value, fill = Species), size = 3, color = "black", pch = 21,
                 position = position_jitter(width = 0.05, seed = 12))+
      facet_grid(variable2 ~ Species, scales = "free_y", labeller = label_parsed) +
      xlab("")+ 
      ylab("")+
      scale_colour_discrete(labels = function(z) scales::label_parse()(sub("bold","",z)))+
      scale_fill_discrete(labels = function(z) scales::label_parse()(sub("bold","",z)))+
      theme_classic()+
      theme(strip.background = element_rect(colour = "black", fill = "grey85", size = 0.1),
            panel.border=element_rect(colour="black",size = 0.1, fill = NA),
            panel.spacing = unit(0.3, "lines"),
            axis.text.y = element_text(size = 12, colour = "black"),
            axis.title.x = element_blank(),
            axis.title.y = element_blank(),
            legend.position = "bottom",
            legend.text=element_text(size=12),
            legend.title=element_text(size=12,face="bold"),
            strip.text.x=element_text(size=12),
            strip.text.y=element_text(size=12))
    

    sample plot with strip labels and facet text fixed


    Sample data:

    set.seed(42)
    n <- 420
    group.data <- data.frame(Culture2 = sample(c("Auri", "Grav"), size=n, replace=TRUE), value=runif(n), Species=sample(c("Bos", "Cerv", "Equus"), size=n, replace=TRUE), variable=sample(c("d13C", "d15N", "d34S"), size=n, replace=TRUE))
    head(group.data)
    #   Culture2      value Species variable
    # 1     Auri 0.11483254   Equus     d15N
    # 2     Auri 0.48275690   Equus     d13C
    # 3     Auri 0.97917358   Equus     d34S
    # 4     Auri 0.81151679     Bos     d13C
    # 5     Grav 0.54291282   Equus     d34S
    # 6     Grav 0.07236709    Cerv     d34S