Skip to content

Commit 5c778f5

Browse files
feat(plotnine): implement stem-basic (#5636)
## Implementation: `stem-basic` - python/plotnine Implements the **python/plotnine** version of `stem-basic`. **File:** `plots/stem-basic/implementations/python/plotnine.py` **Parent Issue:** #972 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25172265081)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent d054bac commit 5c778f5

2 files changed

Lines changed: 301 additions & 0 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
""" anyplot.ai
2+
stem-basic: Basic Stem Plot
3+
Library: plotnine 0.15.3 | Python 3.13.13
4+
Quality: 87/100 | Created: 2026-04-30
5+
"""
6+
7+
import os
8+
9+
import numpy as np
10+
import pandas as pd
11+
from plotnine import (
12+
aes,
13+
element_line,
14+
element_rect,
15+
element_text,
16+
geom_hline,
17+
geom_point,
18+
geom_segment,
19+
ggplot,
20+
labs,
21+
theme,
22+
theme_minimal,
23+
)
24+
25+
26+
THEME = os.getenv("ANYPLOT_THEME", "light")
27+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
28+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
29+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
30+
31+
BRAND = "#009E73"
32+
33+
# Data - Damped sinusoidal discrete signal (signal processing example)
34+
np.random.seed(42)
35+
n = 30
36+
t = np.arange(n)
37+
signal = np.exp(-t / 12.0) * np.cos(0.55 * t)
38+
39+
df = pd.DataFrame({"t": t, "signal": signal, "zero": 0.0})
40+
41+
# Plot
42+
plot = (
43+
ggplot(df, aes(x="t"))
44+
+ geom_hline(yintercept=0, color=INK_SOFT, size=0.8)
45+
+ geom_segment(aes(x="t", xend="t", y="zero", yend="signal"), color=BRAND, size=0.9)
46+
+ geom_point(aes(y="signal"), color=BRAND, size=4, stroke=0.5)
47+
+ labs(x="Sample Index", y="Amplitude", title="stem-basic · plotnine · anyplot.ai")
48+
+ theme_minimal()
49+
+ theme(
50+
figure_size=(16, 9),
51+
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
52+
panel_background=element_rect(fill=PAGE_BG),
53+
text=element_text(size=14, color=INK),
54+
axis_title=element_text(size=20, color=INK),
55+
axis_text=element_text(size=16, color=INK_SOFT),
56+
plot_title=element_text(size=24, color=INK),
57+
panel_grid_major_y=element_line(color=INK, size=0.3, alpha=0.10),
58+
panel_grid_major_x=element_line(color=INK, size=0.0, alpha=0.0),
59+
panel_grid_minor=element_line(color=INK, size=0.2, alpha=0.05),
60+
axis_line=element_line(color=INK_SOFT),
61+
)
62+
)
63+
64+
# Save
65+
plot.save(f"plot-{THEME}.png", dpi=300, width=16, height=9, verbose=False)
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
library: plotnine
2+
language: python
3+
specification_id: stem-basic
4+
created: '2026-04-30T15:18:15Z'
5+
updated: '2026-04-30T15:34:36Z'
6+
generated_by: claude-sonnet
7+
workflow_run: 25172265081
8+
issue: 972
9+
python_version: 3.13.13
10+
library_version: 0.15.3
11+
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/stem-basic/python/plotnine/plot-light.png
12+
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/stem-basic/python/plotnine/plot-dark.png
13+
preview_html_light: null
14+
preview_html_dark: null
15+
quality_score: 87
16+
review:
17+
strengths:
18+
- 'Perfect spec compliance: all stem plot features (stems, markers, baseline) implemented
19+
correctly using plotnine''s grammar of graphics (geom_segment + geom_point + geom_hline)'
20+
- 'Excellent theme adaptation: both light and dark renders are fully legible with
21+
correct backgrounds (#FAF8F1 / #1A1A17), text colors, and adaptive grid tokens'
22+
- 'Compelling realistic data: damped sinusoidal signal is a natural fit for a stem
23+
plot and demonstrates positive/negative values, oscillation, and amplitude decay'
24+
- 'Refined grid design: y-axis-only grid at 10% opacity with x-axis grid suppressed
25+
— an intentional and excellent visual choice'
26+
weaknesses:
27+
- Y-axis label 'Amplitude' lacks units/context — 'Amplitude (normalized)' would
28+
be more informative and score full points on VQ-06
29+
- No visual storytelling or hierarchy — the decay pattern in the damped sinusoidal
30+
signal is not visually emphasized through size variation, alpha, or a reference
31+
envelope curve, leaving DE-03 at default level
32+
image_description: |-
33+
Light render (plot-light.png):
34+
Background: Warm off-white #FAF8F1 — correct, not pure white
35+
Chrome: Title "stem-basic · plotnine · anyplot.ai" in dark #1A1A17, clearly readable. X-axis label "Sample Index" and y-axis label "Amplitude" in dark ink. Tick labels in muted #4A4A44. All text readable against light background.
36+
Data: 30 stems in brand green #009E73 — thin vertical lines from y=0 baseline to filled circle markers. Baseline at y=0 as a darker horizontal reference line. Y-axis-only subtle grid at ~10% opacity. No legend (single series).
37+
Legibility verdict: PASS
38+
39+
Dark render (plot-dark.png):
40+
Background: Near-black #1A1A17 — correct, not pure black
41+
Chrome: Title in light #F0EFE8, clearly readable against dark background. Axis labels in light ink. Tick labels in muted #B8B7B0. No dark-on-dark failures — all text is light-colored and fully legible. Axis lines in muted light gray.
42+
Data: Colors identical to light render — stems and markers remain #009E73. Baseline visible in lighter gray tone. Same data representation as light render.
43+
Legibility verdict: PASS
44+
criteria_checklist:
45+
visual_quality:
46+
score: 29
47+
max: 30
48+
items:
49+
- id: VQ-01
50+
name: Text Legibility
51+
score: 8
52+
max: 8
53+
passed: true
54+
comment: Title 24pt, axis labels 20pt, tick labels 16pt — all explicitly set
55+
and readable in both themes
56+
- id: VQ-02
57+
name: No Overlap
58+
score: 6
59+
max: 6
60+
passed: true
61+
comment: 30 well-spaced stems, no text collisions
62+
- id: VQ-03
63+
name: Element Visibility
64+
score: 6
65+
max: 6
66+
passed: true
67+
comment: Stems (size=0.9) and markers (size=4) appropriately sized for 30
68+
points; baseline clearly visible
69+
- id: VQ-04
70+
name: Color Accessibility
71+
score: 2
72+
max: 2
73+
passed: true
74+
comment: 'Single brand green #009E73, CVD-safe, good contrast in both themes'
75+
- id: VQ-05
76+
name: Layout & Canvas
77+
score: 4
78+
max: 4
79+
passed: true
80+
comment: 16:9 canvas, balanced margins, plot fills canvas well
81+
- id: VQ-06
82+
name: Axis Labels & Title
83+
score: 1
84+
max: 2
85+
passed: false
86+
comment: Y-axis 'Amplitude' is descriptive but lacks units/context; 'Amplitude
87+
(normalized)' would be better
88+
- id: VQ-07
89+
name: Palette Compliance
90+
score: 2
91+
max: 2
92+
passed: true
93+
comment: 'First series is #009E73; backgrounds #FAF8F1 (light) and #1A1A17
94+
(dark); theme chrome adapts correctly'
95+
design_excellence:
96+
score: 10
97+
max: 20
98+
items:
99+
- id: DE-01
100+
name: Aesthetic Sophistication
101+
score: 4
102+
max: 8
103+
passed: true
104+
comment: Clean, well-configured with brand color and baseline; above generic
105+
defaults but not publication-ready
106+
- id: DE-02
107+
name: Visual Refinement
108+
score: 4
109+
max: 6
110+
passed: true
111+
comment: Y-axis-only grid at 10% opacity is excellent; x-axis grid suppressed;
112+
theme_minimal removes top/right spines
113+
- id: DE-03
114+
name: Data Storytelling
115+
score: 2
116+
max: 6
117+
passed: false
118+
comment: Data displayed but decay pattern not visually emphasized; no visual
119+
hierarchy or storytelling
120+
spec_compliance:
121+
score: 15
122+
max: 15
123+
items:
124+
- id: SC-01
125+
name: Plot Type
126+
score: 5
127+
max: 5
128+
passed: true
129+
comment: Correct stem plot via geom_segment + geom_point + geom_hline
130+
- id: SC-02
131+
name: Required Features
132+
score: 4
133+
max: 4
134+
passed: true
135+
comment: Thin stems, visible circular markers, y=0 baseline, consistent sizing
136+
- id: SC-03
137+
name: Data Mapping
138+
score: 3
139+
max: 3
140+
passed: true
141+
comment: Sample index on x, amplitude on y; all 30 points visible
142+
- id: SC-04
143+
name: Title & Legend
144+
score: 3
145+
max: 3
146+
passed: true
147+
comment: Title 'stem-basic · plotnine · anyplot.ai' correct; no legend appropriate
148+
for single series
149+
data_quality:
150+
score: 15
151+
max: 15
152+
items:
153+
- id: DQ-01
154+
name: Feature Coverage
155+
score: 6
156+
max: 6
157+
passed: true
158+
comment: Shows positive AND negative values, oscillation, and decay envelope
159+
— all stem plot characteristics
160+
- id: DQ-02
161+
name: Realistic Context
162+
score: 5
163+
max: 5
164+
passed: true
165+
comment: Damped sinusoidal signal is a textbook signal processing example;
166+
neutral and scientific
167+
- id: DQ-03
168+
name: Appropriate Scale
169+
score: 4
170+
max: 4
171+
passed: true
172+
comment: 30 samples, normalized amplitude range, physically plausible decay
173+
constant and frequency
174+
code_quality:
175+
score: 10
176+
max: 10
177+
items:
178+
- id: CQ-01
179+
name: KISS Structure
180+
score: 3
181+
max: 3
182+
passed: true
183+
comment: Clean Imports → Data → Plot → Save; no functions or classes
184+
- id: CQ-02
185+
name: Reproducibility
186+
score: 2
187+
max: 2
188+
passed: true
189+
comment: np.random.seed(42) set
190+
- id: CQ-03
191+
name: Clean Imports
192+
score: 2
193+
max: 2
194+
passed: true
195+
comment: All 11 plotnine imports are used
196+
- id: CQ-04
197+
name: Code Elegance
198+
score: 2
199+
max: 2
200+
passed: true
201+
comment: Pythonic, appropriate complexity, no over-engineering
202+
- id: CQ-05
203+
name: Output & API
204+
score: 1
205+
max: 1
206+
passed: true
207+
comment: Saves as plot-{THEME}.png, current API throughout
208+
library_mastery:
209+
score: 8
210+
max: 10
211+
items:
212+
- id: LM-01
213+
name: Idiomatic Usage
214+
score: 5
215+
max: 5
216+
passed: true
217+
comment: 'Fully idiomatic grammar of graphics: layered geoms, aes() mappings,
218+
theme() customization'
219+
- id: LM-02
220+
name: Distinctive Features
221+
score: 3
222+
max: 5
223+
passed: true
224+
comment: Composing stem plot from primitive geoms (geom_segment + geom_point
225+
+ geom_hline) demonstrates grammar-of-graphics thinking; somewhat library-specific
226+
but not exceptional
227+
verdict: APPROVED
228+
impl_tags:
229+
dependencies: []
230+
techniques:
231+
- layer-composition
232+
patterns:
233+
- data-generation
234+
dataprep: []
235+
styling:
236+
- grid-styling

0 commit comments

Comments
 (0)