Search code examples
rplotlinear-regression

Adding lm summaries to plots RStudio


I'm using this tutorial to perform a linear regression. Is there a way to add the summary (results) of the linear model to the plot in order to save it as a pdf.

This is the code:

scatter.smooth(x=cars$speed, y=cars$dist, main="Dist ~ Speed")  # scatterplot


linearMod <- lm(dist ~ speed, data=cars)  # build linear regression model on full data
print(linearMod)

#> Call:
#> lm(formula = dist ~ speed, data = cars)
#> 
#> Coefficients:
#> (Intercept)        speed  
#>     -17.579        3.932





summary(linearMod)  # model summary
#> Call:
#> lm(formula = dist ~ speed, data = cars)
#> 
#> Residuals:
#>     Min      1Q  Median      3Q     Max 
#> -29.069  -9.525  -2.272   9.215  43.201 
#> 
#> Coefficients:
#>             Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) -17.5791     6.7584  -2.601   0.0123 *  
#> speed         3.9324     0.4155   9.464 1.49e-12 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 15.38 on 48 degrees of freedom
#> Multiple R-squared:  0.6511, Adjusted R-squared:  0.6438 
#> F-statistic: 89.57 on 1 and 48 DF,  p-value: 1.49e-12

Solution

  • What you want to do is surprisingly difficult, which is why most people would not choose to do it that way :)

    The closest solution I could find uses ggplot2 and a lot of other packages. It's possible to do the following:

    1. Create a summary table of the regression model using stargazer::stargazer()
    2. Convert that to a PNG image file using kableExtra::as_image()
    3. Convert the PNG to a grob using grid::rasterGrob()
    4. Use ggplot2::annotation_custom() to embed the table-as-image-as-grob into a ggplot2 chart

    Note that as_image() requires some other packages and an installation of phantomjs.

    Here's an example:

    enter image description here

    However, there are other solutions that might be better such as a simple summary using ggpubr::stat_regline_equation() or adding a table grob using the output of broom::tidy().

    I think the simplest way to demonstrate all the options is in a RMarkdown file. Here is the code to copy into an RMarkdown file which you can knit in RStudio.

    ---
    title: "Regression"
    author: "Neil Saunders"
    date: "27/01/2021"
    output:
      html_document: 
        toc: yes
    ---
    
    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = FALSE,
                          message = FALSE,
                          fig.path = "figures/")
    library(ggplot2)
    library(ggpubr)
    library(broom)
    library(gridExtra)
    library(kableExtra)
    library(grid)
    library(sjPlot)
    library(stargazer)
    library(png)
    
    theme_set(theme_bw())
    ```
    
    # The model
    ```{r echo=TRUE}
    linearMod <- cars %>% 
      lm(dist ~ speed, data = .)
    ```
    
    # Visualizations
    
    ## Add equation and adjusted R-squared to a plot
    ```{r}
    cars %>% 
      ggplot(aes(speed, dist)) +
      geom_point() +
      geom_smooth(method = "lm") +
      stat_regline_equation(
        aes(label =  paste(..eq.label.., ..adj.rr.label.., sep = "~~~~"))
      )
    ```
    
    ## Add tidy summary table to a plot
    ```{r}
    linearMod_tidy <- tidy(linearMod)
    
    cars %>% 
      ggplot(aes(speed, dist)) +
      geom_point() +
      geom_smooth(method = "lm") +
      annotation_custom(tableGrob(linearMod_tidy, 
                        theme = ttheme_default(base_size = 10)), 
                        xmin = 0, ymin = 90)
    ```
    
    
    ## Add tabular summary and plot side-by-side
    ### stargazer
    
    :::::: {.columns}
    ::: {.column width="48%" data-latex="{0.48\textwidth}"}
    ```{r}
    cars %>% 
      ggplot(aes(speed, dist)) +
      geom_point() +
      geom_smooth(method = "lm")
    ```
    :::
    ::: {.column width="4%" data-latex="{0.04\textwidth}"}
    \ 
    <!-- an empty Div (with a white space), serving as
    a column separator -->
    :::
    :::::: {.column width="48%" data-latex="{0.48\textwidth}"}
    ```{r results='asis'}
    stargazer(linearMod, type = "html")
    ```
    :::
    ::::::
    
    ### tab\_model
    
    :::::: {.columns}
    ::: {.column width="48%" data-latex="{0.48\textwidth}"}
    ```{r echo=FALSE,}
    cars %>% 
      ggplot(aes(speed, dist)) +
      geom_point() +
      geom_smooth(method = "lm")
    ```
    :::
    ::: {.column width="4%" data-latex="{0.04\textwidth}"}
    \ 
    <!-- an empty Div (with a white space), serving as
    a column separator -->
    :::
    :::::: {.column width="48%" data-latex="{0.48\textwidth}"}
    ```{r}
    tab_model(linearMod)
    ```
    :::
    ::::::
    
    ## Add stargazer table to a plot
    
    ```{r}
    imgfile <- stargazer(linearMod, type = "html") %>% 
      as_image()
    
    img <- readPNG(imgfile)
    g <- rasterGrob(img, interpolate = TRUE, width = 0.5, height = 0.5)
    
    cars %>% 
      ggplot(aes(speed, dist)) +
      geom_point() +
      geom_smooth(method = "lm") +
      annotation_custom(g, xmin = 1, xmax = 15, ymin = 50, ymax = 130)
    ```