library(ggpubr)
ggdensity(ToothGrowth, x = "len", fill = "lightgray",
xlab = "Tooth length")
Check whether your data is normally distributed — rstatix the tidy way, base R for the classics
Learn to test for normality in R. Use the Shapiro-Wilk test — rstatix shapiro_test() for one, grouped or multiple variables, and base R shapiro.test() — alongside the visual checks (density plot and Q-Q plot with ggpubr) that you should always combine with the test.
June 22, 2026
July 17, 2026
p > 0.05 → no significant departure from normal (assume normality); p < 0.05 → the data is not normal (use a non-parametric test).shapiro_test() from rstatix (one variable, grouped, or several at once) or base R shapiro.test().Many common tests — the t-test, ANOVA, and Pearson correlation — are parametric: they’re only valid if the data follows a roughly normal (Gaussian) distribution. So before running one, you check the assumption. If it holds, use the parametric test; if not, switch to a non-parametric alternative (Wilcoxon, Kruskal-Wallis, Spearman).
This lesson checks normality two complementary ways — visually (density and Q-Q plots) and with a significance test (Shapiro-Wilk) — using rstatix shapiro_test() and base R shapiro.test() on the built-in ToothGrowth data (the len = tooth-length variable).
First, a caveat: with a large sample (n > 30–40), the central limit theorem says the sampling distribution of the mean is approximately normal regardless of the data’s shape — so parametric tests are often fine even when the raw data isn’t perfectly normal. Normality matters most for small samples. Either way, it’s good practice to look.
A density plot shows the distribution’s shape — you’re looking for a symmetric, bell curve:
A Q-Q plot compares your data’s quantiles to a normal distribution’s. If the data is normal, the points fall along the 45-degree reference line (inside the confidence band):
The points hug the line, so tooth length looks approximately normal. (Base R offers qqnorm() + qqline(), and car::qqPlot() adds the confidence band like ggqqplot().)
Before you trust a plot, learn what the two shapes look like. A normal variable gives a symmetric bell and a straight Q-Q line; a skewed one gives a lopsided density and points that curve away from the line:
library(ggpubr)
set.seed(123)
normal.data <- rnorm(200) # symmetric, normal
skewed.data <- rexp(200) # right-skewed
ggarrange(
ggdensity(normal.data, title = "Normal: symmetric bell"),
ggdensity(skewed.data, title = "Skewed: long right tail"),
ggqqplot(normal.data, title = "Normal: points on the line"),
ggqqplot(skewed.data, title = "Skewed: points curve off"),
ncol = 2, nrow = 2
)
Once you can spot the skewed pattern, the Q-Q plot becomes a fast first read on any new variable.
Visual inspection is subjective. The Shapiro-Wilk test puts a number on it. Its null hypothesis is “the data is normally distributed”, so:
shapiro_test() is pipe-friendly and returns a tidy result — and it scales to grouped and multiple variables, which base R can’t do in one call:
# A tibble: 1 × 3
variable statistic p
<chr> <dbl> <dbl>
1 len 0.967 0.109
Here p > 0.05, so we assume len is normally distributed.
Shapiro-Wilk normality test
data: ToothGrowth$len
W = 0.96743, p-value = 0.1091
Same statistic, same p-value — shapiro_test() is a tidy wrapper around shapiro.test().
The rstatix advantage: test each group separately (essential before a t-test or ANOVA, which assume normality within groups)…
# A tibble: 3 × 4
dose variable statistic p
<dbl> <chr> <dbl> <dbl>
1 0.5 len 0.941 0.247
2 1 len 0.931 0.164
3 2 len 0.978 0.902
…or several variables at once:
Check normality on a different variable — try iris$Sepal.Width, or test mtcars$mpg grouped by cyl. The sandbox boots on first Run.
Ask Prova “is my variable normal enough for a t-test, and what should I do if it isn’t?” — it answers with rstatix code you can run on your own data, then helps you read the Q-Q plot and the Shapiro test. The runtime is the judge. Ask Prova →
Shapiro-Wilk errors on a large sample. shapiro.test() requires between 3 and 5000 observations. For bigger samples, rely on the Q-Q plot (and the central limit theorem) instead.
The test says non-normal but the Q-Q plot looks fine. With a large n, Shapiro-Wilk becomes hyper-sensitive and flags trivial deviations. For n > 50, trust the Q-Q plot more than the p-value.
A tiny sample “passes” normality. Small samples lack the power to detect non-normality, so a non-significant result isn’t strong evidence. Combine the test with the visual check — always.
Combine a visual check with a significance test. Plot a Q-Q plot (ggpubr::ggqqplot(data, "var")) and run the Shapiro-Wilk test — data %>% shapiro_test(var) (rstatix) or shapiro.test(data$var) (base R). If the Q-Q points hug the line and the Shapiro p-value is above 0.05, you can assume normality.
The null hypothesis is that the data is normal. So p > 0.05 means you cannot reject normality — assume the data is normal. p < 0.05 means the data deviates significantly from normal, so a parametric test may not be appropriate; consider a non-parametric alternative.
Shapiro-Wilk is generally preferred for testing normality: it has more statistical power than the Kolmogorov-Smirnov (K-S) test for this purpose. Use K-S when comparing a sample to a fully specified distribution; for the routine “is my data normal?” question, use Shapiro-Wilk.
You have three good options: (1) use a non-parametric test (Wilcoxon instead of t-test, Kruskal-Wallis instead of ANOVA, Spearman instead of Pearson); (2) transform the variable (log, square-root, Box-Cox) to make it more normal; or (3) if your sample is large, rely on the central limit theorem and proceed with the parametric test.
Yes — for a t-test or ANOVA, the normality assumption applies to the data within each group, not the pooled data. Use data %>% group_by(group) %>% shapiro_test(value) to check every group at once.
mtcars$mpg is normally distributed (Q-Q plot + Shapiro test). Is it normal at the 0.05 level?p = 0.003, and concludes the data “can’t be used” for a t-test. Why is that conclusion probably wrong?Fill both blanks with mpg. Read the p column: above 0.05 → assume normal. For question 2, think about how the Shapiro-Wilk test behaves as the sample size grows very large.
For question 2: with 8,000 observations, the Shapiro-Wilk test is so powerful that it detects trivial, harmless departures from normality — a tiny effect becomes “significant.” At that sample size the central limit theorem also makes the t-test robust to non-normality. The right move is to look at the Q-Q plot: if the points roughly follow the line, the parametric test is fine despite the small p-value.
You can now test for normality in R the right way — combining a Q-Q plot with the Shapiro-Wilk test (shapiro_test() in rstatix for one, grouped or multiple variables, or base shapiro.test()), and reading the result with sample size in mind.
This is the gate before a parametric test. If normality holds, move on to the t-test or correlation test; if it doesn’t, reach for a non-parametric alternative.
Prove you can do it. Master the whole Statistical Assumptions in R series — track your path, build projects, and earn a certificate.
Go Pro — unlimited Prova on your own data and a verifiable certificate that proves the skill.
from $15/mo billed yearly
✓ You're Pro — keep going. The runtime is the judge.
Ready to level up?
Get new R & Python lessons by email
Practical, reproducible, no spam. Unsubscribe anytime.
Double opt-in. We never share your email.
Every result on this page was produced by the code shown, run at build time against a pinned R environment — edit any block and Run to reproduce it yourself.
@online{2026,
author = {},
title = {Normality {Test} in {R:} {Shapiro-Wilk} \& {Q-Q} {Plots}},
date = {2026-06-22},
url = {https://www.datanovia.com/learn/biostatistics/assumptions/normality-test-in-r},
langid = {en}
}