Adding a regression line to ggplot in R helps you visualize and quantify the relationship between a predictor and an outcome. With tidy data and the ggplot2 package, you can layer a trend line that fits your modeling choice and styling needs.
These examples use geom_smooth for automatic fitting and stat_poly_eq from ggpmisc to render equation and R-squared labels directly on the plot, which is common in reporting and dashboard scenarios.
| Package | Function | Purpose | Key Argument |
|---|---|---|---|
| ggplot2 | ggplot() + geom_point() | Base scatter plot construction | data, mapping |
| ggplot2 | geom_smooth() | Add regression line with optional confidence band | method, se, color, formula |
| ggpmisc | stat_poly_eq() | Render equation and R-squared on plot | formula, label.x, label.y |
| dplyr | mutate() + across() | Prepare numeric variables and compute expressions | .fns, na.rm |
| broom | tidy() | Extract model coefficients and statistics | conf.int |
Prepare tidy data for regression visualization
Begin by ensuring your data frame contains numeric columns and no missing values that would break model fitting. Use dplyr verbs to filter irrelevant groups and scale predictors if necessary, which stabilizes numerical fitting in ggplot2 layers.
Store the cleaned tibble in a variable so you can reuse it for multiple plot variants and model summaries, which keeps your regression line to ggplot workflow reproducible and transparent.
Quick preparation snippet
df_clean <- df_raw |> dplyr::filter(!is.na(x), !is.na(y)) |> dplyr::mutate(x_scale = scale(x)[[1]])
Add basic regression line with geom_smooth
Use geom_smooth(method = "lm", se = TRUE) to overlay a straight-line regression and a default confidence band. This approach fits a linear model per group and returns a ggplot layer that automatically handles faceting and grouping.
Set formula = y ~ x if your relationship is simple, or color and linetype by a categorical variable to compare slopes across levels while preserving readability in the regression line to ggplot visual.
Basic linear fit example
ggplot(df_clean, aes(x = x, y = y)) + geom_point(alpha = 0.6) + geom_smooth(method = "lm", se = TRUE, color = "steelblue")
Render equation and fit statistics with stat_poly_eq
The ggpmisc package provides stat_poly_eq, which accepts a formula and parses the model to build labels for slope, intercept, p-value, and R-squared. This keeps model diagnostics inline with the regression line on the same ggplot object.
Control placement with argument label.x and label.y, and choose parse = TRUE so that plotmath expressions render neatly beside the regression line annotation.
Annotated plot example
p <- ggplot(df_clean, aes(x = x, y = y)) + geom_point(alpha = 0.6)
p + geom_smooth(method = "lm", se = FALSE, color = "grey30") + stat_poly_eq(aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), parse = TRUE)
Customize appearance and multiple regression lines
When modeling with factors, specify method = "lm" and map group or color to a categorical variable so that geom_smooth draws separate regression lines per level. You can adjust line type, size, and alpha to keep overlapping bands and slopes readable.
Combine stat_poly_eq with different formula arguments to show grouped equations, and use theme_minimal or theme_classic to reduce visual clutter around densely labeled regression line to ggplot outputs.
Key steps to integrate regression line into ggplot
- Clean and validate your data with dplyr to remove NAs and extreme outliers.
- Map variables correctly in aes() so that x and y align with your modeling formula.
- Add geom_point for raw observations and geom_smooth(method = "lm") for the regression line.
- Use ggpmisc::stat_poly_eq to show equation and R-squared with parse = TRUE.
- Customize colors, line types, and bandwidth via se, size, and alpha for clarity.
- Test grouped models by mapping color or linetype to factors and verifying slopes.
- Save reusable plot templates so each regression line to ggplot adapts to new data.
FAQ
Reader questions
How do I display confidence bands only for selected groups while keeping all data points visible?
Use geom_smooth(se = TRUE, alpha = 0.2) inside a faceted plot or subset the layer data with aes() to a grouped tibble, then overlay geom_point for all points without bandwidth for reference groups.
Can I add a regression line for only part of the data without subsetting the dataframe manually?
Yes, pass a subset aesthetic or use the subset argument inside layer data within geom_smooth so that the method fits on a filtered slice while the full dataset remains plotted underneath.
How do I align the equation label in the top right corner even when faceting?
Set label.x and label.y in stat_poly_eq to normalized coordinates (0.95, 0.95) and use facet_wrap with switch = "both" or theme(legend.position) to control overall layout without moving annotation per panel.
What should I do when geom_smooth warns about singularities or perfect separation?
Inspect X and Y for near-zero variance, remove or combine sparse factor levels, or switch to robust methods such as MASS::rlm with method.args passed through geom_smooth to stabilize fits.