Skip to content

Commit e467e9e

Browse files
feat(pygal): implement line-loss-training (#6654)
## Implementation: `line-loss-training` - python/pygal Implements the **python/pygal** version of `line-loss-training`. **File:** `plots/line-loss-training/implementations/python/pygal.py` **Parent Issue:** #2860 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25843905278)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 5c3f406 commit e467e9e

2 files changed

Lines changed: 216 additions & 160 deletions

File tree

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,79 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
line-loss-training: Training Loss Curve
3-
Library: pygal 3.1.0 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-31
3+
Library: pygal 3.1.0 | Python 3.13.13
4+
Quality: 92/100 | Updated: 2026-05-14
55
"""
66

7+
import os
8+
import sys
9+
710
import numpy as np
8-
import pygal
9-
from pygal.style import Style
1011

1112

13+
# Remove local directory from sys.path to avoid shadowing the pygal package
14+
_local_dir = os.path.abspath(os.path.dirname(__file__))
15+
sys.path = [p for p in sys.path if os.path.abspath(p) != _local_dir]
16+
17+
import pygal # noqa: E402
18+
from pygal.style import Style # noqa: E402
19+
20+
21+
THEME = os.getenv("ANYPLOT_THEME", "light")
22+
23+
# Theme tokens (from default-style-guide.md)
24+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
25+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
26+
INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F"
27+
28+
# Okabe-Ito palette (first series = brand green #009E73)
29+
OKABE_ITO = ("#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442")
30+
1231
# Data: Simulated training loss curves showing typical overfitting behavior
1332
np.random.seed(42)
1433
epochs = np.arange(1, 51)
1534

1635
# Training loss: Steadily decreasing with some noise
1736
train_loss = 2.5 * np.exp(-0.08 * epochs) + 0.1 + np.random.normal(0, 0.02, len(epochs))
1837

19-
# Validation loss: Decreases then increases (overfitting after epoch ~30)
38+
# Validation loss: Decreases then increases (overfitting after epoch ~25)
2039
val_loss = 2.3 * np.exp(-0.07 * epochs) + 0.15 + 0.003 * np.maximum(0, epochs - 25) ** 1.5
2140
val_loss += np.random.normal(0, 0.03, len(epochs))
2241

2342
# Find minimum validation loss epoch for annotation
2443
min_val_epoch = int(epochs[np.argmin(val_loss)])
2544
min_val_loss = float(np.min(val_loss))
2645

27-
# Custom style for large canvas
46+
# Custom theme-adaptive style
2847
custom_style = Style(
29-
background="white",
30-
plot_background="white",
31-
foreground="#333333",
32-
foreground_strong="#333333",
33-
foreground_subtle="#666666",
34-
colors=("#306998", "#FFD43B"), # Python Blue, Python Yellow
35-
title_font_size=48,
36-
label_font_size=36,
37-
major_label_font_size=32,
38-
legend_font_size=32,
39-
value_font_size=28,
40-
stroke_width=4,
41-
opacity=0.9,
42-
opacity_hover=1.0,
48+
background=PAGE_BG,
49+
plot_background=PAGE_BG,
50+
foreground=INK,
51+
foreground_strong=INK,
52+
foreground_subtle=INK_MUTED,
53+
colors=OKABE_ITO,
54+
title_font_size=28,
55+
label_font_size=22,
56+
major_label_font_size=18,
57+
legend_font_size=16,
58+
value_font_size=14,
59+
stroke_width=3,
4360
)
4461

4562
# Create line chart
4663
chart = pygal.Line(
4764
width=4800,
4865
height=2700,
4966
style=custom_style,
50-
title="line-loss-training · pygal · pyplots.ai",
67+
title="line-loss-training · pygal · anyplot.ai",
5168
x_title="Epoch",
5269
y_title="Cross-Entropy Loss",
53-
show_x_guides=False,
70+
show_x_guides=True,
5471
show_y_guides=True,
5572
dots_size=6,
56-
stroke_style={"width": 4},
73+
stroke_style={"width": 3},
5774
legend_at_bottom=False,
5875
legend_box_size=24,
59-
margin=50,
76+
margin=80,
6077
x_label_rotation=0,
6178
truncate_label=-1,
6279
show_dots=True,
@@ -69,6 +86,7 @@
6986
chart.add("Training Loss", list(train_loss))
7087
chart.add("Validation Loss", list(val_loss))
7188

72-
# Save as PNG and HTML
73-
chart.render_to_png("plot.png")
74-
chart.render_to_file("plot.html")
89+
# Save as PNG and HTML with theme suffix
90+
chart.render_to_png(f"plot-{THEME}.png")
91+
with open(f"plot-{THEME}.html", "wb") as f:
92+
f.write(chart.render())

0 commit comments

Comments
 (0)