Normality Test in R: Shapiro-Wilk & Q-Q Plots

Check whether your data is normally distributed — rstatix the tidy way, base R for the classics

Biostatistics

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.

Published

June 22, 2026

Modified

July 17, 2026

TipKey takeaways
  • Many tests (t-test, ANOVA, Pearson correlation) are parametric — they assume the data is normally distributed. Check that assumption before you test.
  • Use two tools together: a visual check (density plot + Q-Q plot) and a significance test (Shapiro-Wilk). Neither alone is reliable.
  • The Shapiro-Wilk test: p > 0.05 → no significant departure from normal (assume normality); p < 0.05 → the data is not normal (use a non-parametric test).
  • Run it with shapiro_test() from rstatix (one variable, grouped, or several at once) or base R shapiro.test().
  • The test is sample-size sensitive: tiny samples almost always “pass”; very large samples flag trivial deviations — so lean on the Q-Q plot for n > 50.

Introduction

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).

Large samples: the central limit theorem

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.

Visual methods

Density plot

A density plot shows the distribution’s shape — you’re looking for a symmetric, bell curve:

library(ggpubr)

ggdensity(ToothGrowth, x = "len", fill = "lightgray",
          xlab = "Tooth length")

A density plot of tooth length, showing a roughly bell-shaped, slightly irregular distribution.

Q-Q plot

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):

library(ggpubr)

ggqqplot(ToothGrowth, x = "len")

A Q-Q plot of tooth length against the normal distribution, with points falling close to the 45-degree reference line inside the shaded 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().)

Calibrate your eye: normal vs skewed

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
)

Four panels: a symmetric bell-shaped density and a straight Q-Q plot for normally distributed data, beside a right-skewed density and a Q-Q plot whose points curve away from the reference line.

Once you can spot the skewed pattern, the Q-Q plot becomes a fast first read on any new variable.

The Shapiro-Wilk test

Visual inspection is subjective. The Shapiro-Wilk test puts a number on it. Its null hypothesis is “the data is normally distributed”, so:

  • p > 0.05 → fail to reject → assume normality.
  • p < 0.05 → reject → the data is significantly non-normal.

With base R

shapiro.test(ToothGrowth$len)

    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().

Grouped and multiple variables

The rstatix advantage: test each group separately (essential before a t-test or ANOVA, which assume normality within groups)…

library(rstatix)

ToothGrowth %>%
  group_by(dose) %>%
  shapiro_test(len)
# 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:

library(rstatix)

iris %>% shapiro_test(Sepal.Length, Petal.Width)
# A tibble: 2 × 3
  variable     statistic            p
  <chr>            <dbl>        <dbl>
1 Petal.Width      0.902 0.0000000168
2 Sepal.Length     0.976 0.0102      

Try it live

Check normality on a different variable — try iris$Sepal.Width, or test mtcars$mpg grouped by cyl. The sandbox boots on first Run.

🟢 With an AI agent

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 →

Common issues

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.

Frequently asked questions

Combine a visual check with a significance test. Plot a Q-Q plot (ggpubr::ggqqplot(data, "var")) and run the Shapiro-Wilk testdata %>% 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.

Test your understanding

  1. Run it. In the live cell, test whether mtcars$mpg is normally distributed (Q-Q plot + Shapiro test). Is it normal at the 0.05 level?
  2. Conceptual. A colleague runs Shapiro-Wilk on 8,000 rows, gets 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.

library(rstatix)
mtcars %>% shapiro_test(mpg)
#> p ≈ 0.12  → above 0.05, so mpg is approximately normal.

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.

Conclusion

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.

Reuse

Citation

BibTeX citation:
@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}
}
For attribution, please cite this work as:
“Normality Test in R: Shapiro-Wilk & Q-Q Plots.” 2026. June 22. https://www.datanovia.com/learn/biostatistics/assumptions/normality-test-in-r.