A violin plot shows the distribution of a numeric variable for one or several groups. Each group is drawn as a mirrored kernel density estimate (the "violin"), so the width of the shape at a given value is proportional to how many observations lie around it. Violin plots reveal features that a box plot hides, such as multi-modality or skewness, while an inner box plot keeps the familiar summary statistics in view. The look and feel is inspired by the violin traces of the Plotly.js library.
The kernel density estimates are computed in the browser with a Gaussian
kernel. By default each violin gets its own bandwidth, computed with
Silverman's rule of thumb (equivalent to stats::bw.nrd0()).
The plot is interactive: hovering a violin dims the others, draws a horizontal spike line at the cursor (with its value tagged on the y-axis) and shows a tooltip with the group's summary statistics (n, min, q1, median, q3, max and mean). Hovering a raw point shows its value.
Usage
violin_plot(
data,
y,
group = NULL,
bandwidth = NULL,
span = c("soft", "hard"),
scale = c("width", "count"),
box = TRUE,
meanline = FALSE,
points = c("outliers", "all", "none"),
jitter = 0.6,
pointRadius = 2.5,
pointOpacity = 0.7,
sort = c("none", "mean", "median"),
colorPalette = "Category10",
fillOpacity = 0.5,
lineWidth = 1.5,
violinWidth = 0.8,
hover = TRUE,
animate = TRUE,
ytitle = NULL,
ytitleFontSize = 13,
xtitle = NULL,
xtitleFontSize = 13,
title = NULL,
titleFontSize = 16,
xFontSize = 11,
yFontSize = 11,
font = "Verdana, Geneva, Tahoma, sans-serif",
bgcol = "white",
axisCol = "black",
gridCol = "#e6e6e6",
width = NULL,
height = NULL
)Arguments
- data
The data frame containing the variables to consider.
- y
The name of the numeric column whose distribution is displayed.
- group
Optional. The name of a categorical column used to split the data into one violin per group. When the column is a factor, its level order is used (unless
sortis set). Defaults toNULL(a single violin).- bandwidth
Optional. The kernel bandwidth, expressed as the standard deviation of the Gaussian kernel (as in
stats::density()), applied to every violin. WhenNULL(default), each violin uses its own bandwidth computed with Silverman's rule of thumb.- span
How far the density extends.
"soft"(default) extends each violin two bandwidths beyond its minimum and maximum so the tails fade out smoothly;"hard"cuts the violin at the observed minimum and maximum.- scale
How the violin widths are scaled.
"width"(default) gives every violin the same maximum width;"count"makes the width proportional to the number of observations, so larger groups look larger.- box
Logical. When
TRUE(default), an inner box plot is drawn inside each violin: a box from the first to the third quartile, a white median line, and whiskers reaching the most extreme values within 1.5 IQR.- meanline
Logical. When
TRUE, a dashed line is drawn across each violin at the mean. Defaults toFALSE.- points
Which raw observations to draw on top of the violins:
"outliers"(default, values beyond the whiskers),"all", or"none".- jitter
Horizontal spread of the points, as a fraction (0 to 1) of the violin's width at the point's value. Points therefore always stay inside their violin. Defaults to
0.6. Use0to align them on the center line.- pointRadius
Radius of the points in pixels. Defaults to
2.5.- pointOpacity
Fill opacity of the points (0 to 1). Defaults to
0.7.- sort
How to order the violins from left to right. One of
"none"(default, factor level order or order of appearance),"mean", or"median"(ascending).- colorPalette
The violin colors. Either the name of a D3 categorical color scheme (e.g.
"Category10", the default, which is also Plotly's classic colorway,"Tableau10","Set2"), a single color applied to every violin, 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 violins (0 to 1). Defaults to
0.5.- lineWidth
Width of the violin outline in pixels. Defaults to
1.5.- violinWidth
Maximum width of a violin, as a fraction (0 to 1] of the space allotted to each group. Defaults to
0.8.- hover
Logical. When
TRUE(default), hovering a violin highlights it and shows a tooltip with its summary statistics.- animate
Logical. When
TRUE(default), the violins grow from their center line and the points fade in on first render.- ytitle
Optional. Title of the y-axis.
- ytitleFontSize
Font size of the y-axis title. Defaults to
13.- 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 group labels. Defaults to
11. Labels are rotated automatically when they do not fit.- yFontSize
Font size of the y-axis tick 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".- gridCol
Color of the horizontal grid lines. Defaults to
"#e6e6e6". Use"none"to hide them.- width
Optional. The width of the SVG output.
- height
Optional. The height of the SVG output.
Examples
# Sepal length by species, with the inner box plot and outliers
violin_plot(
data = iris,
y = "Sepal.Length",
group = "Species",
title = "Sepal length by species",
ytitle = "Sepal length (cm)"
)
# Every observation jittered inside its violin, plus a mean line
library(ggplot2) # for the mpg dataset
violin_plot(
data = mpg,
y = "hwy",
group = "class",
points = "all",
meanline = TRUE,
sort = "median",
colorPalette = "Tableau10",
title = "Highway fuel economy by vehicle class",
ytitle = "Highway miles per gallon"
)
# A bimodal distribution, width proportional to group size, hard span
set.seed(2026)
waiting <- data.frame(
minutes = c(rnorm(300, 55, 6), rnorm(200, 80, 5),
rnorm(150, 70, 10), rnorm(60, 62, 4)),
station = rep(c("North", "Central", "South"), c(500, 150, 60))
)
violin_plot(
data = waiting,
y = "minutes",
group = "station",
scale = "count",
span = "hard",
colorPalette = c(North = "#636efa", Central = "#ef553b",
South = "#00cc96"),
title = "Waiting time by station",
ytitle = "Minutes",
xtitle = "Station"
)
# A single violin with a custom bandwidth
violin_plot(
data = faithful,
y = "eruptions",
bandwidth = 0.2,
colorPalette = "#9467bd",
points = "all",
ytitle = "Eruption time (min)"
)