Search code examples
rggplot2line-breaksgeom-textplotmath

atop with multiple linebreaks and subscripts in geom_label


I have a dataframe for which I am plotting data using ggplot. My objective is to add an annotation using geom_label, with words that contain subscripts and linebreaks. In particular two linebreaks. Here is a reproducible example:

###DATA###
data_df = data.frame(x=5:11, y = c(rep(0,3),0.4,rep(1,3)))
types = c('A','B','C')
###DATA###

###ANALYSIS###
combo_mat = t(combn(types,2))
list_combo = paste0(combo_mat[,1],'-',combo_mat[,2])

val1_list = c(10,23, 33)
val2_list = c(3,13, 22)
val3_list = c(12,33, 44)

string_lab = paste0('D[',combo_mat,']==',val1_list,
       ' (',val2_list,', ',val3_list,')')

final_string = paste0('atop(',string_lab[1],', atop(',string_lab[2],',',string_lab[3],'))')
data_labels = data.frame(x=6,y=0.75,label = final_string)

ggplot(data_df,aes(x = x, y=y))+
  geom_point()+
  geom_line(linetype='dashed')+
  geom_label(data = data_labels,aes(x=x,y=y,label = label),parse = T, szie = 2)+
  theme_bw()

enter image description here

The problem I encounter is that using atop, two linebraks appear indeed, but with the first line having a larger font size than the other two. How can avoid this change in fontsize and keep the three lines all with the same fontsize and at an equal distance from each other?


Solution

  • One option would be to add your labels individually to your plot via a geom_text and to mimic the geom_label look by adding an empty textbox for which I use ggtext::geom_text_box. Note however, that this approach is a bit hacky and depending on the height of your plot needs some fiddling with the value (I use .05 in the code below) used to "nudge" the labels vertically:

    library(ggplot2)
    
    final_string <- string_lab[1:3]
    data_labels <- data.frame(x = 6, y = 0.75 + .05 * seq(-1, 1, length.out = 3), label = final_string)
    
    h <- max(strheight(scales::label_parse()(final_string), units = "inches"))
    w <- max(strwidth(scales::label_parse()(final_string), units = "inches"))
    
    ggplot(data_df, aes(x = x, y = y)) +
      geom_point() +
      geom_line(linetype = "dashed") +
      ggtext::geom_textbox(
        data = data_labels, 
        aes(x = x, y = .75, label = ""),
        maxwidth = unit(w, "in"),
        minheight = unit(4 * h, "in")
      ) +
      geom_text(data = data_labels, aes(x = x, y = y, label = label), parse = TRUE) +
      theme_bw()
    

    enter image description here