Plot A Normal Distribution In R

7 min read

Introduction

Plotting a normal distribution in R is a fundamental skill for anyone working with statistics, data science, or research. Still, whether you need to visualize the shape of a probability density function (PDF) for a report, assess how well your data fits a normal curve, or simply demonstrate the concept in a classroom, R provides both base graphics and advanced packages that make the task straightforward. This article will guide you step‑by‑step through the entire process, from generating synthetic data to producing a polished, publication‑ready plot. By the end, you will be able to create a clear visual representation of a normal distribution, customize its appearance, and understand the underlying concepts that make the graph meaningful.

Prerequisites

Before you begin, see to it that you have a working installation of R and RStudio (or any IDE you prefer). The following packages are essential:

  • base – comes pre‑installed with R and contains the plot function.
  • ggplot2 – a powerful graphics package based on the Grammar of Graphics; install it with install.packages("ggplot2") if you haven’t already.
  • MASS (optional) – useful for generating random numbers from specific distributions.

Load the required libraries at the start of your script:

library(ggplot2)   # for advanced plotting

Generating a Normal Distribution

1. Create a Sequence for the Density Curve

A smooth normal curve requires a sequence of x‑values that spans the range where the density is non‑negligible. Typically, you choose a range from -4 to 4 standard deviations, because beyond this the probability density approaches zero.

x <- seq(-4, 4, length.out = 1000)   # 1000 points for a smooth curve

2. Compute the Density

Use the built‑in function dnorm() to calculate the probability density for each x value. The function takes the mean (mu) and standard deviation (sigma) as arguments.

mu   <- 0          # population mean
sigma <- 1         # population standard deviation
y   <- dnorm(x, mean = mu, sd = sigma)   # density values

3. Generate Random Samples (Optional)

If you also want to overlay a histogram of random samples, generate data with rnorm():

set.seed(123)               # for reproducibility
sample_data <- rnorm(n = 1000, mean = mu, sd = sigma)

Plotting with Base R

Histogram with Density Curve

The simplest way to visualize a normal distribution in base R is to combine a histogram with the theoretical density curve Simple, but easy to overlook..

hist(sample_data,
     breaks = 30,
     col = "lightblue",
     main = "Histogram of Normal Samples with Density Curve",
     xlab = "Value",
     ylab = "Frequency")
lines(x, y * length(sample_data) * diff(x), col = "red", lwd = 2)

Explanation of key points:

  • breaks = 30 defines the number of histogram bins; adjust to suit your data.
  • col sets the fill color of the bars.
  • lines() adds the density curve. The factor y * length(sample_data) * diff(x) rescales the density to match the histogram’s y‑axis (frequency rather than probability).

Adding a Theoretical Curve Directly

If you prefer to plot the density curve without a histogram, you can use plot():

plot(x, y, type = "l", col = "darkgreen", lwd = 2,
     main = "Normal Density Curve (μ = 0, σ = 1)",
     xlab = "Value", ylab = "Density")

Important: The y‑axis now represents density (area under the curve equals 1), so no rescaling is needed.

Plotting with ggplot2

Basic Histogram + Density

ggplot2 offers a more flexible and aesthetically pleasing approach. First, create a data frame that contains both the sample data and a sequence for the density curve.

# Data frame for samples
sample_df <- data.frame(value = sample_data)

# Data frame for the theoretical curve
curve_df <- data.frame(x = x, density = y)

Now plot:

ggplot(sample_df, aes(x = value)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "lightblue", color = "black") +
  geom_line(data = curve_df, aes(x = x, y = density), color = "red", size = 1.2) +
  labs(title = "Normal Distribution (μ = 0, σ = 1)",
       x = "Value", y = "Density") +
  theme_minimal()

Key components:

  • aes(y = ..density..) transforms the histogram counts into density, allowing direct overlay with the density curve.
  • geom_histogram() handles binning; bins = 30 can be tweaked.
  • geom_line() draws the smooth density curve.
  • theme_minimal() provides a clean background; you can replace it with other themes.

Customizing the Plot

1. Change Colors and Line Types

ggplot(sample_df, aes(x = value)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "#66c2a5", color = "white") +
  geom_line(data = curve_df, aes(x = x, y = density), color = "#fc8d62", linetype = "dashed", size = 1) +
  labs(title = "Customized Normal Distribution Plot",
       x = "Value", y = "Density") +
  theme_classic()

