Violin Plot
Ridgeline Violin Plot
Elegant overlapping distributions with gradient colors and trend line
Output
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
# Data
np.random.seed(42)
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August']
data = [np.random.normal(5 + i * 0.5, 1.2 - i * 0.05, 500) for i in range(len(months))]
# Custom gradient colormap (coral to cyan)
colors_hex = ['#FF6B6B', '#FF8E72', '#FFA07A', '#FFB347',
'#98D8C8', '#7FC8A9', '#52B788', '#40916C']
# Create figure with subtle gradient background
fig, ax = plt.subplots(figsize=(12, 9), facecolor='#FAFBFC')
ax.set_facecolor('#FAFBFC')
spacing = 1.0
overlap = 0.4
for i, (d, month) in enumerate(zip(data, months)):
pos = i * spacing
# Create violin
vp = ax.violinplot([d], positions=[pos], widths=spacing * 2.2,
showmeans=False, showmedians=False, showextrema=False,
vert=False)
for body in vp['bodies']:
vertices = body.get_paths()[0].vertices.copy()
# Clip to create ridgeline effect
vertices[:, 1] = np.clip(vertices[:, 1], pos - 0.05, np.inf)
body.get_paths()[0].vertices = vertices
# Main fill with gradient effect
body.set_facecolor(colors_hex[i])
body.set_edgecolor('none')
body.set_alpha(0.9)
# Add subtle shadow
shadow_vertices = vertices.copy()
shadow_vertices[:, 1] -= 0.08
shadow_vertices[:, 0] += 0.05
ax.fill(shadow_vertices[:, 0], shadow_vertices[:, 1],
color='#000000', alpha=0.03, zorder=i)
# Add white edge glow
ax.plot(vertices[:, 0], vertices[:, 1],
color='white', linewidth=2.5, alpha=0.8, zorder=i+10)
ax.plot(vertices[:, 0], vertices[:, 1],
color=colors_hex[i], linewidth=1, alpha=0.9, zorder=i+11)
# Median marker with glow
median = np.median(d)
ax.scatter(median, pos + 0.15, s=80, c='white', zorder=100,
edgecolor=colors_hex[i], linewidth=2)
# Value annotation
ax.text(median, pos + 0.35, f'{median:.1f}', fontsize=9,
ha='center', va='bottom', color='#374151', fontweight='500')
# Month labels with custom styling
for i, month in enumerate(months):
ax.text(-0.8, i * spacing + 0.1, month, fontsize=11, fontweight='600',
color='#1F2937', ha='right', va='center')
# Remove default ticks
ax.set_yticks([])
ax.set_yticklabels([])
# X-axis styling
ax.set_xlabel('Temperature Distribution (°C)', fontsize=13, fontweight='500',
color='#374151', labelpad=15)
ax.set_xlim(-1.5, 12)
ax.set_ylim(-0.5, len(months) * spacing + 0.5)
# Minimal spines
for spine in ax.spines.values():
spine.set_visible(False)
# Subtle vertical grid
for x in range(0, 12, 2):
ax.axvline(x, color='#E5E7EB', linewidth=0.8, alpha=0.5, zorder=0)
# X-axis ticks
ax.set_xticks(range(0, 12, 2))
ax.tick_params(axis='x', colors='#9CA3AF', labelsize=10, length=0, pad=8)
# Add subtle trend line
medians = [np.median(d) for d in data]
positions = [i * spacing + 0.15 for i in range(len(months))]
ax.plot(medians, positions, color='#6366F1', linewidth=2, alpha=0.4,
linestyle='--', zorder=50)
plt.tight_layout()
plt.show()
Library
Matplotlib
Category
Statistical
More Violin Plot examples
☕