|
1 | 1 | """ pyplots.ai |
2 | 2 | violin-basic: Basic Violin Plot |
3 | | -Library: matplotlib 3.10.8 | Python 3.13.11 |
4 | | -Quality: 92/100 | Created: 2025-12-23 |
| 3 | +Library: matplotlib 3.10.8 | Python 3.14.3 |
| 4 | +Quality: /100 | Updated: 2026-02-21 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import matplotlib.pyplot as plt |
8 | 8 | import numpy as np |
9 | 9 |
|
10 | 10 |
|
11 | | -# Data - simulated test scores across different schools |
| 11 | +# Data - simulated test scores (0-100) across different schools |
12 | 12 | np.random.seed(42) |
13 | 13 | categories = ["School A", "School B", "School C", "School D"] |
14 | 14 | data = [ |
15 | | - np.random.normal(75, 10, 150), # School A: centered around 75 |
16 | | - np.random.normal(82, 8, 150), # School B: higher scores, less spread |
17 | | - np.random.normal(68, 15, 150), # School C: lower average, more spread |
18 | | - np.random.normal(78, 12, 150), # School D: moderate |
| 15 | + np.clip(np.random.normal(75, 10, 150), 0, 100), # School A: centered around 75 |
| 16 | + np.clip(np.random.normal(85, 6, 150), 0, 100), # School B: high scores, tight cluster |
| 17 | + np.clip(np.random.normal(62, 15, 150), 0, 100), # School C: lower average, wide spread |
| 18 | + np.clip( |
| 19 | + np.concatenate([np.random.normal(70, 5, 80), np.random.normal(88, 4, 70)]), 0, 100 |
| 20 | + ), # School D: bimodal (two subgroups) |
19 | 21 | ] |
20 | 22 |
|
21 | | -# Create plot (4800x2700 px) |
| 23 | +# Plot |
22 | 24 | fig, ax = plt.subplots(figsize=(16, 9)) |
23 | 25 |
|
24 | | -# Create violin plot with quartile markers |
25 | | -parts = ax.violinplot(data, positions=range(len(categories)), showmeans=False, showmedians=True, showextrema=True) |
| 26 | +# Violin plot with built-in quartile lines and facecolor/linecolor params |
| 27 | +parts = ax.violinplot( |
| 28 | + data, |
| 29 | + positions=range(len(categories)), |
| 30 | + quantiles=[[0.25, 0.5, 0.75]] * len(categories), |
| 31 | + showmeans=False, |
| 32 | + showmedians=False, |
| 33 | + showextrema=False, |
| 34 | + bw_method=0.3, |
| 35 | + widths=0.75, |
| 36 | +) |
26 | 37 |
|
27 | | -# Style the violins with Python Blue |
28 | | -for pc in parts["bodies"]: |
29 | | - pc.set_facecolor("#306998") |
| 38 | +# Style violin bodies with shade intensity by median value |
| 39 | +medians = [np.median(d) for d in data] |
| 40 | +median_min, median_max = min(medians), max(medians) |
| 41 | +base_blue = np.array([0x30, 0x69, 0x98]) / 255 # Python Blue #306998 |
| 42 | + |
| 43 | +for i, pc in enumerate(parts["bodies"]): |
| 44 | + t = (medians[i] - median_min) / (median_max - median_min) if median_max > median_min else 0.5 |
| 45 | + pc.set_facecolor(base_blue * (0.6 + 0.4 * t)) |
30 | 46 | pc.set_edgecolor("#1e4a6e") |
31 | | - pc.set_alpha(0.7) |
| 47 | + pc.set_alpha(0.75) |
32 | 48 | pc.set_linewidth(2) |
33 | 49 |
|
34 | | -# Style the lines (median, min, max) |
35 | | -parts["cmedians"].set_color("#FFD43B") |
36 | | -parts["cmedians"].set_linewidth(3) |
37 | | -parts["cmins"].set_color("#1e4a6e") |
38 | | -parts["cmins"].set_linewidth(2) |
39 | | -parts["cmaxes"].set_color("#1e4a6e") |
40 | | -parts["cmaxes"].set_linewidth(2) |
41 | | -parts["cbars"].set_color("#1e4a6e") |
42 | | -parts["cbars"].set_linewidth(2) |
43 | | - |
44 | | -# Add quartile markers (Q1 and Q3) as box indicators |
45 | | -quartile1 = [np.percentile(d, 25) for d in data] |
46 | | -quartile3 = [np.percentile(d, 75) for d in data] |
47 | | - |
48 | | -# Draw thin boxes for interquartile range |
49 | | -for i, (q1, q3) in enumerate(zip(quartile1, quartile3, strict=True)): |
50 | | - ax.vlines(i, q1, q3, color="#1e4a6e", linewidth=6, zorder=3) |
51 | | - |
52 | | -# Labels and styling (scaled font sizes for 4800x2700) |
| 50 | +# Style quantile lines: white for Q1/Q3, yellow for median |
| 51 | +parts["cquantiles"].set_colors(["white", "#FFD43B", "white"] * len(categories)) |
| 52 | +parts["cquantiles"].set_linewidths([2, 3.5, 2] * len(categories)) |
| 53 | + |
| 54 | +# Labels and styling |
53 | 55 | ax.set_xticks(range(len(categories))) |
54 | 56 | ax.set_xticklabels(categories) |
55 | 57 | ax.set_xlabel("School", fontsize=20) |
56 | 58 | ax.set_ylabel("Test Score (points)", fontsize=20) |
57 | | -ax.set_title("violin-basic · matplotlib · pyplots.ai", fontsize=24) |
| 59 | +ax.set_title("violin-basic \u00b7 matplotlib \u00b7 pyplots.ai", fontsize=24, fontweight="medium") |
58 | 60 | ax.tick_params(axis="both", labelsize=16) |
59 | | -ax.grid(True, alpha=0.3, linestyle="--", axis="y") |
| 61 | + |
| 62 | +# Spine removal and grid per library rules |
| 63 | +ax.spines["top"].set_visible(False) |
| 64 | +ax.spines["right"].set_visible(False) |
| 65 | +ax.yaxis.grid(True, alpha=0.2, linewidth=0.8) |
60 | 66 |
|
61 | 67 | plt.tight_layout() |
62 | 68 | plt.savefig("plot.png", dpi=300, bbox_inches="tight") |
0 commit comments