Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions plots/stem-basic/implementations/python/plotnine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
""" anyplot.ai
stem-basic: Basic Stem Plot
Library: plotnine 0.15.3 | Python 3.13.13
Quality: 87/100 | Created: 2026-04-30
"""

import os

import numpy as np
import pandas as pd
from plotnine import (
aes,
element_line,
element_rect,
element_text,
geom_hline,
geom_point,
geom_segment,
ggplot,
labs,
theme,
theme_minimal,
)


THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"

BRAND = "#009E73"

# Data - Damped sinusoidal discrete signal (signal processing example)
np.random.seed(42)
n = 30
t = np.arange(n)
signal = np.exp(-t / 12.0) * np.cos(0.55 * t)

df = pd.DataFrame({"t": t, "signal": signal, "zero": 0.0})

# Plot
plot = (
ggplot(df, aes(x="t"))
+ geom_hline(yintercept=0, color=INK_SOFT, size=0.8)
+ geom_segment(aes(x="t", xend="t", y="zero", yend="signal"), color=BRAND, size=0.9)
+ geom_point(aes(y="signal"), color=BRAND, size=4, stroke=0.5)
+ labs(x="Sample Index", y="Amplitude", title="stem-basic · plotnine · anyplot.ai")
+ theme_minimal()
+ theme(
figure_size=(16, 9),
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
panel_background=element_rect(fill=PAGE_BG),
text=element_text(size=14, color=INK),
axis_title=element_text(size=20, color=INK),
axis_text=element_text(size=16, color=INK_SOFT),
plot_title=element_text(size=24, color=INK),
panel_grid_major_y=element_line(color=INK, size=0.3, alpha=0.10),
panel_grid_major_x=element_line(color=INK, size=0.0, alpha=0.0),
panel_grid_minor=element_line(color=INK, size=0.2, alpha=0.05),
axis_line=element_line(color=INK_SOFT),
)
)

# Save
plot.save(f"plot-{THEME}.png", dpi=300, width=16, height=9, verbose=False)
236 changes: 236 additions & 0 deletions plots/stem-basic/metadata/python/plotnine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
library: plotnine
language: python
specification_id: stem-basic
created: '2026-04-30T15:18:15Z'
updated: '2026-04-30T15:34:36Z'
generated_by: claude-sonnet
workflow_run: 25172265081
issue: 972
python_version: 3.13.13
library_version: 0.15.3
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/stem-basic/python/plotnine/plot-light.png
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/stem-basic/python/plotnine/plot-dark.png
preview_html_light: null
preview_html_dark: null
quality_score: 87
review:
strengths:
- 'Perfect spec compliance: all stem plot features (stems, markers, baseline) implemented
correctly using plotnine''s grammar of graphics (geom_segment + geom_point + geom_hline)'
- 'Excellent theme adaptation: both light and dark renders are fully legible with
correct backgrounds (#FAF8F1 / #1A1A17), text colors, and adaptive grid tokens'
- 'Compelling realistic data: damped sinusoidal signal is a natural fit for a stem
plot and demonstrates positive/negative values, oscillation, and amplitude decay'
- 'Refined grid design: y-axis-only grid at 10% opacity with x-axis grid suppressed
— an intentional and excellent visual choice'
weaknesses:
- Y-axis label 'Amplitude' lacks units/context — 'Amplitude (normalized)' would
be more informative and score full points on VQ-06
- No visual storytelling or hierarchy — the decay pattern in the damped sinusoidal
signal is not visually emphasized through size variation, alpha, or a reference
envelope curve, leaving DE-03 at default level
image_description: |-
Light render (plot-light.png):
Background: Warm off-white #FAF8F1 — correct, not pure white
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.
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).
Legibility verdict: PASS

