Skip to content

Commit c814a06

Browse files
feat(plotnine): implement line-loss-training (#2919)
## Implementation: `line-loss-training` - plotnine Implements the **plotnine** version of `line-loss-training`. **File:** `plots/line-loss-training/implementations/plotnine.py` **Parent Issue:** #2860 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608693967)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 30ef877 commit c814a06

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
""" pyplots.ai
2+
line-loss-training: Training Loss Curve
3+
Library: plotnine 0.15.2 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
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+
scale_color_manual,
20+
theme,
21+
theme_minimal,
22+
)
23+
24+
25+
# Data - Simulated training history with typical loss curve behavior
26+
np.random.seed(42)
27+
epochs = np.arange(1, 51)
28+
29+
# Training loss: starts high, decreases with diminishing returns
30+
train_loss = 2.5 * np.exp(-0.08 * epochs) + 0.15 + np.random.normal(0, 0.02, len(epochs))
31+
32+
# Validation loss: follows training initially, then diverges (overfitting)
33+
val_loss = 2.5 * np.exp(-0.06 * epochs) + 0.25 + np.random.normal(0, 0.03, len(epochs))
34+
# Add uptick after epoch 30 to show clear overfitting
35+
val_loss[30:] += np.linspace(0, 0.25, 20)
36+
37+
# Find optimal stopping point (minimum validation loss)
38+
optimal_epoch = epochs[np.argmin(val_loss)]
39+
40+
# Create long-format DataFrame for plotnine
41+
df = pd.DataFrame(
42+
{
43+
"Epoch": np.concatenate([epochs, epochs]),
44+
"Loss": np.concatenate([train_loss, val_loss]),
45+
"Type": ["Training Loss"] * len(epochs) + ["Validation Loss"] * len(epochs),
46+
}
47+
)
48+
49+
# Plot
50+
plot = (
51+
ggplot(df, aes(x="Epoch", y="Loss", color="Type"))
52+
+ geom_line(size=1.5, alpha=0.9)
53+
+ geom_point(size=3, alpha=0.7)
54+
+ geom_vline(xintercept=optimal_epoch, linetype="dashed", color="#555555", size=0.8, alpha=0.7)
55+
+ annotate(
56+
"text",
57+
x=optimal_epoch + 1,
58+
y=max(val_loss) * 0.85,
59+
label=f"Best: {optimal_epoch}",
60+
size=12,
61+
ha="left",
62+
color="#555555",
63+
)
64+
+ scale_color_manual(values={"Training Loss": "#306998", "Validation Loss": "#FFD43B"})
65+
+ labs(title="line-loss-training · plotnine · pyplots.ai", x="Epoch", y="Cross-Entropy Loss", color="")
66+
+ theme_minimal()
67+
+ theme(
68+
figure_size=(16, 9),
69+
text=element_text(size=14),
70+
axis_title=element_text(size=20),
71+
axis_text=element_text(size=16),
72+
plot_title=element_text(size=24, weight="bold"),
73+
legend_text=element_text(size=16),
74+
legend_position="top",
75+
legend_direction="horizontal",
76+
panel_grid_major=element_line(color="#cccccc", size=0.5, alpha=0.3),
77+
panel_grid_minor=element_line(color="#eeeeee", size=0.3, alpha=0.2),
78+
)
79+
)
80+
81+
# Save
82+
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: line-loss-training
3+
created: '2025-12-31T00:35:43Z'
4+
updated: '2025-12-31T00:38:02Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608693967
7+
issue: 2860
8+
python_version: 3.13.11
9+
library_version: 0.15.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/line-loss-training/plotnine/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/line-loss-training/plotnine/plot_thumb.png
12+
preview_html: null
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent visualization of training dynamics with clear overfitting pattern visible
17+
after epoch 30
18+
- Proper use of plotnine grammar of graphics with clean, readable code structure
19+
- Smart annotation showing optimal stopping point with vertical dashed line
20+
- Well-chosen color scheme (blue/yellow) that is colorblind-accessible
21+
- Perfect title format and comprehensive axis labeling with loss function specified
22+
weaknesses:
23+
- Grid line visibility is inconsistent - some lines appear more prominent than others
24+
despite same alpha settings
25+
- 'The Best: 46 annotation could be positioned better - currently placed at a fixed
26+
y-position that may not scale well with different data'
27+
- Yellow color for validation loss could benefit from slightly darker shade for
28+
better contrast against white background

0 commit comments

Comments
 (0)