Search code examples
rggplot2ggpmisc

Label ggplot with group names and their equation, possibly with ggpmisc?


I would like to label my plot, possibly using the equation method from ggpmisc to give an informative label that links to the colour and equation (then I can remove the legend altogether). For example, in the plot below, I would ideally have the factor levels of 4, 6 and 8 in the equation LHS.

library(tidyverse)
library(ggpmisc)

df_mtcars <- mtcars %>% mutate(factor_cyl = as.factor(cyl))

p <- ggplot(df_mtcars, aes(x = wt, y = mpg, group = factor_cyl, colour= factor_cyl))+
  geom_smooth(method="lm")+
  geom_point()+
  stat_poly_eq(formula = my_formula,
               label.x = "centre",
               #eq.with.lhs = paste0(expression(y), "~`=`~"),
               eq.with.lhs = paste0("Group~factor~level~here", "~Cylinders:", "~italic(hat(y))~`=`~"),
               aes(label = paste(..eq.label.., sep = "~~~")), 
               parse = TRUE)
p

plot_lhs_1

There is a workaround by modifying the plot afterwards using the technique described here, but surely there is something simpler?

p <- ggplot(df_mtcars, aes(x = wt, y = mpg, group = factor_cyl, colour= factor_cyl))+
  geom_smooth(method="lm")+
  geom_point()+
  stat_poly_eq(formula = my_formula,
               label.x = "centre",
               eq.with.lhs = paste0(expression(y), "~`=`~"),
               #eq.with.lhs = paste0("Group~factor~level~here", "~Cylinders:", "~italic(hat(y))~`=`~"),
               aes(label = paste(..eq.label.., sep = "~~~")), 
               parse = TRUE)
p

# Modification of equation LHS technique from:
# https://stackoverflow.com/questions/56376072/convert-gtable-into-ggplot-in-r-ggplot2
temp <- ggplot_build(p)
temp$data[[3]]$label <- temp$data[[3]]$label %>% 
  fct_relabel(~ str_replace(.x, "y", paste0(c("8","6","4"),"~cylinder:", "~~italic(hat(y))" )))
class(temp)

#convert back to ggplot object
#https://stackoverflow.com/questions/56376072/convert-gtable-into-ggplot-in-r-ggplot2
#install.packages("ggplotify")
library("ggplotify")
q <- as.ggplot(ggplot_gtable(temp))
class(q)
q

plot_lhs_2


Solution

  • This first example puts the label to the right of the equation, and is partly manual. On the other hand it is very simple to code. Why this works is because group is always present in the data as seen by layer functions (statistics and geoms).

    library(tidyverse)
    library(ggpmisc)
    
    df_mtcars <- mtcars %>% mutate(factor_cyl = as.factor(cyl))
    
    my_formula <- y ~ x
    
    p <- ggplot(df_mtcars, aes(x = wt, y = mpg, group = factor_cyl, colour = factor_cyl)) +
      geom_smooth(method="lm")+
      geom_point()+
      stat_poly_eq(formula = my_formula,
                   label.x = "centre",
                   eq.with.lhs = "italic(hat(y))~`=`~",
                   aes(label = paste(stat(eq.label), "*\", \"*", 
                                     c("4", "6", "8")[stat(group)], 
                                     "~cylinders.",  sep = "")),
                   label.x.npc = "right",
                   parse = TRUE) +
      scale_colour_discrete(guide = FALSE)
    p
    

    enter image description here

    In fact with a little bit of additional juggling one can achieve almost an answer to the question. We need to add the lhs by pasting it explicitly in aes() so that we can add also paste text to its left based on a computed variable.

    library(tidyverse)
    library(ggpmisc)
    
    df_mtcars <- mtcars %>% mutate(factor_cyl = as.factor(cyl))
    
    my_formula <- y ~ x
    
    p <- ggplot(df_mtcars, aes(x = wt, y = mpg, group = factor_cyl, colour = factor_cyl)) +
      geom_smooth(method="lm")+
      geom_point()+
      stat_poly_eq(formula = my_formula,
                   label.x = "centre",
                   eq.with.lhs = "",
                   aes(label = paste("bold(\"", c("4", "6", "8")[stat(group)], 
                                     " cylinders:  \")*",
                                     "italic(hat(y))~`=`~",
                                     stat(eq.label),
                                     sep = "")),
                   label.x.npc = "right",
                   parse = TRUE) +
      scale_colour_discrete(guide = FALSE)
    p 
    

    enter image description here