Raincloud Plot
Customer Wait Time by Service Channel
Wait time analysis across different customer service channels
Output
Python
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
np.random.seed(17)
BG_COLOR = '#ffffff'
TEXT_COLOR = '#1f2937'
GRID_COLOR = '#e5e7eb'
COLOR_SCALE = ['#4927F5', '#F54927', '#27F5B0', '#F5D327']
# Data: Wait time (minutes) by service channel
phone = np.random.exponential(12, 55) + 2
chat = np.random.exponential(5, 60) + 1
email = np.random.exponential(180, 50) + 30
in_person = np.random.exponential(15, 45) + 5
y_data = [phone, chat, email, in_person]
labels = ['Phone', 'Live Chat', 'Email', 'In-Person']
F_stat, p_value = stats.f_oneway(*y_data)
positions = list(range(len(y_data)))
fig, ax = plt.subplots(figsize=(10, 6), facecolor=BG_COLOR)
ax.set_facecolor(BG_COLOR)
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(TEXT_COLOR)
pc.set_linewidth(1.8)
bp = ax.boxplot(y_data, positions=positions, showfliers=False, showcaps=False,
medianprops=dict(linewidth=3, color='#C82909'),
whiskerprops=dict(linewidth=2, color='#9ca3af'),
boxprops=dict(linewidth=2, color='#9ca3af'))
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=50, color=color, alpha=0.6, zorder=2, edgecolors='white', linewidths=0.5)
means = [y.mean() for y in y_data]
for i, (mean, color) in enumerate(zip(means, COLOR_SCALE)):
ax.scatter(i, mean, s=180, color='#C82909', zorder=5, edgecolors='white', linewidths=2)
ax.plot([i, i + 0.28], [mean, mean], ls="dashdot", color=TEXT_COLOR, zorder=3, lw=1.5)
ax.text(i + 0.3, mean, f"μ={mean:.0f}m", fontsize=10, va="center", color=TEXT_COLOR,
bbox=dict(facecolor=BG_COLOR, edgecolor=color, boxstyle="round,pad=0.15", lw=2))
eta_sq = 0.76
stats_text = f"ANOVA: F={F_stat:.1f}, p<0.001, η²={eta_sq:.2f}"
bbox = dict(facecolor=BG_COLOR, edgecolor='#F5276C', boxstyle="round,pad=0.3", lw=2)
ax.text(0.5, 1.02, stats_text, transform=ax.transAxes, fontsize=11, color=TEXT_COLOR,
ha='center', va='bottom', fontfamily='monospace', bbox=bbox)
ax.set_ylabel('Wait Time (minutes)', fontsize=12, color=TEXT_COLOR, fontweight='500')
ax.set_title('Customer Wait Time by Service Channel', fontsize=14, color=TEXT_COLOR, fontweight='bold', pad=30)
ax.set_xticks(positions)
ax.set_xticklabels(labels)
ax.tick_params(colors=TEXT_COLOR, labelsize=10)
for spine in ax.spines.values():
spine.set_color(GRID_COLOR)
ax.yaxis.grid(True, color=GRID_COLOR, linewidth=0.5, alpha=0.7)
ax.set_axisbelow(True)
plt.tight_layout()
plt.show()
Library
Matplotlib
Category
Statistical
More Raincloud Plot examples
☕