Search code examples
rggplot2gamggpmisc

stat_fit_glance and generalized additive models (GAM) error


I am trying to add the p-value and R2 from mgcv::gam results to ggplot with facets. The sample dataframe and code are below. Is there a way to successfully paste the p-value and R2 on the ggplots?

DF <- data.frame(Site = rep(LETTERS[20:24], each = 4),
                 Region = rep(LETTERS[14:18], each = 4),
                 time = rep(LETTERS[1:10], each = 10),
                 group = rep(LETTERS[1:4], each = 10),
                 value1 = runif(n = 1000, min = 10, max = 15),
                 value2 = runif(n = 1000, min = 100, max = 150))
DF$time <- as.numeric(DF$time)


GAMFORMULA <- y ~ s(x,bs="cr",k=3)

plot1 <- ggplot(data=DF, 
                aes(x=time, y=value2)) +
  geom_point(col="gray", alpha=0.8,
             name="") +
  geom_line(col="gray", alpha=0.8,
            name="",aes(group=group)) +
  geom_smooth(se=T, col="darkorange", alpha=0.8,
              name="", fill="orange",
              method="gam",formula=GAMFORMULA) +
  theme_bw() + 
  theme(strip.text.x = element_text(size=10),
        strip.text.y = element_text(size=10, face="bold", angle=0),
        strip.background = element_rect(colour="black", fill="gray90"),
        axis.text.x = element_text(size=10),  # remove x-axis text
        axis.text.y = element_text(size=10), # remove y-axis text
        axis.ticks = element_blank(),  # remove axis ticks
        axis.title.x = element_text(size=18), # remove x-axis labels
        axis.title.y = element_text(size=25), # remove y-axis labels
        panel.background = element_blank(), 
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank()) + 
  labs(y="Value", x="Time", title = "") +
  stat_fit_glance(method = "gam",
                  method.args = list(formula = GAMFORMULA),
                  aes(label = sprintf('R^2~"="~%.3f~~italic(p)~"="~%.2f',
                                      stat(..r.squared..),stat(..p.value..))),
                  parse = TRUE)


plot1 + facet_wrap(Site~group, scales="free_y", ncol=3)

Error in sprintf("R^2~\"=\"~%.3f~~italic(p)~\"=\"~%.2f", r.squared, p.value) : 
  object 'r.squared' not found

Solution

  • My answer explains why stat_fit_glance() cannot be used to add r.sq to a plot, but I am afraid is does not provide an alternative approach.

    stat_fit_glance() is a wrapper on broom:glance() that fits the model and passes the model fit object to broom:glance(). In the case of gam(), broom:glance() does not return an estimate for R2 and consequently also stat_fit_glance() is unable to return it.

    To see what computed values are available one can use geom_debug() from package 'gginnards'.

    library(ggpmisc)
    library(gginnards)
    library(mgcv)
    
    DF <- data.frame(Site = rep(LETTERS[20:24], each = 4),
                     Region = rep(LETTERS[14:18], each = 4),
                     time = rep(LETTERS[1:10], each = 10),
                     group = rep(LETTERS[1:4], each = 10),
                     value1 = runif(n = 1000, min = 10, max = 15),
                     value2 = runif(n = 1000, min = 100, max = 150))
    DF$time <- as.numeric(DF$time)
    
    
    GAMFORMULA <- y ~ s(x,bs="cr",k=3)
    
    plot1 <- ggplot(data=DF, 
                    aes(x=time, y=value2)) +
      geom_point(col="gray", alpha=0.8,
                 name="") +
      geom_line(col="gray", alpha=0.8,
                name="",aes(group=group)) +
      geom_smooth(se=T, col="darkorange", alpha=0.8,
                  name="", fill="orange",
                  method="gam",formula=GAMFORMULA) +
      theme_bw() + 
      theme(strip.text.x = element_text(size=10),
            strip.text.y = element_text(size=10, face="bold", angle=0),
            strip.background = element_rect(colour="black", fill="gray90"),
            axis.text.x = element_text(size=10),  # remove x-axis text
            axis.text.y = element_text(size=10), # remove y-axis text
            axis.ticks = element_blank(),  # remove axis ticks
            axis.title.x = element_text(size=18), # remove x-axis labels
            axis.title.y = element_text(size=25), # remove y-axis labels
            panel.background = element_blank(), 
            panel.grid.major = element_blank(),  #remove major-grid labels
            panel.grid.minor = element_blank(),  #remove minor-grid labels
            plot.background = element_blank()) + 
      labs(y="Value", x="Time", title = "") +
      stat_fit_glance(method = "gam",
                      method.args = list(formula = GAMFORMULA),
                      # aes(label = sprintf('R^2~"="~%.3f~~italic(p)~"="~%.2f',
                      #                     stat(..r.squared..),stat(..p.value..))),
                      # parse = TRUE)
                      geom = "debug")
    
    
    plot1 + facet_wrap(Site~group, scales="free_y", ncol=3)
    
    

    enter image description here

    Shown above are the values returned by stat_fit_glance() for the first two panels in the plot.

    Note: There does not seem to be agreement on whether R-square is meaningful for GAM. However the summary() method for gam does return an adjusted R-square estimate as member r.sq.