Search code examples
ggplot2axis-labels

Multi-row x-axis labels with breaks in R


I would like to add 2-row x-axis labels on my line plot, but not sure how to also incorporate the continuous labels and breaks I have for my 1st x-axis (Column "CYR" - short for calendar year). I'd like to have the 2nd axis (WYR) start half-way between the first label and the second (WYR = 2010 starts between CYR = 2009 -> 2010). I also wasn't sure how to add 2 x-axis titles either, maybe at the beginning of each x-axis row?

My data:

> dput(wet_pivot)
structure(list(WYR = c("WR_2010", "WR_2011", "WR_2012", "WR_2013", 
"WR_2014", "WR_2015", "WR_2016", "WR_2017", "WR_2018", "WR_2019", 
"WR_2020", "WR_2021", "WR_2022"), CYR = c(2009, 2010, 2011, 2012, 
2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021), Season = structure(c(2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("DRY", 
"WET"), class = "factor"), N = c(59L, 63L, 69L, 70L, 72L, 71L, 
71L, 72L, 71L, 68L, 70L, 48L, 72L), n_mean = c(0.00696806934430411, 
0.000649730847004026, 0.00288256551918419, 0.01141088388474, 
0.000536174103147671, 0.00349584646220785, 0.000482925207291882, 
0.00245359625194744, 0.00292096956686587, 0.00252817293686805, 
0.00196286772014134, 0.00501799463867351, 0.00132244297252478
), n_median = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), sd = c(0.030946706350869, 
0.00248965525641742, 0.0100973832581282, 0.051577934580242, 0.00331468784320076, 
0.0266064084754242, 0.00212505905295283, 0.00675243933898364, 
0.0119729983336735, 0.00639785127193391, 0.00930625647382774, 
0.0136275258272549, 0.00543420856675111), se = c(0.00402891799826298, 
0.000313667078988821, 0.00121558209746373, 0.0061647423020683, 
0.000390639708573979, 0.00315759975690469, 0.000252198110662322, 
0.000795782607691024, 0.00142093348159893, 0.000775853428563995, 
0.00111231039833223, 0.00196696392618855, 0.000640427621321956
)), row.names = c(NA, -13L), class = "data.frame")

My attempt:

years <- seq(2009,2021,1)
labs <- seq(2009,2021,by=1)

myplot <- ggplot(wet_pivot, aes(x = CYR, y = n_mean)) +
  geom_errorbar(aes(ymin=n_mean-se, ymax=n_mean+se), width=.2, color = "black") +
  geom_point(color = "black", shape = 1, size = 2) +
geom_line(color = "black") +
  scale_y_continuous(limits = c(0, 0.04), expand = expansion(mult = c(0, 0.05))) +
  scale_x_continuous(breaks= years, labels = labs)

myplot +
annotate(geom = "text",
             x = 1:nrow(wet_pivot),
             y = min(wet_pivot$n_mean),
             label = labs,
             vjust = 3.5) +
annotate(geom = "text",
             x = 1:nrow(wet_pivot),
             y = min(wet_pivot$n_mean),
             label = wet_pivot$WYR,
             vjust = 5)

Solution

  • You indeed can use text annotations to substitute for x-axis labels. A few recommendations:

    • Set y = -Inf to automatically place text as bottom, independent of whatever data is on the plot. vjust can indeed be used to place it further down.
    • You'd need coord_cartesian(clip = "off") to actually show the text.
    • You can place 'titles' with an extra annotation layer, with x = -Inf to place it on the left.

    I used the above for the example below. Maybe the text is still to big, so you could set the 8.8 / .pt to something smaller. (The / .pt translates between mm, which geom_text() uses, to points, which is used in theme)

    library(ggplot2)
    
    # wet_pivot <- structure(...) # omitted for previty
    
    ggplot(wet_pivot, aes(x = CYR, y = n_mean)) +
      geom_errorbar(aes(ymin=n_mean-se, ymax=n_mean+se), width=.2, color = "black") +
      geom_point(color = "black", shape = 1, size = 2) +
      geom_line(color = "black") +
      scale_y_continuous(limits = c(0, 0.04), expand = expansion(mult = c(0, 0.05))) +
      scale_x_continuous(breaks= years, labels = ~ rep("", length(.x))) +
      annotate(geom = "text",
               x = wet_pivot$CYR,
               y = -Inf,
               label = labs, 
               size = 8.8 / .pt,
               vjust = 2.5) +
      annotate(geom = "text",
               x = wet_pivot$CYR,
               y = -Inf,
               label = wet_pivot$WYR, 
               size = 8.8 / .pt,
               vjust = 4) +
      # Titles
      annotate(geom = "text",
               x = -Inf,
               y = -Inf,
               label = c("CYR", "WYR"),
               vjust = c(2.5, 4), hjust = 1,
               size = 8.8 / .pt
               ) +
      coord_cartesian(clip = "off") +
      theme(
        # Make extra space between axis ticks and axis title
        axis.text.x.bottom = element_text(margin = margin(t = 8.8, b = 8.8))
      )
    

    Created on 2022-05-19 by the reprex package (v2.0.1)