Dark render (plot-dark.png):
Background: Near-black #1A1A17 — correct, not pure black
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.
Data: Colors identical to light render — stems and markers remain #009E73. Baseline visible in lighter gray tone. Same data representation as light render.
Legibility verdict: PASS
criteria_checklist:
visual_quality:
score: 29
max: 30
items:
- id: VQ-01
name: Text Legibility
score: 8
max: 8
passed: true
comment: Title 24pt, axis labels 20pt, tick labels 16pt — all explicitly set
and readable in both themes
- id: VQ-02
name: No Overlap
score: 6
max: 6
passed: true
comment: 30 well-spaced stems, no text collisions
- id: VQ-03
name: Element Visibility
score: 6
max: 6
passed: true
comment: Stems (size=0.9) and markers (size=4) appropriately sized for 30
points; baseline clearly visible
- id: VQ-04
name: Color Accessibility
score: 2
max: 2
passed: true
comment: 'Single brand green #009E73, CVD-safe, good contrast in both themes'
- id: VQ-05
name: Layout & Canvas
score: 4
max: 4
passed: true
comment: 16:9 canvas, balanced margins, plot fills canvas well
- id: VQ-06
name: Axis Labels & Title
score: 1
max: 2
passed: false
comment: Y-axis 'Amplitude' is descriptive but lacks units/context; 'Amplitude
(normalized)' would be better
- id: VQ-07
name: Palette Compliance
score: 2
max: 2
passed: true
comment: 'First series is #009E73; backgrounds #FAF8F1 (light) and #1A1A17
(dark); theme chrome adapts correctly'
design_excellence:
score: 10
max: 20
items:
- id: DE-01
name: Aesthetic Sophistication
score: 4
max: 8
passed: true
comment: Clean, well-configured with brand color and baseline; above generic
defaults but not publication-ready
- id: DE-02
name: Visual Refinement
score: 4
max: 6
passed: true
comment: Y-axis-only grid at 10% opacity is excellent; x-axis grid suppressed;
theme_minimal removes top/right spines
- id: DE-03
name: Data Storytelling
score: 2
max: 6
passed: false
comment: Data displayed but decay pattern not visually emphasized; no visual
hierarchy or storytelling
spec_compliance:
score: 15
max: 15
items:
- id: SC-01
name: Plot Type
score: 5
max: 5
passed: true
comment: Correct stem plot via geom_segment + geom_point + geom_hline
- id: SC-02
name: Required Features
score: 4
max: 4
passed: true
comment: Thin stems, visible circular markers, y=0 baseline, consistent sizing
- id: SC-03
name: Data Mapping
score: 3
max: 3
passed: true
comment: Sample index on x, amplitude on y; all 30 points visible
- id: SC-04
name: Title & Legend
score: 3
max: 3
passed: true
comment: Title 'stem-basic · plotnine · anyplot.ai' correct; no legend appropriate
for single series
data_quality:
score: 15
max: 15
items:
- id: DQ-01
name: Feature Coverage
score: 6
max: 6
passed: true
comment: Shows positive AND negative values, oscillation, and decay envelope
— all stem plot characteristics
- id: DQ-02
name: Realistic Context
score: 5
max: 5
passed: true
comment: Damped sinusoidal signal is a textbook signal processing example;
neutral and scientific
- id: DQ-03
name: Appropriate Scale
score: 4
max: 4
passed: true
comment: 30 samples, normalized amplitude range, physically plausible decay
constant and frequency
code_quality:
score: 10
max: 10
items:
- id: CQ-01
name: KISS Structure
score: 3
max: 3
passed: true
comment: Clean Imports → Data → Plot → Save; no functions or classes
- id: CQ-02
name: Reproducibility
score: 2
max: 2
passed: true
comment: np.random.seed(42) set
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
comment: All 11 plotnine imports are used
- id: CQ-04
name: Code Elegance
score: 2
max: 2
passed: true
comment: Pythonic, appropriate complexity, no over-engineering
- id: CQ-05
name: Output & API
score: 1
max: 1
passed: true
comment: Saves as plot-{THEME}.png, current API throughout
library_mastery:
score: 8
max: 10
items:
- id: LM-01
name: Idiomatic Usage
score: 5
max: 5
passed: true
comment: 'Fully idiomatic grammar of graphics: layered geoms, aes() mappings,
theme() customization'
- id: LM-02
name: Distinctive Features
score: 3
max: 5
passed: true
comment: Composing stem plot from primitive geoms (geom_segment + geom_point
+ geom_hline) demonstrates grammar-of-graphics thinking; somewhat library-specific
but not exceptional
verdict: APPROVED
impl_tags:
dependencies: []
techniques:
- layer-composition
patterns:
- data-generation
dataprep: []
styling:
- grid-styling
Loading