Written and maintained by CASRAI Editorial Board
Last updated
A linear regression scatter plot is a scatter plot of paired measurements with one straight line drawn through the points: the least-squares line that best predicts the vertical variable (y) from the horizontal variable (x). The points show the data, the line shows the model, and the gap between each point and the line is a residual. This guide covers how to draw the plot, how to read the line and the shaded band around it, and how to report the result.
What a scatter plot with a linear regression line shows
A scatter plot with a linear regression line answers one question: does y change in a roughly straight-line way as x changes, and by how much? The slope of the line is the average change in y per one-unit increase in x. The height where the line meets x = 0 is the intercept. How tightly the points hug the line tells you how well the line describes them.
The same figure goes by several names: a scatter plot linear regression chart, a linear regression line scatter plot, a trend line chart, or a line of best fit plot. In every case it is two layers: the raw points first, then the fitted line on top. If you only need the points, see scatter plots in Python or scatterplots in R; for what the point cloud itself tells you before any line is drawn, see scatterplot interpretation.
Formula: the line drawn on the plot
The NIST/SEMATECH e-Handbook of Statistical Methods describes linear least squares as fitting data with a function in which each explanatory variable is multiplied by an unknown parameter, at most one unknown parameter has no explanatory variable, and the terms are summed. For one explanatory variable this is the straight line:
ŷ = b₀ + b₁x
- ŷ (y-hat): the value of y the line predicts at a given x (see y-hat).
- b₀: the intercept, the predicted y when x = 0.
- b₁: the slope, the predicted change in y per one-unit increase in x.
- x: the horizontal-axis (explanatory) variable.
Least squares chooses b₀ and b₁ so that the sum of the squared vertical distances from the points to the line is as small as possible. The closed forms are b₁ = Sxy / Sxx and b₀ = ȳ − b₁x̄, where Sxx = Σ(x − x̄)² and Sxy = Σ(x − x̄)(y − ȳ). The share of the variation in y that the line accounts for is R² = Sxy² / (Sxx · Syy), where Syy = Σ(y − ȳ)². With one predictor, R² is the square of the Pearson correlation r.
Worked example: drawing the line by hand
The numbers below are invented for illustration only: hours studied (x) and exam score (y) for eight students.
| Student | x (hours) | y (score) |
|---|---|---|
| 1 | 1 | 52 |
| 2 | 2 | 55 |
| 3 | 3 | 61 |
| 4 | 4 | 60 |
| 5 | 5 | 68 |
| 6 | 6 | 70 |
| 7 | 7 | 75 |
| 8 | 8 | 79 |
- Means: x̄ = 36 / 8 = 4.5 and ȳ = 520 / 8 = 65.
- Sxx = Σ(x − 4.5)² = 12.25 + 6.25 + 2.25 + 0.25 + 0.25 + 2.25 + 6.25 + 12.25 = 42.
- Sxy = Σ(x − 4.5)(y − 65). The eight cross-products are (−3.5)(−13) = 45.5; (−2.5)(−10) = 25; (−1.5)(−4) = 6; (−0.5)(−5) = 2.5; (0.5)(3) = 1.5; (1.5)(5) = 7.5; (2.5)(10) = 25; (3.5)(14) = 49. Their sum is Sxy = 162.
- Slope: b₁ = 162 / 42 = 3.857.
- Intercept: b₀ = 65 − 3.857 × 4.5 = 47.643.
- Syy = Σ(y − 65)² = 169 + 100 + 16 + 25 + 9 + 25 + 100 + 196 = 640, so R² = 162² / (42 × 640) = 26,244 / 26,880 = 0.976 and r = 0.988.
The line is ŷ = 47.64 + 3.857x. To draw it on the scatter plot, mark two points on the line, for example x = 1 (ŷ = 51.50) and x = 8 (ŷ = 78.50), and join them. Each additional hour of study goes with a predicted 3.86-point higher score in this made-up sample. The residual for student 4 is 60 − (47.643 + 3.857 × 4) = 60 − 63.07 = −3.07, so that point sits about three points below the line (see how to calculate residuals).
Reading the line and the shaded band
Scatter plot with linear regression line: what each part means
| What you see | How to read it |
|---|---|
| Line rises left to right | Slope b₁ is positive: higher x goes with higher predicted y. |
| Line falls left to right | Slope b₁ is negative: higher x goes with lower predicted y. |
| Points tight around the line | R² is high; the line describes most of the variation in y. |
| Points widely scattered around the line | R² is low; the line is a weak summary even if the slope is not zero. |
| Points curve away from the line in a systematic arc | A straight line is the wrong model; see the linearity assumption. |
| One point far from the rest | It can pull the line toward it; refit without it to see how much the line moves. |
The shaded confidence band
Plotting tools such as seaborn’s regplot draw a translucent band around the line. In seaborn this band is the confidence interval for the regression estimate, set by the ci argument and estimated by bootstrapping. It describes uncertainty about where the average line lies, not where individual points will fall, so many points can sit outside it. For large datasets the seaborn documentation lets you set ci=None to skip the bootstrap. For background on intervals see confidence interval.
Linear regression line scatter plot versus other fits
A straight line is one choice among several. In seaborn, order above 1 fits a polynomial through numpy’s polyfit, and lowess=True draws a locally weighted smoother using statsmodels (no confidence band). If a smoother bends sharply away from your straight line, treat that as evidence the relationship is not linear.
Assumptions and common mistakes
- Linear relationship. The straight line only summarises a straight-line pattern. Check the points for curvature before trusting the slope.
- Normal residuals for the usual tests. SciPy’s documentation notes that the standard error of the slope assumes normally distributed residuals; the p-value comes from a Wald test using the t-distribution with the null hypothesis that the slope is zero.
- Extrapolating past the data. The drawn line should stop at the observed x range. Predicting beyond it assumes the pattern continues, which the data cannot show.
- Reading the line as causation. A fitted line describes association between x and y. It does not show that changing x causes y to change.
- Swapping the axes. Regressing y on x and regressing x on y give different lines. Put the variable you want to predict on the vertical axis.
- Dropping the points. Showing only the line hides the spread. Draw the points, then the line.
How to report it (APA style)
A generic reporting form for a simple linear regression gives the sample size or degrees of freedom, the slope with its confidence interval, the test statistic and p-value, and R². For the worked example above:
A simple linear regression was fitted to predict exam score from hours studied. Hours studied significantly predicted exam score, b = 3.86, 95% CI [3.26, 4.46], t(6) = 15.73, p < .001, and the model explained 97.6% of the variance in scores, R² = .98. Figure 1 shows the data and the fitted line.
Label the figure with the axes, units and the number of points, and state in the caption what the shaded band represents (for example, a 95% confidence interval for the regression line). Italicise statistical symbols such as p, t, b and R² as your style guide requires.
How to calculate and plot it in Excel, R or Python
Excel
With x in A2:A9 and y in B2:B9, use =SLOPE(B2:B9,A2:A9) (3.857), =INTERCEPT(B2:B9,A2:A9) (47.643) and =RSQ(B2:B9,A2:A9) (0.976). To draw the plot, select both columns, insert a scatter chart, then add a linear trendline and tick the options to display the equation and R-squared on the chart.
R
hours <- 1:8
score <- c(52, 55, 61, 60, 68, 70, 75, 79)
fit <- lm(score ~ hours)
plot(hours, score)
abline(fit)
summary(fit)$r.squared
Python
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
hours = np.array([1, 2, 3, 4, 5, 6, 7, 8])
score = np.array([52, 55, 61, 60, 68, 70, 75, 79])
fit = stats.linregress(hours, score)
plt.scatter(hours, score)
plt.plot(hours, fit.intercept + fit.slope * hours)
plt.xlabel("Hours studied")
plt.ylabel("Exam score")
print(fit.slope, fit.intercept, fit.rvalue ** 2)
In SciPy’s linregress, slope and intercept are the line you draw, rvalue is the Pearson r (square it for R²), pvalue tests whether the slope is zero, and stderr is the standard error of the slope. For a one-call plot with a confidence band, seaborn.regplot(x=hours, y=score) draws the points, the line and the bootstrapped band; fit_reg=False shows the points only. For more on the calculation, see the linear regression calculator guide.
FAQ
What does a linear regression line on a scatter plot tell you?
It shows the straight-line trend between two variables: its slope is the predicted change in y per one-unit change in x, and the distance of points from it shows how well the line fits.
How do you add a regression line to a scatter plot?
Fit the line first (slope and intercept), then draw it over the points: abline(fit) in R, plt.plot of intercept + slope × x in Python, or a linear trendline in Excel.
Is the shaded area around the line the range of the data?
No. In seaborn it is a confidence interval for the estimated line, so it is narrower than the spread of the points.
When should I not use a straight line?
When the points follow a curve, the spread changes systematically along x, or a few extreme points drive the slope. Use a curved fit or a different method, and check the plot of residuals.
Does a high R² mean x causes y?
No. R² measures how closely the points follow the line, not why they do.
Sources
- NIST/SEMATECH e-Handbook of Statistical Methods, “Linear Least Squares Regression” (checked 2026-10-29): itl.nist.gov/div898/handbook/pmd/section1/pmd141.htm
- SciPy documentation,
scipy.stats.linregress(checked 2026-10-29): docs.scipy.org - seaborn documentation,
seaborn.regplot(checked 2026-10-29): seaborn.pydata.org - Matplotlib documentation,
matplotlib.pyplot.scatter(checked 2026-10-29): matplotlib.org







