Violin Plot

Clinical Trial Drug Response

Biomarker reduction distribution with therapeutic threshold and response rates

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

# Clinical trial response data
np.random.seed(42)
treatments = ['Placebo', 'Drug A\n(10mg)', 'Drug A\n(25mg)', 'Drug A\n(50mg)', 'Drug B\n(25mg)']
# Simulating biomarker reduction (higher = better)
responses = [
    np.random.normal(5, 8, 150),           # Placebo
    np.random.normal(15, 10, 150),         # Drug A low
    np.random.normal(28, 12, 150),         # Drug A mid
    np.random.normal(35, 15, 150),         # Drug A high
    np.random.normal(32, 9, 150),          # Drug B
]

# Clinical threshold
therapeutic_threshold = 20

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

# Color palette
colors = ['#9CA3AF', '#93C5FD', '#60A5FA', '#3B82F6', '#8B5CF6']

vp = ax.violinplot(responses, 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)

# Add response rate annotation (% above threshold)
for i, resp in enumerate(responses):
    response_rate = (resp >= therapeutic_threshold).mean() * 100
    median = np.median(resp)
    
    # Median marker
    ax.scatter(i, median, c='white', s=100, zorder=10,
               edgecolor=colors[i], linewidth=2.5)
    
    # Response rate box
    ax.annotate(f'{response_rate:.0f}%', xy=(i, 55),
                ha='center', fontsize=11, fontweight='bold',
                color='#10B981' if response_rate > 50 else '#6B7280',
                bbox=dict(boxstyle='round,pad=0.3', facecolor='white',
                         edgecolor='#E5E7EB'))

# Therapeutic threshold line
ax.axhline(therapeutic_threshold, color='#10B981', linewidth=2, 
           linestyle='--', alpha=0.8, zorder=0)
ax.text(4.6, therapeutic_threshold + 1, 'Therapeutic\nThreshold', 
        fontsize=9, color='#10B981', fontweight='500', va='bottom')

# Styling
ax.set_xticks(range(len(treatments)))
ax.set_xticklabels(treatments, fontsize=10, fontweight='500')
ax.set_ylabel('Biomarker Reduction (%)', fontsize=12, fontweight='500', color='#374151')
ax.set_ylim(-30, 70)

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

# Label
ax.text(-0.5, 62, 'Response Rate', fontsize=10, color='#6B7280', fontweight='500')

plt.tight_layout()
plt.show()
Library

Matplotlib

Category

Statistical

Did this help you?

Support PyLucid to keep it free & growing

Support