Violin Plot

Drug Efficacy Clinical Trial

Time to symptom relief distribution across treatment phases

Output
Drug Efficacy Clinical Trial
Python
import matplotlib.pyplot as plt
import numpy as np

# Time to symptom relief (hours)
np.random.seed(42)
treatments = ['Placebo', 'Standard\nCare', 'New Drug\n(Phase II)', 'New Drug\n(Phase III)']
relief_times = [
    np.random.exponential(24, 200) + 12,      # Placebo - slow
    np.random.gamma(4, 4, 200) + 6,           # Standard - moderate
    np.random.gamma(6, 2, 200) + 2,           # Phase II - faster
    np.random.gamma(8, 1.5, 200) + 1,         # Phase III - optimized
]

# Clip for visualization
relief_times = [np.clip(r, 0, 72) for r in relief_times]

# Colors
colors = ['#9CA3AF', '#F59E0B', '#8B5CF6', '#10B981']

# Create figure
fig, ax = plt.subplots(figsize=(11, 7), facecolor='white')

vp = ax.violinplot(relief_times, positions=range(len(treatments)), 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 time (clinical goal)
target_time = 12
ax.axhline(target_time, color='#10B981', linewidth=2, linestyle='--', alpha=0.7)
ax.fill_between([-0.5, 3.5], 0, target_time, color='#D1FAE5', alpha=0.3, zorder=0)
ax.text(3.55, target_time - 1, 'Target Zone', fontsize=9, color='#10B981', 
        fontweight='500', va='top')

# Add efficacy metrics
for i, times in enumerate(relief_times):
    median = np.median(times)
    pct_target = (times <= target_time).mean() * 100
    
    # Median marker
    ax.scatter(i, median, c='white', s=100, zorder=10,
               edgecolor=colors[i], linewidth=2.5)
    
    # Efficacy badge
    badge_color = '#10B981' if pct_target > 50 else '#F59E0B' if pct_target > 25 else '#EF4444'
    ax.annotate(f'{pct_target:.0f}%\neffective', xy=(i, 68),
                ha='center', fontsize=9, fontweight='bold', color=badge_color,
                bbox=dict(boxstyle='round,pad=0.4', facecolor='white',
                         edgecolor=badge_color, linewidth=1.5))

# Styling
ax.set_xticks(range(len(treatments)))
ax.set_xticklabels(treatments, fontsize=10, fontweight='500')
ax.set_ylabel('Time to Relief (hours)', fontsize=12, fontweight='500', color='#374151')
ax.set_ylim(0, 75)

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')

# Invert y-axis (lower is better)
ax.invert_yaxis()

plt.tight_layout()
plt.show()
Library

Matplotlib

Category

Statistical

Did this help you?

Support PyLucid to keep it free & growing

Support