Violin Plot
Production Line Efficiency
Cycle time distribution showing automation impact
Output
Python
import matplotlib.pyplot as plt
import numpy as np
# Cycle time data (minutes) by production line
np.random.seed(42)
lines = ['Line A\n(Legacy)', 'Line B\n(Upgraded)', 'Line C\n(New)', 'Line D\n(Automated)', 'Line E\n(AI-Optimized)']
cycle_times = [
np.random.gamma(8, 2, 200) + 10, # Legacy - slow, variable
np.random.gamma(6, 1.8, 200) + 8, # Upgraded
np.random.gamma(5, 1.5, 200) + 6, # New
np.random.gamma(4, 1.2, 200) + 4, # Automated
np.random.gamma(3, 1, 200) + 3, # AI-optimized
]
# Efficiency gradient colors
colors = ['#EF4444', '#F97316', '#EAB308', '#22C55E', '#10B981']
# Create industrial theme
fig, ax = plt.subplots(figsize=(12, 7), facecolor='#F8FAFC')
ax.set_facecolor('#F8FAFC')
vp = ax.violinplot(cycle_times, positions=range(len(lines)), widths=0.7,
showmeans=False, showmedians=False, showextrema=False)
for i, body in enumerate(vp['bodies']):
body.set_facecolor(colors[i])
body.set_edgecolor('white')
body.set_linewidth(2)
body.set_alpha(0.75)
# Target cycle time
target = 12
ax.axhline(target, color='#3B82F6', linewidth=2, linestyle='--', alpha=0.7)
ax.fill_between([-0.5, 4.5], 0, target, color='#DBEAFE', alpha=0.3, zorder=0)
ax.text(4.55, target - 0.5, 'Target', fontsize=10, color='#3B82F6',
fontweight='500', va='top')
# Metrics
for i, times in enumerate(cycle_times):
median = np.median(times)
cv = np.std(times) / np.mean(times) * 100 # Coefficient of variation
on_target = (times <= target).mean() * 100
# Median
ax.scatter(i, median, c='white', s=100, zorder=10,
edgecolor=colors[i], linewidth=2.5)
# Variability indicator (CV)
cv_color = '#10B981' if cv < 25 else '#F59E0B' if cv < 40 else '#EF4444'
ax.errorbar(i, median, yerr=np.std(times), color=colors[i],
capsize=6, capthick=2, linewidth=0, elinewidth=2, alpha=0.5)
# On-target percentage
ax.text(i, 2, f'{on_target:.0f}%', ha='center', fontsize=11,
color='#10B981' if on_target > 80 else '#F97316',
fontweight='bold')
# Improvement arrows
for i in range(1, len(lines)):
prev_med = np.median(cycle_times[i-1])
curr_med = np.median(cycle_times[i])
improvement = ((prev_med - curr_med) / prev_med) * 100
if improvement > 0:
ax.annotate('', xy=(i - 0.1, curr_med), xytext=(i - 0.9, prev_med),
arrowprops=dict(arrowstyle='->', color='#10B981', lw=1.5, alpha=0.5))
# Label
ax.text(-0.5, 3.5, 'On Target', fontsize=9, color='#6B7280')
# Styling
ax.set_xticks(range(len(lines)))
ax.set_xticklabels(lines, fontsize=10, fontweight='500')
ax.set_ylabel('Cycle Time (minutes)', fontsize=12, fontweight='500', color='#374151')
ax.set_ylim(0, 40)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_color('#E5E7EB')
ax.spines['bottom'].set_color('#E5E7EB')
ax.tick_params(colors='#6B7280', labelsize=10)
ax.yaxis.grid(True, linestyle='--', alpha=0.3, color='#9CA3AF')
plt.tight_layout()
plt.show()
Library
Matplotlib
Category
Statistical
More Violin Plot examples
☕