Skip to contents

A ridgeline plot (also known as a "joy plot") shows the distribution of a numeric variable for several groups as a stack of partially overlapping density curves that share a common x-axis. The nickname comes from the cover of Joy Division's 1979 album Unknown Pleasures, itself a reproduction of a 1970 plot of successive radio pulses from the first discovered pulsar. The format was popularised by Claus Wilke's ggridges package and by FiveThirtyEight and The Washington Post graphics desks.

Ridgeline plots are ideal for comparing the shape of many distributions at once (e.g. across months, categories, or experimental conditions) while using far less vertical space than a set of separate histograms.

The kernel density estimates are computed in the browser. Ridges are drawn from the back (top) to the front (bottom), so lower ridges overlap the ones above them. Hovering a ridge (or its label) brings it to the front, dims the others, and shows a small label with the group's number of observations and mean.

Usage

ridgeline_plot(
  data,
  x,
  group,
  bandwidth = NULL,
  kernel = c("gaussian", "epanechnikov"),
  overlap = 1.5,
  fill = "steelblue",
  fillOpacity = 0.8,
  lineCol = "#333333",
  lineWidth = 1,
  sort = c("none", "mean", "median"),
  stat = c("none", "mean", "median"),
  statColor = "#d62728",
  hover = TRUE,
  xtitle = NULL,
  xtitleFontSize = 13,
  title = NULL,
  titleFontSize = 16,
  xFontSize = 11,
  yFontSize = 11,
  font = "Verdana, Geneva, Tahoma, sans-serif",
  bgcol = "white",
  axisCol = "black",
  width = NULL,
  height = NULL
)

Arguments

data

The data frame containing the variables to consider.

x

The name of the numeric column whose distribution is displayed.

group

The name of the categorical column used to split the data into one ridge per group. When the column is a factor, its level order is used (unless sort is set).

bandwidth

Optional. The kernel bandwidth, expressed as the standard deviation of the kernel (as in stats::density()). When NULL (default), a single joint bandwidth is computed from the pooled data with Silverman's rule of thumb (equivalent to stats::bw.nrd0()), so that all ridges are smoothed identically and remain comparable.

kernel

The smoothing kernel, either "gaussian" (default) or "epanechnikov".

overlap

How much each ridge may overlap the one above it, in units of the vertical distance between two consecutive baselines. The tallest peak of the chart reaches exactly overlap baselines up. Defaults to 1.5; use 1 for ridges that just touch and larger values for a more dramatic, Joy Division-like look.

fill

Fill color of the ridges. Either a single color (default "steelblue") applied to every ridge, an unnamed vector of colors recycled over the groups (in their original order), or a named vector whose names match the group values.

fillOpacity

Fill opacity of the ridges (0 to 1). Defaults to 0.8.

lineCol

Color of the density outline. Defaults to "#333333".

lineWidth

Width of the density outline in pixels. Defaults to 1.

sort

How to order the ridges from top to bottom. One of "none" (default, factor level order or order of appearance), "mean", or "median". When sorting, the group with the smallest mean/median is placed at the top.

stat

Character. Draws a vertical line inside each ridge at the "mean" or "median" of its values. Defaults to "none" (no line).

statColor

Color of the mean/median line. Defaults to "#d62728".

hover

Logical. When TRUE (default), hovering a ridge or its label raises and highlights it and shows its number of observations and mean.

xtitle

Optional. Title of the x-axis.

xtitleFontSize

Font size of the x-axis title. Defaults to 13.

title

Optional. Title of the chart.

titleFontSize

Font size of the chart title. Defaults to 16.

xFontSize

Font size of the x-axis tick labels. Defaults to 11.

yFontSize

Font size of the group labels. Defaults to 11.

font

The font family used for all text. Defaults to "Verdana, Geneva, Tahoma, sans-serif".

bgcol

Background color of the SVG. Defaults to "white".

axisCol

Color of axis lines, ticks, and labels. Defaults to "black".

width

Optional. The width of the SVG output.

height

Optional. The height of the SVG output.

Value

An SVG ridgeline plot.

Examples

# Simulated reaction times for five experimental conditions
set.seed(2026)
reaction <- data.frame(
  time = c(rnorm(200, 300, 40), rnorm(200, 340, 50),
           rnorm(200, 380, 35), c(rnorm(100, 360, 25), rnorm(100, 460, 30)),
           rnorm(200, 420, 60)),
  condition = rep(c("Baseline", "Noise", "Fatigue", "Dual task", "Night"),
                  each = 200)
)

ridgeline_plot(
  data   = reaction,
  x      = "time",
  group  = "condition",
  sort   = "mean",
  stat   = "median",
  title  = "Reaction time by condition",
  xtitle = "Reaction time (ms)"
)
# Highway fuel economy by vehicle class library(ggplot2) # for the mpg dataset ridgeline_plot( data = mpg, x = "hwy", group = "class", sort = "median", fill = "#2c7fb8", lineCol = "white", fillOpacity = 0.9, overlap = 2, title = "Highway fuel economy by vehicle class", xtitle = "Highway miles per gallon" )
# One color per group with a named vector, Epanechnikov kernel ridgeline_plot( data = iris, x = "Petal.Length", group = "Species", kernel = "epanechnikov", fill = c(setosa = "#66c2a5", versicolor = "#fc8d62", virginica = "#8da0cb"), overlap = 1, stat = "mean", xtitle = "Petal length (cm)" )