Skip to contents

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 sort is set). Defaults to NULL (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. When NULL (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 to FALSE.

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. Use 0 to 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.

Value

An SVG violin plot.

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