Skip to content

Matplotlib - Violin Plot

Violin plots are a powerful visualization method that combines aspects of a box plot with a kernel density estimation (KDE) plot. They are used to visualize the distribution of numerical data and are particularly effective for comparing distributions across different categories.

Key features of a violin plot:

  • Density Estimation: The main body of the violin is a KDE plot, mirrored on both sides. The width of the violin at a particular value indicates the estimated density or frequency of data points around that value.
  • Box Plot Elements (Optional): Often, a miniature box plot or related markers are drawn inside the violin. This typically includes: - A marker for the median. - A box indicating the interquartile range (IQR: Q1 to Q3). - Sometimes lines (whiskers) extending to a certain range (though less common than in standard box plots).

Compared to a plain box plot, a violin plot provides a much richer understanding of the data’s distribution, revealing features like multimodality (multiple peaks) that are hidden by the summary statistics of a box plot.

The ax.violinplot() method in Matplotlib creates violin plots.

ax.violinplot(dataset, positions=None, showmeans=False, showextrema=True, showmedians=False, **kwargs)
  • dataset: A list or sequence of arrays/vectors. Each element corresponds to one violin.
  • positions: Array-like. Sets the horizontal positions of the violins (defaults to [1, 2, 3, ...]).
  • showmeans: Boolean. If True, renders markers for the mean values.
  • showextrema: Boolean. If True (default), renders lines for the data extrema.
  • showmedians: Boolean. If True, renders markers for the median values.
  • quantiles: Array-like between 0 and 1. If set (e.g., [0.25, 0.75]), renders lines inside the violin for the specified quantiles (often used instead of a full box plot).
  • bw_method: String or float. Method for calculating the estimator bandwidth for the KDE (affects smoothness).
  • vert: Boolean. If True (default), creates vertical violins. If False, creates horizontal violins.

Example: Comparing distributions using violin plots.

import matplotlib.pyplot as plt
import numpy as np
# 1. Generate sample data (e.g., distributions with different shapes)
np.random.seed(10)
dist1_normal = np.random.normal(100, 10, 200)
dist2_skewed = np.random.gamma(6, 15, 200) # Skewed distribution
dist3_bimodal = np.concatenate([
np.random.normal(60, 10, 100),
np.random.normal(110, 10, 100)
]) # Two peaks
dist4_uniform = np.random.uniform(70, 130, 200)
# Combine datasets into a list
data_to_plot = [dist1_normal, dist2_skewed, dist3_bimodal, dist4_uniform]
labels = ['Normal', 'Skewed', 'Bimodal', 'Uniform']
# 2. Create the plot
fig, ax = plt.subplots(figsize=(10, 6))
# 3. Create the violin plot
# Show medians and quantiles (Q1, Q3) instead of default box/extrema
parts = ax.violinplot(data_to_plot,
showmeans=False,
showmedians=True,
quantiles=[[0.25, 0.75]] * len(data_to_plot) # Pass list of lists for quantiles
)
# 4. Customize appearance (optional)
colors = ['lightblue', 'lightgreen', 'lightcoral', 'lightsalmon']
for pc, color in zip(parts['bodies'], colors):
pc.set_facecolor(color)
pc.set_edgecolor('black')
pc.set_alpha(0.7)
# Customize median lines
parts['cmedians'].set_colors('red')
parts['cmedians'].set_linewidth(2)
# Customize quantile lines (if shown)
if 'cquantiles' in parts:
parts['cquantiles'].set_colors('black')
parts['cquantiles'].set_linestyles(':')
parts['cquantiles'].set_linewidth(1.5)
# Customize other parts (cbars for mean/extrema if shown, cmins, cmaxes)
# 5. Add labels and title
ax.set_title('Comparison of Data Distributions using Violin Plots')
ax.set_ylabel('Value')
ax.set_xticks(np.arange(1, len(labels) + 1)) # Set positions for labels
ax.set_xticklabels(labels)
ax.yaxis.grid(True)
plt.show()

This example generates data with different distribution shapes (normal, skewed, bimodal, uniform) and visualizes them using ax.violinplot. By showing the median and quantiles (representing the IQR), and observing the shape of the violin (the KDE), we get a much clearer picture of each distribution’s characteristics compared to just using a box plot.