Search code examples
rggplot2scientific-notationggpubr

How to print p-value in scientific notation in ggplot


A publisher requires a scientific notation in my plot. plot to be changed

My code (simplified) is as follows:

set.seed(123)
n <- 100
x <- rnorm(n)
y <- 2 * x + rnorm(n, sd = 0.5)  
data <- data.frame(x = x, y = 1.4 * x + rnorm(100, sd = 2))

ggplot(data, aes(x, y)) +
  geom_point() +
  geom_smooth(method = "lm", col = "blue") +
  ggpubr::stat_cor()

I tried:

ggplot(df, aes(x, y)) +
  geom_point() +
  geom_smooth(method = "lm", col = "blue") +
  ggpubr::stat_cor(
    aes(label = paste("R =", ..r.., "\nP =", format.pval(..p.., digits = 2, 
                                                         scientific = TRUE))), parse = TRUE)

ggplot(df, aes(x, y)) +
  geom_point() +
  geom_smooth(method = "lm", col = "blue") +
  ggpubr::stat_cor(
    aes(label = ..r.label..~"\nP ="~format.pval(..p.., digits = 2, 
                                                scientific = TRUE)))

ggplot(df, aes(x, y)) +
  geom_point() +
  geom_smooth(method = "lm", col = "blue") +
  ggpubr::stat_cor(
    aes(label = paste("R =", ..r.., "\nP =", format.pval(..p.., digits = 2, scientific = TRUE)))
    
ggplot(df, aes(x, y)) +
      geom_point() +
      geom_smooth(method = "lm", col = "blue") +
      ggpubr::stat_cor(
        aes(label = paste(..r.label.., "\n", ..p.label..)))
    
    
ggplot(df, aes(x, y)) +
      geom_point() +
      geom_smooth(method = "lm", col = "blue") +
      ggpubr::stat_cor(
        aes(label = paste(..r.label.., "\nP =", format(..p.., scientific = TRUE))))

but none of these works. Or at least how to manually add an annotation with annotate()?

Does anyone know how to do that?


Solution

  • Using the guide in ?plotmath, you could do something like

    ggplot(data, aes(x, y)) +
      geom_point() +
      geom_smooth(method = "lm", col = "blue") +
      ggpubr::stat_cor(
        aes(label = paste("R==", ..r.., "*paste(\";\")~~~p ==",
                          10^(log10(..p..) %% 1), "%*% 10^", 
                          floor(log10(..p..)))))
    

    enter image description here

    If you want to automate this, you could create a little function that separates out the logic for you:

    sci_not <- function(r, pval) {
      a <- 10^(log10(pval) %% 1)
      b <- floor(log10(pval))
      paste0("R == ", round(r, 2), "*paste(\";\")~~~p == ", a, " %*% 10^", b)
    }
    

    Then your plotting code would just be

    ggplot(data, aes(x, y)) +
      geom_point() +
      geom_smooth(method = "lm", col = "blue") +
      ggpubr::stat_cor(aes(label = sci_not(..r.., ..p..)))
    

    And give the same result.