1

I'm trying to figure out how to add a nice R^2 = value to each subplot.

Right now I am able to add the value (from a separate dataframe) I want on the plot, but I don't know how to add an "R^2 =" preceding it that is italicized and superscripted.

Any advice appreciated. Thank you for your time!

example_df <- data.frame(x = c(1,2,5,7,8,9,10),
                         y = c(1,3,5,7,8, 9, 10),
                         grp = c("a", "a", "b","b","b", "c", "c"))

grp_info <- data.frame( grp = c("a", "b", "c"),
                        num = c(0.5, 0.75, 1))
  
plt <- ggplot(example_df, aes(x = x, y=y, group = grp)) +
  geom_point() + 
  facet_wrap(vars(grp), ncol = 2, scales = "free")+
  annotate(geom = "text", x = -Inf, y = Inf, label = grp_info$num, hjust = 0, vjust =1)

print(plt)

If I wanted just the "R^2 = " formatted nicely, then the following works, but it doesn't allow me to add a value from a separate dataframe.

plt <- ggplot(example_df, aes(x = x, y=y, group = grp)) +
  geom_point() + 
  facet_wrap(vars(grp), ncol = 2, scales = "free")+
  annotate(geom = "text", x = -Inf, y = Inf, label = paste("paste(italic(R) ^ 2,\"=\")"), parse = TRUE, hjust = 0, vjust =1)

The final point I belatedly raised in the comments was that ideally this addition would be multiline, allowing addition of another variable expression.

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
cds
  • 13
  • 4
  • Check out `ggpubr::stat_regline_equation` – Dan Adams Mar 24 '21 at 02:38
  • Sorry, I think it's `stat_cor` you want – Dan Adams Mar 24 '21 at 03:14
  • Thanks that's helpful - but if I wanted it to be the general case (not just R^2 or p) I'm wondering if there's a straightforward way to just supply my own computed variable – cds Mar 24 '21 at 03:47
  • 1
    Fair nuff. If you're doing the same formatting for each, you could use this: https://stackoverflow.com/a/47836541/13210554 – Dan Adams Mar 24 '21 at 04:08
  • 1
    Also, another approach to the formatting is with `expression` which might have some advantages. See https://stackoverflow.com/a/32465628/13210554 – Dan Adams Mar 24 '21 at 04:09
  • Thanks - I'd actually looked the first link there and just couldn't figure out how to get the italicized formatting in!! – cds Mar 24 '21 at 18:56

2 Answers2

1

I think it would work best to assign your annotations as a geom_text call - this does the same thing as annotate in some ways, but will keep in sync with your facet_wrap call:

library(ggplot2)

example_df <- data.frame(
  x = c(1, 2, 5, 7, 8, 9, 10),
  y = c(1, 3, 5, 7, 8, 9, 10),
  grp = c("a", "a", "b", "b", "b", "c", "c")
)

grp_info <- data.frame(grp = c("a", "b", "c"),
                       num = c(0.5, 0.75, 1))

ggplot(example_df, aes(x = x, y = y, group = grp)) +
  geom_point() +
  facet_wrap(vars(grp), ncol = 2, scales = "free") +
  geom_text(
    data = grp_info,
    aes(
      x = -Inf,
      y = Inf,
      label = paste0("italic(R)^2", "==", num)
    ),
    parse = TRUE,
    hjust = 0,
    vjust = 1
  )

Created on 2021-03-24 by the reprex package (v1.0.0)

Andy Baxter
  • 5,833
  • 1
  • 8
  • 22
  • Thanks so much! I've been playing around with this solution - I'm getting hung up around the parse on top of the paste output. Do you have any suggestions about how to have an "RMSE = " below the R^2? The newline character is freaking out the parser and I don't have enough of an intuition to figure out why. – cds Mar 24 '21 at 18:58
  • Check out `plotmath::atop` described [here](https://stackoverflow.com/questions/18237134/line-break-in-expression) – Dan Adams Mar 24 '21 at 19:15
  • it's ugly but `label = paste0("atop(", "italic(R)^2", "==", num,",", "RMSE = )")` works – Dan Adams Mar 24 '21 at 19:16
  • Haha I don't mind ugly at all - and it runs, but the RMSE doesn't show up! also `label =` doesn't take the output of expression? – cds Mar 24 '21 at 21:22
  • Oh, sorry, I messed it up... try `label = paste0("atop(", "italic(R)^2", "==", num,",", "RMSE)")` but you'll have to modify it to add the = and whatever value you want. But that's the general structure. – Dan Adams Mar 24 '21 at 22:57
  • Just added an answer with the full implementation of this. – Dan Adams Mar 25 '21 at 12:22
0

You can use plotmath::atop, described here, to get a line break in the expression that parses. It's a pretty messy construction, but it works. Here's an example:

library(tidyverse)

example_df <- data.frame(
  x = c(1, 2, 5, 7, 8, 9, 10),
  y = c(1, 3, 5, 7, 8, 9, 10),
  grp = c("a", "a", "b", "b", "b", "c", "c")
)

grp_info <- data.frame(grp = c("a", "b", "c"),
                       num = c(0.5, 0.75, 1),
                       rmse = c(4, 5, 6))

ggplot(example_df, aes(x = x, y = y, group = grp)) +
  geom_point() +
  facet_wrap(vars(grp), ncol = 2, scales = "free") +
  geom_text(
    data = grp_info,
    aes(
      x = -Inf,
      y = Inf,
      label = paste0("atop(", "italic(R)^2", "==", num,",", "RMSE", "==", rmse, ")")
    ),
    parse = TRUE,
    hjust = 0,
    vjust = 1
  )

Created on 2021-03-25 by the reprex package (v1.0.0)

Dan Adams
  • 4,971
  • 9
  • 28
  • Thanks Dan! This worked well for me and now I have a great tool to use. I appreciate your help! – cds Mar 25 '21 at 19:16
  • Glad it helped, I learned something too. You might want to update your question to record for posterity the additional point raised in the comments about multi-line expressions. – Dan Adams Mar 25 '21 at 21:47