rggplot2plotmath

Using paste() and formatC() together in plot label in R


I want to use a subscript and a number in a geom_text() layer of a ggplot2 plot. The number will come from an indexed dataframe so that I can use it in a flexible way within a custom function, but here is a simpler reproducible example:

temp_line <- structure(list(x = c(670.892544634835, 670.94367492675, 670.994805218665, 
671.04593551058, 671.097065802495, 671.14819609441, 671.199326386325, 
671.25045667824, 671.301586970155, 671.35271726207, 671.403847553985, 
671.4549778459, 671.506108137815, 671.55723842973, 671.608368721645, 
671.65949901356, 671.710629305475, 671.76175959739, 671.812889889305, 
671.86402018122, 671.915150473135, 671.96628076505, 672.017411056965, 
672.06854134888, 672.119671640795, 672.17080193271, 672.221932224625, 
672.27306251654, 672.324192808455, 672.37532310037, 672.426453392285, 
672.4775836842, 672.528713976115, 672.57984426803, 672.630974559945, 
672.68210485186), y = c(0.985240554809607, 0.982213133032921, 
0.986693753084667, 0.987366974516756, 0.987636649598203, 0.982056033377924, 
0.980484643703154, 0.983029322815495, 0.988833379596215, 0.983723421126925, 
0.984861430761356, 0.975375941059582, 0.973793277004997, 0.974896425651856, 
0.976215113076567, 0.980190883847887, 0.97234555785344, 0.976564419204803, 
0.971411825270084, 0.958092987035761, 0.948933680537213, 0.944433555718954, 
0.955207036644352, 0.966236032356096, 0.97461001903587, 0.982502838158965, 
0.977806030386617, 0.980102357820749, 0.971970360584438, 0.972510182292617, 
0.971868273995148, 0.986332867356837, 0.992939055558675, 1, 0.990384208442822, 
0.987140151281311)), class = "data.frame", row.names = c(NA, 
-36L))

temp <- structure(list(x = 671.96628076505, y = 0.943555524955473), class = "data.frame", row.names = "window_mins")

temp_num <- c(window_mins = 0.000878030763480352)


# Attempt at plotting equation using paste()
  ggplot() +
    geom_line(data = temp_line, 
              aes(x = x, y = y), alpha = 0.85, size = 0.6) +
    geom_point(data = temp,
               aes(x = x, y = y), alpha = 0.85, size = 1.5, shape = 15) +
    geom_text(data = temp,
              aes(x = x, y = y),
              label = paste("L1 - L[tot] = ", 
                                       formatC(temp_num, 
                                               format = "e", digits = 3)),
              nudge_x = -0.45,
              show.legend = FALSE)

The challenge is using paste() in a way that works for both the subscript and the formatted number. I tried using expression() and paste() together. This creates the correct subscript, but unfortunately prints the command and arguments for formatC() instead of evaluating to produce the number:

label = expression(paste("L1 - ", L[tot], "= ", 
                                       formatC(temp_num, 
                                               format = "e", digits = 3)))

I tried the above but wrapping the formatC command in eval() but I couldn't get that to work. I also played around with wrapping the whole expression in parse() and substitute() based on the links below. What am I missing to generate both a subscript and a formatted number within a paste() command?

Related posts I looked at: Combining paste() and expression() functions in plot labels

https://community.rstudio.com/t/use-bquote-in-ggplot2-for-subscript-text/40882

R - how to combine expression(), paste() and formatC() commands for one legend element?


Solution

  • OK, this was surprisingly tricky.

    First of all, you need to study help("plotmath"). Then, I would pass a character string and let ggplot2 parse it. If we do that, the RHS of the equation should be specified as a character string, otherwise standard print formatting will be applied within plotmath. I prefer sprintf for convenience but if you insist you can construct the same character string with a combination of paste and formatC.

    #note the single quotes within the string
    sprintf("L1 - L[tot] == '%.3e'", temp_num)
    #[1] "L1 - L[tot] == '8.780e-04'"
    
    ggplot() +
      geom_line(data = temp_line, 
                aes(x = x, y = y), alpha = 0.85, size = 0.6) +
      geom_point(data = temp,
                 aes(x = x, y = y), alpha = 0.85, size = 1.5, shape = 15) +
      geom_text(data = temp,
                aes(x = x, y = y),
                label = sprintf("L1 - L[tot] == '%.3e'", temp_num),
                nudge_x = -0.45,
                show.legend = FALSE,
                parse = TRUE)
    

    resulting plot showing the correct text label