Raincloud Plot
Programming Language Benchmark Raincloud
Elegant comparison of execution times across programming languages with statistical annotations.
Output
Python
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
np.random.seed(42)
# Execution time in milliseconds for a benchmark task
python_times = np.random.lognormal(4.5, 0.4, 80)
java_times = np.random.lognormal(3.2, 0.35, 85)
rust_times = np.random.lognormal(2.0, 0.3, 75)
python_times = np.clip(python_times, 30, 400)
java_times = np.clip(java_times, 10, 100)
rust_times = np.clip(rust_times, 3, 30)
# ANOVA
F_stat, p_value = stats.f_oneway(python_times, java_times, rust_times)
# Colors
BG_COLOR = "#0a0a0f"
GREY_LIGHT = "#444444"
COLOR_SCALE = ["#F5276C", "#27D3F5", "#6CF527"]
fig, ax = plt.subplots(figsize=(10, 6), facecolor=BG_COLOR)
ax.set_facecolor(BG_COLOR)
y_data = [python_times, java_times, rust_times]
positions = [0, 1, 2]
labels = ["Python", "Java", "Rust"]
# Horizontal reference lines
for h in [50, 100, 200, 300]:
ax.axhline(h, color=GREY_LIGHT, ls=(0, (5, 5)), alpha=0.5, zorder=0)
# Violins
violins = ax.violinplot(y_data, positions=positions, widths=0.45,
bw_method="silverman", showmeans=False,
showmedians=False, showextrema=False)
for pc in violins["bodies"]:
pc.set_facecolor("none")
pc.set_edgecolor("white")
pc.set_linewidth(1.8)
pc.set_alpha(0.9)
# Boxplots
bp = ax.boxplot(y_data, positions=positions, showfliers=False, showcaps=False,
medianprops=dict(linewidth=3, color='#F5D327'),
whiskerprops=dict(linewidth=2, color='#888888'),
boxprops=dict(linewidth=2, color='#888888'))
# Jittered points
for i, (y, color) in enumerate(zip(y_data, COLOR_SCALE)):
x_jitter = np.array([i] * len(y)) + stats.t(df=6, scale=0.04).rvs(len(y))
ax.scatter(x_jitter, y, s=60, color=color, alpha=0.5, zorder=2)
# Mean annotations
means = [y.mean() for y in y_data]
for i, (mean, color) in enumerate(zip(means, COLOR_SCALE)):
ax.scatter(i, mean, s=200, color='#C82909', zorder=5, edgecolors='white', linewidths=2)
ax.plot([i, i + 0.3], [mean, mean], ls="dashdot", color="white", zorder=3, lw=1.5)
ax.text(i + 0.32, mean, f"μ = {mean:.1f}ms", fontsize=11, va="center", color='white',
bbox=dict(facecolor=BG_COLOR, edgecolor=color, boxstyle="round,pad=0.2", lw=2), zorder=10)
# Comparison brackets
tick_len = 8
# Python vs Java
ax.plot([0, 0, 1, 1], [380-tick_len, 380, 380, 380-tick_len], c="white", lw=1.5)
ax.text(0.5, 385, "p < 0.001 ***", fontsize=10, va="bottom", ha="center", color='#F5D327')
# Python vs Rust
ax.plot([0, 0, 2, 2], [410-tick_len, 410, 410, 410-tick_len], c="white", lw=1.5)
ax.text(1, 415, "p < 0.001 ***", fontsize=10, va="bottom", ha="center", color='#F5D327')
# Styling
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["left"].set_color(GREY_LIGHT)
ax.spines["bottom"].set_color(GREY_LIGHT)
ax.tick_params(colors='#888888', length=0)
xlabels = [f"{l}\n(n={len(y_data[i])})" for i, l in enumerate(labels)]
ax.set_xticks(positions)
ax.set_xticklabels(xlabels, size=12, color='white')
ax.set_ylabel("Execution Time (ms)", size=14, color='white', fontweight='bold')
# Title with stats
ax.set_title("Programming Language Performance Benchmark", fontsize=14, color="white", fontweight="bold", pad=20)
ax.text(0.5, -0.12, "F-Welch={F_stat:.1f}, p={p_value:.2e}, ω²=0.89, n=240", transform=ax.transAxes, fontsize=10, color="#6b7280", ha="center")
ax.set_ylim(0, 450)
plt.tight_layout()
plt.show()
Library
Matplotlib
Category
Statistical
More Raincloud Plot examples
☕