2. Add a Vertical Line for the Mean

ggplot(sample_df, aes(x = value)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "gray90", color = "black") +
  geom_vline(xintercept = mu, color = "darkblue", linetype = "dotdash", size = 1) +
  geom_line(data = curve_df, aes(x = x, y = density), color = "darkgreen", size = 1.2) +
  labs(title = "Normal Distribution with Mean Indicator",
       x = "Value", y = "Density") +
  theme_bw()

3. Annotate the Plot

Use annotate() to add text or labels:

ggplot(sample_df, aes(x = value)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "mistyrose", color = "black") +
  geom_line(data = curve_df, aes(x = x, y = density), color = "purple",

, size = 1.2) +
  annotate("text", x = mu, y = max(y) * 0.On top of that, 9, label = paste("μ =", mu),
           color = "darkblue", size = 5, fontface = "bold") +
  annotate("segment", x = mu - sigma, xend = mu + sigma,
           y = dnorm(mu + sigma), yend = dnorm(mu + sigma),
           color = "orange", size = 1, arrow = arrow(ends = "both", length = unit(0. 2, "cm"))) +
  annotate("text", x = mu, y = dnorm(mu + sigma) * 1.

#### 4. Faceting for Multiple Distributions  

Compare several normal distributions side by side:

```r
# Generate data for multiple distributions
params <- data.frame(
  mu = c(-2, 0, 2),
  sigma = c(0.5, 1, 1.5),
  label = c("μ=-2, σ=0.5", "μ=0, σ=1", "μ=2, σ=1.5")
)

curve_list <- lapply(1:nrow(params), function(i) {
  x_seq <- seq(params$mu[i] - 4 * params$sigma[i],
               params$mu[i] + 4 * params$sigma[i], length.out = 200)
  data.frame(
    x = x_seq,
    density = dnorm(x_seq, params$mu[i], params$sigma[i]),
    group = params$label[i]
  )
})
multi_curve_df <- do.

ggplot(multi_curve_df, aes(x = x, y = density, color = group)) +
  geom_line(size = 1.2) +
  labs(title = "Comparing Normal Distributions",
       x = "Value", y = "Density", color = "Parameters") +
  theme_minimal() +
  scale_color_brewer(palette = "Set1")

Saving Your Plots

Base R

png("normal_plot_base.png", width = 800, height = 600, res = 120)
plot(x, y, type = "l", col = "darkgreen", lwd = 2,
     main = "Normal Density Curve (μ = 0, σ = 1)",
     xlab = "Value", ylab = "Density")
dev.off()

ggplot2

ggsave("normal_plot_ggplot.png", width = 8, height = 6, dpi = 300,
       plot = last_plot())  # or assign the plot to an object and pass it

Tip: Use ggsave() with device = "pdf" for vector output suitable for publications Small thing, real impact. Worth knowing..


Common Pitfalls & Quick Fixes

Issue Cause Solution
Histogram bars too tall/short vs. Because of that, , 500–1000)
Axes cut off data Default limits too narrow Add `coord_cartesian(xlim = c(... g.curve
Legend missing in ggplot Aesthetics mapped inside geom_* without aes() Move color = "group" inside aes() in the initial ggplot() call
..out (e.)oraes(y = after_stat(density))` Use density scaling in geom_histogram()
Curve looks jagged Too few points in seq() Increase `length.density..

Conclusion

Visualizing the normal distribution in R is straightforward once you understand the two core ingredients: a sequence of quantiles (x) and their corresponding densities (dnorm(x, mean, sd)). Base R’s plot() gives you a quick, no‑dependency graphic ideal for exploratory checks, while ggplot2 provides a layered grammar that scales to complex, publication‑ready figures—complete with histograms, theoretical curves, annotations, facets, and custom themes Easy to understand, harder to ignore..

Whether you are teaching the empirical rule, checking model residuals, or preparing a manuscript figure, the patterns shown here—generating a smooth x grid, computing y = dnorm(x, ...Day to day, ), and overlaying empirical data with geom_histogram(aes(y = after_stat(density)))—form a reusable template. Adjust the parameters, swap themes, add vertical lines or shaded regions for confidence intervals, and export with ggsave() to fit any workflow.

With these tools in hand, you can move beyond static textbook curves and create dynamic, informative visual

Just Published

New Around Here

Related Territory

Other Angles on This

Thank you for reading about Plot A Normal Distribution In R. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home