Raincloud Plot
Clinical Drug Efficacy Raincloud
Comparing treatment response rates across clinical trial arms.
Output
Python
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
np.random.seed(777)
# Response score (0-100)
placebo = np.random.normal(35, 12, 100)
low_dose = np.random.normal(52, 14, 95)
high_dose = np.random.normal(68, 11, 90)
placebo = np.clip(placebo, 5, 70)
low_dose = np.clip(low_dose, 20, 85)
high_dose = np.clip(high_dose, 40, 95)
F_stat, p_value = stats.f_oneway(placebo, low_dose, high_dose)
BG_COLOR = "#0d1117"
COLOR_SCALE = ["#888888", "#F5B027", "#6CF527"]
fig, ax = plt.subplots(figsize=(13, 10), facecolor=BG_COLOR)
ax.set_facecolor(BG_COLOR)
y_data = [placebo, low_dose, high_dose]
positions = [0, 1, 2]
labels = ["Placebo", "Low Dose\n(50mg)", "High Dose\n(100mg)"]
for h in [30, 50, 70]:
ax.axhline(h, color='#333333', ls=(0, (5, 5)), alpha=0.5, zorder=0)
# Efficacy threshold
ax.axhline(y=50, color='#22c55e', ls='--', alpha=0.7, lw=2)
ax.text(2.55, 50, "Clinical\nThreshold", color='#22c55e', fontsize=9, va='center')
violins = ax.violinplot(y_data, positions=positions, widths=0.5,
bw_method="silverman", showmeans=False,
showmedians=False, showextrema=False)
for pc in violins["bodies"]:
pc.set_facecolor("none")
pc.set_edgecolor("#27D3F5")
pc.set_linewidth(2)
bp = ax.boxplot(y_data, positions=positions, showfliers=False, showcaps=False,
medianprops=dict(linewidth=3, color='white'),
whiskerprops=dict(linewidth=2, color='#555555'),
boxprops=dict(linewidth=2, color='#555555'))
for i, (y, color) in enumerate(zip(y_data, COLOR_SCALE)):
x_jitter = np.array([i] * len(y)) + stats.t(df=6, scale=0.045).rvs(len(y))
ax.scatter(x_jitter, y, s=55, color=color, alpha=0.55, zorder=2)
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.32], [mean, mean], ls="dashdot", color="white", zorder=3, lw=1.5)
ax.text(i + 0.34, mean, f"μ={mean:.1f}", fontsize=11, va="center", color='white',
bbox=dict(facecolor=BG_COLOR, edgecolor=color, boxstyle="round,pad=0.2", lw=2))
# P-value brackets
tick = 3
ax.plot([0, 0, 1, 1], [88-tick, 88, 88, 88-tick], c="white", lw=1.5)
ax.text(0.5, 90, "p<0.001***", fontsize=10, va="bottom", ha="center", color='#F5D327')
ax.plot([0, 0, 2, 2], [95-tick, 95, 95, 95-tick], c="white", lw=1.5)
ax.text(1, 97, "p<0.001***", fontsize=10, va="bottom", ha="center", color='#F5D327')
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["left"].set_color('#444444')
ax.spines["bottom"].set_color('#444444')
ax.tick_params(colors='#888888', length=0)
ax.set_xticks(positions)
ax.set_xticklabels(labels, size=11, color='white')
ax.set_ylabel("Treatment Response Score", size=14, color='white', fontweight='bold')
ax.set_title("Clinical Drug Efficacy Trial Results", fontsize=14, color="white", fontweight="bold", pad=20)
ax.set_ylim(0, 105)
plt.tight_layout()
plt.show()
Library
Matplotlib
Category
Statistical
More Raincloud Plot examples
☕