|
1 | 1 | """ pyplots.ai |
2 | 2 | density-basic: Basic Density Plot |
3 | | -Library: seaborn 0.13.2 | Python 3.13.11 |
4 | | -Quality: 93/100 | Created: 2025-12-23 |
| 3 | +Library: seaborn 0.13.2 | Python 3.14.3 |
| 4 | +Quality: 91/100 | Updated: 2026-02-23 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import matplotlib.pyplot as plt |
8 | 8 | import numpy as np |
9 | 9 | import seaborn as sns |
10 | 10 |
|
11 | 11 |
|
12 | | -# Data - create a realistic bimodal distribution of test scores |
| 12 | +# Data - bimodal distribution of test scores |
13 | 13 | np.random.seed(42) |
14 | 14 | test_scores = np.concatenate( |
15 | 15 | [ |
16 | | - np.random.normal(72, 10, 300), # Main group centered at 72 |
17 | | - np.random.normal(88, 5, 100), # High achievers group |
| 16 | + np.random.normal(68, 8, 280), # Main group centered at 68 |
| 17 | + np.random.normal(90, 4, 120), # High achievers group |
18 | 18 | ] |
19 | 19 | ) |
20 | 20 |
|
21 | | -# Create figure |
| 21 | +# Plot |
22 | 22 | fig, ax = plt.subplots(figsize=(16, 9)) |
23 | 23 |
|
24 | | -# Plot density curve with fill |
25 | | -sns.kdeplot(data=test_scores, ax=ax, fill=True, alpha=0.6, color="#306998", linewidth=3) |
| 24 | +# KDE line first (for peak detection), then fill |
| 25 | +sns.kdeplot(data=test_scores, ax=ax, fill=False, color="#306998", linewidth=3, bw_adjust=0.9) |
| 26 | +line = ax.get_lines()[0] |
| 27 | +x_kde, y_kde = line.get_xdata(), line.get_ydata() |
| 28 | +ax.fill_between(x_kde, y_kde, alpha=0.5, color="#306998") |
26 | 29 |
|
27 | | -# Add rug plot to show individual observations |
28 | | -sns.rugplot(data=test_scores, ax=ax, color="#306998", alpha=0.3, height=0.03) |
| 30 | +sns.rugplot(data=test_scores, ax=ax, color="#1a3a5c", alpha=0.5, height=0.05) |
| 31 | + |
| 32 | +# Annotate the two peaks to tell the bimodal story |
| 33 | +peak1_idx = np.argmax(y_kde[x_kde < 80]) |
| 34 | +peak2_idx = len(y_kde[x_kde < 80]) + np.argmax(y_kde[x_kde >= 80]) |
| 35 | + |
| 36 | +px1, py1 = x_kde[peak1_idx], y_kde[peak1_idx] |
| 37 | +ax.annotate( |
| 38 | + "Main group", |
| 39 | + xy=(px1, py1), |
| 40 | + xytext=(px1 - 14, py1 - 0.008), |
| 41 | + fontsize=16, |
| 42 | + fontweight="medium", |
| 43 | + color="#1a3a5c", |
| 44 | + arrowprops={"arrowstyle": "->", "color": "#1a3a5c", "lw": 1.5}, |
| 45 | + ha="center", |
| 46 | + va="top", |
| 47 | +) |
| 48 | +ax.axvline(px1, color="#306998", alpha=0.15, linestyle="--", linewidth=1.5) |
| 49 | + |
| 50 | +px2, py2 = x_kde[peak2_idx], y_kde[peak2_idx] |
| 51 | +ax.annotate( |
| 52 | + "High achievers", |
| 53 | + xy=(px2, py2), |
| 54 | + xytext=(px2 + 12, py2 - 0.004), |
| 55 | + fontsize=16, |
| 56 | + fontweight="medium", |
| 57 | + color="#1a3a5c", |
| 58 | + arrowprops={"arrowstyle": "->", "color": "#1a3a5c", "lw": 1.5}, |
| 59 | + ha="center", |
| 60 | + va="top", |
| 61 | +) |
| 62 | +ax.axvline(px2, color="#306998", alpha=0.15, linestyle="--", linewidth=1.5) |
29 | 63 |
|
30 | 64 | # Style |
31 | 65 | ax.set_xlabel("Test Score (points)", fontsize=20) |
32 | 66 | ax.set_ylabel("Density", fontsize=20) |
33 | | -ax.set_title("density-basic · seaborn · pyplots.ai", fontsize=24) |
| 67 | +ax.set_title("density-basic \u00b7 seaborn \u00b7 pyplots.ai", fontsize=24, fontweight="medium") |
34 | 68 | ax.tick_params(axis="both", labelsize=16) |
35 | | -ax.grid(True, alpha=0.3, linestyle="--") |
| 69 | +ax.spines["top"].set_visible(False) |
| 70 | +ax.spines["right"].set_visible(False) |
| 71 | +ax.yaxis.grid(True, alpha=0.2, linewidth=0.8) |
36 | 72 |
|
37 | 73 | plt.tight_layout() |
38 | 74 | plt.savefig("plot.png", dpi=300, bbox_inches="tight") |
0 commit comments