Skip to content

Commit e2624fa

Browse files
feat(plotnine): implement elbow-curve (#2360)
## Implementation: `elbow-curve` - plotnine Implements the **plotnine** version of `elbow-curve`. **File:** `plots/elbow-curve/implementations/plotnine.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20528204090)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent ce5ba17 commit e2624fa

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
""" pyplots.ai
2+
elbow-curve: Elbow Curve for K-Means Clustering
3+
Library: plotnine 0.15.2 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-26
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
from plotnine import (
10+
aes,
11+
annotate,
12+
element_line,
13+
element_text,
14+
geom_line,
15+
geom_point,
16+
geom_vline,
17+
ggplot,
18+
labs,
19+
theme,
20+
theme_minimal,
21+
)
22+
23+
24+
# Data - Simulate realistic K-means inertia values
25+
# Inertia decreases as k increases, with diminishing returns after optimal k
26+
np.random.seed(42)
27+
28+
k_values = list(range(1, 11))
29+
30+
# Simulate inertia values that show clear elbow at k=4
31+
# Formula: base decay curve + noise
32+
base_inertias = [1000, 500, 280, 150, 120, 100, 85, 75, 68, 62]
33+
noise = np.random.uniform(-5, 5, len(k_values))
34+
inertias = [max(10, base + n) for base, n in zip(base_inertias, noise, strict=True)]
35+
36+
# Create DataFrame for plotting
37+
df = pd.DataFrame({"k": k_values, "inertia": inertias})
38+
39+
# Optimal k (elbow point)
40+
optimal_k = 4
41+
42+
# Plot
43+
plot = (
44+
ggplot(df, aes(x="k", y="inertia"))
45+
+ geom_line(color="#306998", size=2, alpha=0.9)
46+
+ geom_point(color="#306998", size=5, alpha=1.0)
47+
+ geom_vline(xintercept=optimal_k, linetype="dashed", color="#FFD43B", size=1.5, alpha=0.8)
48+
+ annotate(
49+
"text",
50+
x=optimal_k + 0.5,
51+
y=inertias[optimal_k - 1] + 80,
52+
label=f"Optimal k = {optimal_k}",
53+
size=14,
54+
color="#FFD43B",
55+
ha="left",
56+
fontweight="bold",
57+
)
58+
+ labs(
59+
title="elbow-curve · plotnine · pyplots.ai",
60+
x="Number of Clusters (k)",
61+
y="Inertia (Within-Cluster Sum of Squares)",
62+
)
63+
+ theme_minimal()
64+
+ theme(
65+
figure_size=(16, 9),
66+
plot_title=element_text(size=24, weight="bold"),
67+
axis_title=element_text(size=20),
68+
axis_text=element_text(size=16),
69+
panel_grid_major=element_line(color="#CCCCCC", size=0.5, alpha=0.3),
70+
)
71+
)
72+
73+
# Save
74+
plot.save("plot.png", dpi=300, verbose=False)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library: plotnine
2+
specification_id: elbow-curve
3+
created: '2025-12-26T19:37:41Z'
4+
updated: '2025-12-26T19:44:27Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20528204090
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 0.15.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/elbow-curve/plotnine/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/elbow-curve/plotnine/plot_thumb.png
12+
preview_html: null
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Clear visual hierarchy with excellent text sizing at all levels (title, axis labels,
17+
ticks)
18+
- 'Effective use of plotnine grammar of graphics: layered geoms, annotations, and
19+
theme customization'
20+
- The yellow dashed vertical line with annotation clearly highlights the optimal
21+
k value
22+
- Clean, professional appearance using theme_minimal with subtle grid
23+
- Good color contrast between the blue data line and yellow annotation
24+
weaknesses:
25+
- X-axis shows decimal values (2.5, 5.0, 7.5, 10.0) instead of integers (1, 2, 3,
26+
..., 10) which would be more appropriate for discrete k values
27+
- The realistic context is somewhat generic - could use a more specific domain scenario
28+
in comments

0 commit comments

Comments
 (0)