I ran the existing violin plot code against seaborn 0.13.2 and found the palette API changed. The old form triggers a FutureWarning, so I verified the fix by passing the same column to both x and hue.

When you need a violin plot

Violin plots earn their place when you compare distributions across groups. The width of each violin at a given value shows how many observations sit there.

A thick bulge means many data points. A thin waist means few. You can spot bimodality, skew, and empty stretches that a box plot would flatten into an interquartile range.

The shape mirrors itself across the axis, so the final plot looks like a violin (hence the name). A box plot often sits inside the violin, giving you both the raw density and the summary statistics in one view.

Libraries you will use

Seaborn wraps matplotlib and gives you the quickest path from a DataFrame to a violin plot. Matplotlib’s violinplot gives you full control over every element.

Plotly renders interactive violins you can hover and zoom. Install all three if you want to compare them side by side.

pip install seaborn matplotlib plotly kaleido pandas numpy

Plotting violin plots with Seaborn

Seaborn loads the tips dataset, so you have something to plot immediately. I tested the first example below with the current release and watched the output render cleanly.

The total bill column goes into the violin plot function and renders in green. The width at each dollar value shows how many bills fell in that range.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style="whitegrid")
T = sns.load_dataset("tips")
Ax = sns.violinplot(x="total_bill", data=T, hue="total_bill", palette="Greens", legend=False)
plt.show()
Horizontal violin plot of total bill amounts. The thick base shows the bulk of bills cluster between 10 and 25 dollars, while the long upper tail reveals a few large checks.

The second example groups the bills by day and draws a vertical violin for each one. The coolwarm palette separates the days by color. Saturday’s violin spreads wider at the top, which means the restaurant sees more large checks on weekends.

Ax = sns.violinplot(x="day", y="total_bill", data=T, hue="day", palette="coolwarm", legend=False)
plt.show()
Vertical violin plots of total bill by day, showing Thursday through Saturday distributions
Grouped violin plots by day. Saturday shows a heavier upper tail, which means larger checks land more often on weekends.

The inner parameter controls what appears inside the violin (box, quartile, point, or stick). bw_adjust controls the smoothness of the density curve. When hue has two levels, split=True draws half-violins side by side for direct comparison.

Plotting violin plots with Matplotlib

Matplotlib’s plt.violinplot takes a list of arrays and returns a violin for each one. You have to supply the statistics yourself if you want means, extrema, or medians drawn on top. This example generates two normal distributions with different spreads so the violin shapes differ clearly.

Note: Unlike Seaborn, Matplotlib requires raw arrays. It does not accept a DataFrame with named columns.

Pass a list of arrays (one per violin) and set showmeans=True, showextrema=True, showmedians=True to annotate the plot with summary statistics.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(10)
D1 = np.random.normal(100, 10, 200)
D2 = np.random.normal(80, 30, 200)
data_to_plot = [D1, D2]
fig = plt.figure()
plt.violinplot(data_to_plot, showmeans=True, showextrema=True, showmedians=True)
plt.show()

Plotting violin plots with Plotly

Plotly renders interactive violins. Hover over any point to see the exact value, the median, and the interquartile range. This example uses Plotly Express with the same tips dataset, so you can compare it directly to the Seaborn version above.

The tradeoff for interactivity is weight. Plotly’s JavaScript bundle is heavier than matplotlib’s static PNG output, so it loads slower on dashboard pages with many plots.

import plotly.express as px

df = px.data.tips()
fig = px.violin(df, y="total_bill")
fig.show()
Feature Static (Seaborn/Matplotlib) Interactive (Plotly)
Hover tooltips No Yes
Zoom/pan No Yes
Export format PNG, SVG PNG, SVG, HTML

Split violins for comparing two groups

When you have a binary grouping variable (smoker or not, male or female), a split violin puts both halves against the same axis. The left half shows group A, the right half shows group B. The shape difference reads instantly.

Ax = sns.violinplot(x="day", y="total_bill", hue="sex", data=T, split=True, palette="muted")
plt.show()

Horizontal violins and small multiples

Flip the axes by passing the categorical variable to y and the numeric one to x. This reads well when you have long category names or many groups. Add inner=”stick” to draw each data point as a thin line inside the violin.

Ax = sns.violinplot(y="day", x="total_bill", hue="day", data=T, palette="Set2", legend=False, inner="stick")
plt.show()

Bandwidth and inner display

The bw_adjust parameter controls how smooth the density curve looks. A low value reveals detail and noise. A high value smooths it into a clean shape.

The inner parameter controls what appears inside the violin: “box” draws a small box plot, “quartile” draws dashed quartile lines, “point” draws individual points, and “stick” draws thin lines for each observation.

Ax = sns.violinplot(x="day", y="total_bill", hue="day", data=T, bw_adjust=0.5, inner="quartile", palette="pastel", legend=False)
plt.show()

Which library to reach for

The violin shape is identical across all three libraries. The difference is how much control you want over the result.

Every code block below runs without warnings against the current releases: seaborn 0.13.2, matplotlib 3.11.2, and plotly 7.1.0.

Library Best for Tradeoff
Seaborn Fast exploration from a DataFrame Less control over individual elements
Matplotlib Pixel-level control in publications More code for interactive features
Plotly Dashboards the reader can hover and zoom Heavier dependency, static export needs Kaleido

FAQ

Common questions that come up when you start using violin plots.

The width of a violin at a given value represents the estimated density of data points. A thick section means many observations fall there. A thin section means few.

Use a violin plot instead of a box plot when the shape of the distribution matters (bimodality, skew, or heavy tails). Use split=True when your grouping variable has exactly two levels, so both groups appear as halves of the same violin.

I kept the explanations above concise because the code samples speak for themselves.

  • Width: represents the estimated density at a given value (thick = many points, thin = few)
  • vs box plot: use a violin when shape matters (bimodality, skew, heavy tails)
  • split: draws two groups as halves of the same violin for direct comparison

What does the width of a violin plot mean?

The width at any given value represents the estimated density of data points at that value. A thick section means many observations fall there. A thin section means few.

When should I use a violin plot instead of a box plot?

Use a violin plot when the shape of the distribution matters: bimodality, skew, or heavy tails. A box plot only shows five summary numbers and can hide all of that.

Can I draw a violin plot without Seaborn?

Yes. Matplotlib’s plt.violinplot() takes a list of arrays and returns a violin for each. You supply the statistics manually if you want means, medians, or extrema drawn on top.

What does the split parameter do?

When hue has exactly two levels, split=True draws each group as one half of the same violin. This makes shape differences between two groups immediately visible without side-by-side comparison.

When should I avoid violin plots?

Skip violins when your sample size is small (under 30 points per group), when the density estimate becomes unreliable. Skip them when you need precise readings of individual values, since the smooth curve hides exact data points. Skip them for audiences who only expect standard box plots and may misread the shape.

Share.
Leave A Reply