Skip to content

Commit 2f26e84

Browse files
Merge branch 'main' into implementation/swarm-basic/seaborn
2 parents ea4e20e + 983360f commit 2f26e84

2 files changed

Lines changed: 209 additions & 167 deletions

File tree

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,63 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
swarm-basic: Basic Swarm Plot
3-
Library: matplotlib 3.10.8 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: matplotlib 3.10.9 | Python 3.13.13
4+
Quality: 90/100 | Updated: 2026-05-05
55
"""
66

7+
import os
8+
79
import matplotlib.pyplot as plt
810
import numpy as np
911

1012

13+
# Theme tokens
14+
THEME = os.getenv("ANYPLOT_THEME", "light")
15+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
16+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
17+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
18+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
19+
20+
# Okabe-Ito palette — 4 departments
21+
COLORS = ["#009E73", "#D55E00", "#0072B2", "#CC79A7"]
22+
1123
# Data - Employee performance scores by department
1224
np.random.seed(42)
1325

1426
departments = ["Engineering", "Sales", "Marketing", "Support"]
1527
n_points = [50, 45, 40, 55]
1628

17-
# Generate scores with different distributions to showcase the plot
1829
scores_data = {
19-
"Engineering": np.random.normal(78, 12, n_points[0]),
20-
"Sales": np.random.normal(72, 15, n_points[1]),
21-
"Marketing": np.random.normal(82, 10, n_points[2]),
22-
"Support": np.random.normal(68, 14, n_points[3]),
30+
"Engineering": np.clip(np.random.normal(78, 12, n_points[0]), 0, 100),
31+
"Sales": np.clip(np.random.normal(72, 15, n_points[1]), 0, 100),
32+
"Marketing": np.clip(np.random.normal(82, 10, n_points[2]), 0, 100),
33+
"Support": np.clip(np.random.normal(68, 14, n_points[3]), 0, 100),
2334
}
2435

25-
# Clip scores to realistic range (0-100)
26-
for dept in scores_data:
27-
scores_data[dept] = np.clip(scores_data[dept], 0, 100)
28-
29-
# Create figure
30-
fig, ax = plt.subplots(figsize=(16, 9))
31-
32-
colors = ["#306998", "#FFD43B", "#4CAF50", "#FF7043"]
33-
34-
# Calculate y-range for proper scaling
36+
# Calculate point radius for swarm collision detection
3537
all_values = np.concatenate(list(scores_data.values()))
3638
y_min, y_max = all_values.min() - 5, all_values.max() + 5
37-
point_radius = 150 / 150 * 0.03 * (y_max - y_min)
39+
point_radius = 0.03 * (y_max - y_min)
40+
41+
# Plot
42+
fig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)
43+
ax.set_facecolor(PAGE_BG)
3844

39-
# Plot each department with swarm positioning
4045
for i, dept in enumerate(departments):
4146
vals = scores_data[dept]
4247
n = len(vals)
4348
offsets = np.zeros(n)
4449

45-
# Sort by value and process in order for swarm positioning
4650
sorted_idx = np.argsort(vals)
4751

4852
for j, idx in enumerate(sorted_idx):
4953
val = vals[idx]
50-
# Find nearby points already placed
5154
placed_idx = sorted_idx[:j]
5255
nearby = [(offsets[k], vals[k]) for k in placed_idx if abs(vals[k] - val) < point_radius * 2.5]
5356

5457
if not nearby:
5558
offsets[idx] = 0
5659
continue
5760

58-
# Try positions outward from center
5961
best_offset = 0
6062
found = False
6163
for offset in np.linspace(0, 0.35, 50):
@@ -76,27 +78,34 @@
7678
break
7779
offsets[idx] = best_offset
7880

79-
# Plot points
80-
ax.scatter(i + offsets, vals, s=150, alpha=0.7, color=colors[i], edgecolors="white", linewidth=0.5, label=dept)
81+
ax.scatter(i + offsets, vals, s=150, alpha=0.75, color=COLORS[i], edgecolors=PAGE_BG, linewidth=0.5, label=dept)
8182

82-
# Add mean marker
8383
mean_val = np.mean(vals)
84-
ax.scatter(i, mean_val, s=350, color=colors[i], marker="D", edgecolors="black", linewidth=2, zorder=5)
84+
ax.scatter(i, mean_val, s=350, color=COLORS[i], marker="D", edgecolors=INK, linewidth=2, zorder=5)
8585

86-
# Styling
87-
ax.set_xlabel("Department", fontsize=20)
88-
ax.set_ylabel("Performance Score", fontsize=20)
89-
ax.set_title("swarm-basic · matplotlib · pyplots.ai", fontsize=24)
86+
# Add invisible mean-marker entry for legend
87+
ax.scatter([], [], s=350, color=INK_SOFT, marker="D", edgecolors=INK, linewidth=2, label="Mean")
88+
89+
# Style
90+
ax.set_xlabel("Department", fontsize=20, color=INK)
91+
ax.set_ylabel("Performance Score", fontsize=20, color=INK)
92+
ax.set_title("swarm-basic · matplotlib · anyplot.ai", fontsize=24, fontweight="medium", color=INK)
9093
ax.set_xticks(range(len(departments)))
91-
ax.set_xticklabels(departments)
92-
ax.tick_params(axis="both", labelsize=16)
94+
ax.set_xticklabels(departments, fontsize=16)
95+
ax.tick_params(axis="both", labelsize=16, colors=INK_SOFT)
9396
ax.set_ylim(25, 105)
9497
ax.set_xlim(-0.6, 3.6)
95-
ax.grid(True, alpha=0.3, linestyle="--", axis="y")
9698

97-
# Legend for mean marker
98-
ax.scatter([], [], s=350, color="gray", marker="D", edgecolors="black", linewidth=2, label="Mean")
99-
ax.legend(fontsize=16, loc="upper right")
99+
ax.yaxis.grid(True, alpha=0.10, linewidth=0.8, color=INK)
100+
ax.spines["top"].set_visible(False)
101+
ax.spines["right"].set_visible(False)
102+
for spine in ("left", "bottom"):
103+
ax.spines[spine].set_color(INK_SOFT)
104+
105+
leg = ax.legend(fontsize=16, loc="upper right", framealpha=0.9)
106+
leg.get_frame().set_facecolor(ELEVATED_BG)
107+
leg.get_frame().set_edgecolor(INK_SOFT)
108+
plt.setp(leg.get_texts(), color=INK_SOFT)
100109

101110
plt.tight_layout()
102-
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
111+
plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG)

0 commit comments

Comments
 (0)