Search code examples
rggplot2textannotationsaxis-labels

Adding customized axis label to faceted ggplot


I am trying to add a text element with further information on the x-axis (once) on the left side of my x-axis text of a faceted ggplot (not repeat it every facet):

enter image description here

I failed until now having tried several approaches:

  • geom_text (appears within the plot)
  • annotating function (appears within the plot in every facet)
  • axis.title.x (can't customize the position as desired, namely x=- 1 and y=-1 more or less)
  • mtext (not suitable for ggplot)

My code:

#1.1 create labels for x-axis:
cfutypes_labels <- c("native\n-\n-", "native\n-\n+",
                     "aliquot\n-\n-", "aliquot\n-\n+",
                     "aliquot\n+\n-", "aliquot\n+\n+")

names(cfutypes_labels) <- c("no.0.native", "yes.0.native", 
                            "no.0.aliquot","yes.0.aliquot", 
                            "no.20.aliquot", "yes.20.aliquot")

extra_axis <- c("storagetype\nglycerol\nfreeze-thaw-cycle")

#1.2 plotting

plot_t1calc1 <- thawcycles_long %>%
  filter(dilution_potency<5,
         count >0, cfutype =="cfuperml") %>%
  ggplot(aes(x=interaction(thawcycle,
                           glycerol_content,
                           storagetype), 
             y=count,
             color=interaction(thawcycle,
                               glycerol_content,
                               storagetype))) +
  geom_jitter(width=0.2,
              alpha=0.8,
              show.legend = FALSE)+
  stat_summary(geom = "crossbar",
               fun = "geometric.mean",
               width = 0.3,
               show.legend = FALSE)+
  scale_y_log10(breaks = trans_breaks("log10", function(x) 10^(x+1)),
                labels = trans_format("log10", math_format(10^.x))) +
  scale_x_discrete(labels = cfutypes_labels)+
  ylab("CFU per mL") + 
  xlab("")+
  facet_grid(~timepoint,
             scales="free_x",
             space="free")+
  theme_minimal()+
  theme(panel.background = element_rect(fill = "white"),
      #  axis.title.x = element_text(hjust = -0.5, 
       #                             vjust= 0.9,
        #                            size=9),
        axis.line = element_line(color="black",
                                 size=0.2),
        strip.text = element_text(face="bold"))

A tibble of my dataset:

> tibble(thawcycles_long)
# A tibble: 567 x 9
     sid timepoint storagetype thawcycle glycerol_content dilution_potency cfutype       dotnumber    count
   <dbl> <chr>     <chr>       <chr>                <dbl>            <dbl> <chr>         <chr>        <dbl>
 1     4 t0        native      no                       0                3 dill1_cfu     1              104
 2     4 t0        native      no                       0                3 dill1_cfu     2               83
 3     4 t0        native      no                       0                3 dill1_cfu     3              106
 4     4 t0        native      no                       0                3 cfuperml      1         10400000
 5     4 t0        native      no                       0                3 cfuperml      2          8300000
 6     4 t0        native      no                       0                3 cfuperml      3         10600000
 7     4 t0        native      no                       0                3 auxv_cfuperml 1         10400000
 8     4 t0        native      no                       0                3 auxv_cfuperml 2          8300000
 9     4 t0        native      no                       0                3 auxv_cfuperml 3         10600000
10     4 t0        native      no                       0                4 dill1_cfu     1                7

Does anybody have an idea how to fix this? Many thanks in advance!


Solution

  • One option would be to make use of geom_text like so:

    Important is to add coord_cartesian(clip = "off", ylim = c(1, NA)) to fix the y scale and to prevent the label from being clipped off.

    Additionally you have to make some space for the label which I did by increasing the plot margins.

    extra_axis <- c("storagetype\nglycerol\nfreeze-thaw-cycle")
    
    library(ggplot2)
    
    ggplot(thawcycles_long, aes(x = var, y = count, color = var)) +
      geom_jitter(width = 0.2, alpha = 0.8, show.legend = FALSE) +
      scale_x_discrete(labels = cfutypes_labels) +
      scale_y_log10(breaks = scales::trans_breaks("log10", function(x) 10^(x+1)),
                    labels = scales::trans_format("log10", scales::math_format(10^.x))) +
      labs(y = "CFU per mL", x = NULL) +
      facet_grid(~timepoint, scales = "free_x",  space = "free") +
      theme_minimal() +
      theme(
        panel.background = element_rect(fill = "white"),
        axis.line = element_line(color = "black",size = 0.2),
        strip.text = element_text(face = "bold"),
        plot.margin = margin(5.5, 5.5, 16.5, 55, unit = "pt")
      ) +
      geom_text(data = data.frame(timepoint = "t0"), aes(label = extra_axis), x = -1, y = -.1, 
                inherit.aes = FALSE, color = "red", hjust = .5, vjust = 1, size = 8 / .pt) +
      coord_cartesian(clip = "off", ylim = c(1, NA))
    

    DATA

    set.seed(42)
    
    thawcycles_long <- data.frame(
      thawcycle = sample(c("yes", "no"), 20, replace = TRUE),
      glycerol_content = sample(c(0, 20), 20, replace = TRUE),
      storagetype = sample(c("native", "aliquot"), 20, replace = TRUE),
      count = 1:20,
      timepoint = sample(c("t0", "t1"), 20, replace = TRUE)
    )
    thawcycles_long$var <- interaction(
      thawcycles_long$thawcycle,
      thawcycles_long$glycerol_content,
      thawcycles_long$storagetype
    )