ANOVA Violin Plot

Customer Satisfaction Channel ANOVA

Comparing CSAT scores across different customer service channels.

Output
Customer Satisfaction Channel ANOVA
Python
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats

np.random.seed(1818)

# CSAT scores (1-10)
phone = np.random.normal(7.2, 1.5, 200)
email = np.random.normal(6.5, 1.8, 200)
chat = np.random.normal(7.8, 1.3, 200)
social = np.random.normal(6.0, 2.0, 200)
self_service = np.random.normal(7.5, 1.4, 200)

# Clip to valid range
phone = np.clip(phone, 1, 10)
email = np.clip(email, 1, 10)
chat = np.clip(chat, 1, 10)
social = np.clip(social, 1, 10)
self_service = np.clip(self_service, 1, 10)

F_stat, p_value = stats.f_oneway(phone, email, chat, social, self_service)

fig, ax = plt.subplots(figsize=(13, 7), facecolor='#ffffff')
ax.set_facecolor('#ffffff')

colors = ['#4927F5', '#F5B027', '#27F5B0', '#F5276C', '#27D3F5']

parts = ax.violinplot([phone, email, chat, social, self_service], 
                       positions=[1, 2, 3, 4, 5], showmeans=True, showmedians=True, widths=0.7)

for i, pc in enumerate(parts['bodies']):
    pc.set_facecolor(colors[i])
    pc.set_alpha(0.6)
    pc.set_edgecolor(colors[i])
    pc.set_linewidth(2)

parts['cmeans'].set_color('#C82909')
parts['cmeans'].set_linewidth(2.5)
parts['cmedians'].set_color('#1f2937')
for partname in ['cbars', 'cmins', 'cmaxes']:
    parts[partname].set_color('#9ca3af')

# Target satisfaction
ax.axhline(y=8.0, color='#22c55e', linestyle='--', alpha=0.7, linewidth=1.5)
ax.text(5.45, 8.0, 'Target', fontsize=8, color='#22c55e', va='center')

# Zones
ax.axhspan(8, 10, alpha=0.08, color='#22c55e')

labels = ['Phone', 'Email', 'Chat', 'Social', 'Self-Svc']

# NPS at bottom
nps_scores = [42, 28, 55, 15, 48]
response_times = ['8min', '24h', '2min', '4h', 'instant']
for i, (nps, rt, color) in enumerate(zip(nps_scores, response_times, colors)):
    ax.text(i+1, 0.5, f'NPS:{nps} | {rt}', ha='center', fontsize=8, color=color)

# Stats at top
stats_text = f"ANOVA: F={F_stat:.2f}, p={p_value:.2e} | Top: Live Chat (μ={chat.mean():.2f})"
bbox = dict(boxstyle="round,pad=0.3", facecolor='#ecfdf5', edgecolor='#27F5B0', lw=2)
ax.text(0.5, 1.02, stats_text, transform=ax.transAxes, fontsize=9, color='#1f2937',
        ha='center', va='bottom', fontfamily='monospace', bbox=bbox)

ax.set_xticks([1, 2, 3, 4, 5])
ax.set_xticklabels(labels, fontsize=10, color='#1f2937')
ax.set_ylabel('CSAT Score (1-10)', fontsize=12, color='#1f2937', fontweight='500')
ax.set_title('Customer Satisfaction by Service Channel\nQ4 2024 Support Metrics', 
             fontsize=14, color='#1f2937', fontweight='bold', pad=25)

ax.tick_params(colors='#374151')
for spine in ax.spines.values():
    spine.set_color('#e5e7eb')
ax.yaxis.grid(True, color='#f3f4f6', linewidth=0.8)
ax.set_axisbelow(True)
ax.set_ylim(0, 11)

plt.tight_layout()
plt.show()
Library

Matplotlib

Category

Statistical

Did this help you?

Support PyLucid to keep it free & growing

Support