Skip to content

Commit 95301d1

Browse files
feat(plotnine): implement scatter-lag (#5275)
## Implementation: `scatter-lag` - plotnine Implements the **plotnine** version of `scatter-lag`. **File:** `plots/scatter-lag/implementations/plotnine.py` **Parent Issue:** #5251 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/24313009899)* --------- 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 c16bec6 commit 95301d1

File tree

2 files changed

+310
-0
lines changed

2 files changed

+310
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
""" pyplots.ai
2+
scatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis
3+
Library: plotnine 0.15.3 | Python 3.14.3
4+
Quality: 88/100 | Created: 2026-04-12
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
from plotnine import (
10+
aes,
11+
element_blank,
12+
element_line,
13+
element_text,
14+
facet_wrap,
15+
geom_abline,
16+
geom_point,
17+
ggplot,
18+
labs,
19+
scale_color_gradient,
20+
theme,
21+
theme_minimal,
22+
)
23+
24+
25+
# Data - Daily temperature with natural autocorrelation (AR(1) process)
26+
np.random.seed(42)
27+
n = 300
28+
phi = 0.85
29+
noise = np.random.normal(0, 2.5, n)
30+
temperatures = np.zeros(n)
31+
temperatures[0] = 20 + noise[0]
32+
for i in range(1, n):
33+
temperatures[i] = (1 - phi) * 20 + phi * temperatures[i - 1] + noise[i]
34+
35+
# Create lag data for multiple lag values
36+
lags = [1, 3, 7]
37+
rows = []
38+
for lag in lags:
39+
for i in range(n - lag):
40+
rows.append(
41+
{
42+
"temp_t": temperatures[i],
43+
"temp_t_lag": temperatures[i + lag],
44+
"day": i,
45+
"lag": f"Lag = {lag} day{'s' if lag > 1 else ''}",
46+
}
47+
)
48+
df = pd.DataFrame(rows)
49+
df["lag"] = pd.Categorical(df["lag"], categories=[f"Lag = {k} day{'s' if k > 1 else ''}" for k in lags], ordered=True)
50+
51+
# Plot
52+
plot = (
53+
ggplot(df, aes(x="temp_t", y="temp_t_lag", color="day"))
54+
+ geom_abline(intercept=0, slope=1, color="#BBBBBB", linetype="dashed", size=0.7)
55+
+ geom_point(size=3, alpha=0.65)
56+
+ facet_wrap("lag", ncol=3)
57+
+ scale_color_gradient(low="#306998", high="#E8A838", name="Day")
58+
+ labs(
59+
x="Temperature at Day t (°C)",
60+
y="Temperature at Day t+k (°C)",
61+
title="Daily Temperature · scatter-lag · plotnine · pyplots.ai",
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+
strip_text=element_text(size=18, weight="bold"),
70+
legend_title=element_text(size=16),
71+
legend_text=element_text(size=14),
72+
panel_grid_major=element_line(color="#E8E8E8", size=0.5),
73+
panel_grid_minor=element_blank(),
74+
axis_ticks=element_blank(),
75+
)
76+
)
77+
78+
# Save
79+
plot.save("plot.png", dpi=300)
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
library: plotnine
2+
specification_id: scatter-lag
3+
created: '2026-04-12T18:13:17Z'
4+
updated: '2026-04-12T18:17:42Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 24313009899
7+
issue: 5251
8+
python_version: 3.14.3
9+
library_version: 0.15.3
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-lag/plotnine/plot.png
11+
preview_html: null
12+
quality_score: 88
13+
review:
14+
strengths:
15+
- 'Perfect code quality: KISS structure, reproducible seed, all imports used, clean
16+
Pythonic code throughout'
17+
- 'Full spec compliance: all three required features (configurable lags, diagonal
18+
reference line, temporal color coding) correctly implemented'
19+
- 'Excellent data quality: AR(1) daily temperature is a realistic neutral scenario;
20+
scale and autocorrelation strength are appropriate'
21+
- Explicit font size configuration at all levels meets the 24/20/16pt requirements
22+
weaknesses:
23+
- Title format starts with 'Daily Temperature' prefix instead of spec-id; should
24+
start with 'scatter-lag · plotnine · pyplots.ai'
25+
- 'Color gradient (#306998 to #E8A838) is not a formally colorblind-optimized palette;
26+
consider viridis or plasma'
27+
- Design could reach publication quality with explicit spine removal, coord_fixed()
28+
for equal axis scales, and stronger visual identity
29+
image_description: Three faceted scatter plots arranged side by side, titled "Daily
30+
Temperature · scatter-lag · plotnine · pyplots.ai". Each panel shows daily temperature
31+
at day t (°C) on the x-axis vs temperature at day t+k (°C) on the y-axis, for
32+
lags of 1, 3, and 7 days respectively. Points are colored on a blue-to-gold gradient
33+
representing the day index (0–200+), with a "Day" colorbar legend on the right.
34+
A dashed gray diagonal reference line (y=x) runs through each panel. The Lag=1
35+
panel shows tight clustering along the diagonal (strong autocorrelation); Lag=3
36+
shows moderate spread; Lag=7 shows noticeably more scatter — telling a clear visual
37+
story of autocorrelation decay. The layout is clean on a white background using
38+
theme_minimal with a subtle light gray grid. Temperature values range roughly
39+
from 10–30°C across all panels.
40+
criteria_checklist:
41+
visual_quality:
42+
score: 28
43+
max: 30
44+
items:
45+
- id: VQ-01
46+
name: Text Legibility
47+
score: 8
48+
max: 8
49+
passed: true
50+
comment: 'All font sizes explicitly set: title 24pt bold, axis titles 20pt,
51+
tick labels 16pt, strip text 18pt bold, legend 14-16pt'
52+
- id: VQ-02
53+
name: No Overlap
54+
score: 6
55+
max: 6
56+
passed: true
57+
comment: No overlapping text or elements across all three facets
58+
- id: VQ-03
59+
name: Element Visibility
60+
score: 5
61+
max: 6
62+
passed: true
63+
comment: Points well-sized for ~100 per facet; alpha=0.65 adequate but slightly
64+
high for density
65+
- id: VQ-04
66+
name: Color Accessibility
67+
score: 3
68+
max: 4
69+
passed: true
70+
comment: Blue-to-gold gradient not red-green but not formally colorblind-optimized
71+
(no viridis)
72+
- id: VQ-05
73+
name: Layout & Canvas
74+
score: 4
75+
max: 4
76+
passed: true
77+
comment: Three facets fill canvas well; legend positioned cleanly; balanced
78+
margins
79+
- id: VQ-06
80+
name: Axis Labels & Title
81+
score: 2
82+
max: 2
83+
passed: true
84+
comment: 'Descriptive labels with units: Temperature at Day t (°C) and Temperature
85+
at Day t+k (°C)'
86+
design_excellence:
87+
score: 13
88+
max: 20
89+
items:
90+
- id: DE-01
91+
name: Aesthetic Sophistication
92+
score: 5
93+
max: 8
94+
passed: true
95+
comment: Thoughtful color choice (Python Blue to amber), bold strip labels,
96+
clean minimal theme; above defaults but short of publication-ready
97+
- id: DE-02
98+
name: Visual Refinement
99+
score: 4
100+
max: 6
101+
passed: true
102+
comment: Subtle gray grid, minor grid removed, tick marks removed; good refinement
103+
but no explicit spine removal beyond theme_minimal
104+
- id: DE-03
105+
name: Data Storytelling
106+
score: 4
107+
max: 6
108+
passed: true
109+
comment: Multiple lags tell visual story of autocorrelation decay; temporal
110+
color coding reveals structure; viewer reads insight clearly
111+
spec_compliance:
112+
score: 14
113+
max: 15
114+
items:
115+
- id: SC-01
116+
name: Plot Type
117+
score: 5
118+
max: 5
119+
passed: true
120+
comment: 'Correct lag plot: scatter of y(t) vs y(t+k)'
121+
- id: SC-02
122+
name: Required Features
123+
score: 4
124+
max: 4
125+
passed: true
126+
comment: Configurable lags (1,3,7), diagonal reference line, color by time
127+
index all present
128+
- id: SC-03
129+
name: Data Mapping
130+
score: 3
131+
max: 3
132+
passed: true
133+
comment: X=y(t), Y=y(t+k) as specified; all data visible
134+
- id: SC-04
135+
name: Title & Legend
136+
score: 2
137+
max: 3
138+
passed: false
139+
comment: Title has extra prefix 'Daily Temperature' before spec-id; should
140+
start with 'scatter-lag · plotnine · pyplots.ai'
141+
data_quality:
142+
score: 15
143+
max: 15
144+
items:
145+
- id: DQ-01
146+
name: Feature Coverage
147+
score: 6
148+
max: 6
149+
passed: true
150+
comment: 'Shows all aspects: multiple lags demonstrating autocorrelation decay,
151+
temporal color structure, diagonal reference, realistic data spread'
152+
- id: DQ-02
153+
name: Realistic Context
154+
score: 5
155+
max: 5
156+
passed: true
157+
comment: Daily temperature AR(1) process is a classic, neutral, real-world
158+
time series scenario
159+
- id: DQ-03
160+
name: Appropriate Scale
161+
score: 4
162+
max: 4
163+
passed: true
164+
comment: 10-30 degrees C range realistic; phi=0.85 produces natural AR(1)
165+
behavior
166+
code_quality:
167+
score: 10
168+
max: 10
169+
items:
170+
- id: CQ-01
171+
name: KISS Structure
172+
score: 3
173+
max: 3
174+
passed: true
175+
comment: Clean Imports -> Data -> Plot -> Save; no functions or classes
176+
- id: CQ-02
177+
name: Reproducibility
178+
score: 2
179+
max: 2
180+
passed: true
181+
comment: np.random.seed(42) set
182+
- id: CQ-03
183+
name: Clean Imports
184+
score: 2
185+
max: 2
186+
passed: true
187+
comment: All 12 imported names are used
188+
- id: CQ-04
189+
name: Code Elegance
190+
score: 2
191+
max: 2
192+
passed: true
193+
comment: Pythonic, appropriate complexity; AR(1) loop is necessary, not over-engineered
194+
- id: CQ-05
195+
name: Output & API
196+
score: 1
197+
max: 1
198+
passed: true
199+
comment: plot.save('plot.png', dpi=300) correct
200+
library_mastery:
201+
score: 8
202+
max: 10
203+
items:
204+
- id: LM-01
205+
name: Idiomatic Usage
206+
score: 5
207+
max: 5
208+
passed: true
209+
comment: 'Expert ggplot grammar: layered geoms, facet_wrap, scale_color_gradient,
210+
labs, theme overrides — all idiomatic plotnine'
211+
- id: LM-02
212+
name: Distinctive Features
213+
score: 3
214+
max: 5
215+
passed: true
216+
comment: facet_wrap for small multiples and scale_color_gradient are distinctively
217+
ggplot-idiomatic; could push with coord_fixed() or stat_smooth()
218+
verdict: REJECTED
219+
impl_tags:
220+
dependencies: []
221+
techniques:
222+
- faceting
223+
- layer-composition
224+
patterns:
225+
- data-generation
226+
- iteration-over-groups
227+
dataprep:
228+
- time-series
229+
styling:
230+
- custom-colormap
231+
- alpha-blending

0 commit comments

Comments
 (0)