Skip to content

Commit 4f7c064

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

File tree

2 files changed

+344
-0
lines changed

2 files changed

+344
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
""" pyplots.ai
2+
scatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis
3+
Library: seaborn 0.13.2 | Python 3.14.3
4+
Quality: 89/100 | Created: 2026-04-12
5+
"""
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
import pandas as pd
10+
import seaborn as sns
11+
12+
13+
# Data - synthetic AR(1) process with strong positive autocorrelation
14+
np.random.seed(42)
15+
n = 500
16+
phi = 0.85
17+
noise = np.random.normal(0, 1, n)
18+
19+
values = np.zeros(n)
20+
values[0] = noise[0]
21+
for t in range(1, n):
22+
values[t] = phi * values[t - 1] + noise[t]
23+
24+
# Lag plot data (lag = 1)
25+
lag = 1
26+
y_t = values[:-lag]
27+
y_t_lag = values[lag:]
28+
time_index = np.arange(len(y_t))
29+
30+
df = pd.DataFrame({"y(t)": y_t, "y(t + 1)": y_t_lag, "Time Index": time_index})
31+
32+
r = np.corrcoef(y_t, y_t_lag)[0, 1]
33+
34+
# Plot
35+
sns.set_theme(
36+
style="ticks",
37+
context="talk",
38+
font_scale=1.1,
39+
rc={"font.family": "sans-serif", "axes.edgecolor": "#888888", "axes.linewidth": 0.8},
40+
)
41+
42+
fig, ax = plt.subplots(figsize=(16, 9))
43+
44+
sns.scatterplot(
45+
data=df,
46+
x="y(t)",
47+
y="y(t + 1)",
48+
hue="Time Index",
49+
palette="viridis",
50+
s=35,
51+
alpha=0.45,
52+
edgecolor="white",
53+
linewidth=0.4,
54+
legend=False,
55+
ax=ax,
56+
zorder=3,
57+
)
58+
59+
# Diagonal reference line (y = x)
60+
data_min = min(y_t.min(), y_t_lag.min())
61+
data_max = max(y_t.max(), y_t_lag.max())
62+
margin = (data_max - data_min) * 0.05
63+
ax.plot(
64+
[data_min - margin, data_max + margin],
65+
[data_min - margin, data_max + margin],
66+
color="#c44e52",
67+
linewidth=2,
68+
linestyle="--",
69+
alpha=0.6,
70+
zorder=2,
71+
)
72+
73+
# Colorbar for temporal structure
74+
norm = plt.Normalize(df["Time Index"].min(), df["Time Index"].max())
75+
sm = plt.cm.ScalarMappable(cmap="viridis", norm=norm)
76+
cbar = plt.colorbar(sm, ax=ax, pad=0.02, aspect=30)
77+
cbar.set_label("Time Index", fontsize=18, color="#444444")
78+
cbar.ax.tick_params(labelsize=14)
79+
80+
# Correlation coefficient
81+
ax.annotate(
82+
f"r = {r:.2f}",
83+
xy=(0.03, 0.96),
84+
xycoords="axes fraction",
85+
fontsize=18,
86+
fontweight="bold",
87+
color="#444444",
88+
ha="left",
89+
va="top",
90+
bbox={"boxstyle": "round,pad=0.4", "facecolor": "white", "edgecolor": "#cccccc", "alpha": 0.9},
91+
)
92+
93+
# Style
94+
ax.set_title("scatter-lag · seaborn · pyplots.ai", fontsize=24, fontweight="medium", color="#333333", pad=16)
95+
ax.set_xlabel("y(t)", fontsize=20, color="#444444")
96+
ax.set_ylabel("y(t + 1)", fontsize=20, color="#444444")
97+
ax.tick_params(axis="both", labelsize=16, colors="#555555")
98+
ax.grid(True, alpha=0.15, linewidth=0.6)
99+
sns.despine(ax=ax)
100+
101+
plt.tight_layout()
102+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
library: seaborn
2+
specification_id: scatter-lag
3+
created: '2026-04-12T18:10:33Z'
4+
updated: '2026-04-12T18:25:33Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 24313009886
7+
issue: 5251
8+
python_version: 3.14.3
9+
library_version: 0.13.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-lag/seaborn/plot.png
11+
preview_html: null
12+
quality_score: 89
13+
review:
14+
strengths:
15+
- 'Perfect spec compliance: diagonal reference line, time-index coloring, and r-value
16+
annotation all implemented exactly as specified'
17+
- 'Excellent visual quality: font sizes explicitly set to correct values, viridis
18+
colormap is colorblind-safe and semantically meaningful for temporal ordering'
19+
- Clean, reproducible code with appropriate marker size/alpha calibration for the
20+
dataset density (s=35, alpha=0.45 for 499 points)
21+
weaknesses:
22+
- Design excellence is good but not exceptional — the aesthetic is polished but
23+
not publication-ready; a more distinctive visual treatment would push DE-01 from
24+
5 to 6-7
25+
- Data storytelling only demonstrates one scenario (strong positive autocorrelation);
26+
contrasting with what weak/no autocorrelation looks like would strengthen the
27+
diagnostic narrative
28+
image_description: The plot shows a scatter lag plot of a synthetic AR(1) time series
29+
on a 16:9 canvas. The x-axis is labeled "y(t)" and the y-axis "y(t + 1)", both
30+
in clean sans-serif font. Approximately 499 scatter points are rendered with the
31+
viridis colormap (purple → teal → green → yellow) encoding the time index from
32+
0 to ~499. A red dashed diagonal reference line (y = x) runs from bottom-left
33+
to top-right, visually anchoring the correlation pattern. A colorbar on the right
34+
side of the plot is labeled "Time Index" with tick marks from 0 to 400. In the
35+
top-left corner, a rounded annotation box displays "r = 0.83" in bold dark text
36+
on a white background with a light grey border. The title reads "scatter-lag ·
37+
seaborn · pyplots.ai" at the top. The plot uses the seaborn "ticks" style with
38+
top/right spines removed and a very faint grey grid. The x-axis ranges from approximately
39+
-5 to 6 and the y-axis from approximately -4 to 6. The scatter shows a clear linear
40+
pattern along the diagonal, indicating strong positive autocorrelation at lag
41+
1. The viridis color gradient shows no systematic temporal drift — early (purple)
42+
and late (yellow) observations are mixed throughout, confirming the stationarity
43+
of the process. Overall layout is clean and balanced.
44+
criteria_checklist:
45+
visual_quality:
46+
score: 30
47+
max: 30
48+
items:
49+
- id: VQ-01
50+
name: Text Legibility
51+
score: 8
52+
max: 8
53+
passed: true
54+
comment: 'All font sizes explicitly set: title 24pt, labels 20pt, ticks 16pt,
55+
colorbar label 18pt, annotation 18pt'
56+
- id: VQ-02
57+
name: No Overlap
58+
score: 6
59+
max: 6
60+
passed: true
61+
comment: No text collisions; annotation box, colorbar, axis labels, and title
62+
occupy distinct regions
63+
- id: VQ-03
64+
name: Element Visibility
65+
score: 6
66+
max: 6
67+
passed: true
68+
comment: s=35, alpha=0.45 well-calibrated for 499 points; points clearly visible
69+
without over-saturation
70+
- id: VQ-04
71+
name: Color Accessibility
72+
score: 4
73+
max: 4
74+
passed: true
75+
comment: Viridis is perceptually uniform and colorblind-safe; red dashed line
76+
provides clear contrast
77+
- id: VQ-05
78+
name: Layout & Canvas
79+
score: 4
80+
max: 4
81+
passed: true
82+
comment: Balanced margins, plot fills ~65-70% of canvas width; colorbar appropriately
83+
sized
84+
- id: VQ-06
85+
name: Axis Labels & Title
86+
score: 2
87+
max: 2
88+
passed: true
89+
comment: y(t) / y(t+1) is standard lag plot notation; descriptive and domain-appropriate
90+
design_excellence:
91+
score: 13
92+
max: 20
93+
items:
94+
- id: DE-01
95+
name: Aesthetic Sophistication
96+
score: 5
97+
max: 8
98+
passed: true
99+
comment: 'Above well-configured default: muted reference line color, viridis
100+
for temporal ordering, styled annotation box. Intentional and cohesive,
101+
but stops short of publication-ready polish'
102+
- id: DE-02
103+
name: Visual Refinement
104+
score: 4
105+
max: 6
106+
passed: true
107+
comment: Top/right spines removed via sns.despine; grid is very subtle (alpha=0.15,
108+
linewidth=0.6); custom axis edge color. Good refinement above defaults
109+
- id: DE-03
110+
name: Data Storytelling
111+
score: 4
112+
max: 6
113+
passed: true
114+
comment: 'Visual hierarchy works: viridis coloring reveals temporal uniformity;
115+
r=0.83 gives immediate quantitative context; reference line anchors interpretation.
116+
Only one autocorrelation scenario shown'
117+
spec_compliance:
118+
score: 15
119+
max: 15
120+
items:
121+
- id: SC-01
122+
name: Plot Type
123+
score: 5
124+
max: 5
125+
passed: true
126+
comment: Correct scatter of y(t) vs y(t+k) for lag k=1
127+
- id: SC-02
128+
name: Required Features
129+
score: 4
130+
max: 4
131+
passed: true
132+
comment: Diagonal reference line, time-index coloring, correlation annotation,
133+
configurable lag variable — all present
134+
- id: SC-03
135+
name: Data Mapping
136+
score: 3
137+
max: 3
138+
passed: true
139+
comment: x=y(t), y=y(t+1); time index mapped to viridis color; axes show full
140+
data range
141+
- id: SC-04
142+
name: Title & Legend
143+
score: 3
144+
max: 3
145+
passed: true
146+
comment: Title format 'scatter-lag · seaborn · pyplots.ai' correct; colorbar
147+
serves as legend for time index
148+
data_quality:
149+
score: 14
150+
max: 15
151+
items:
152+
- id: DQ-01
153+
name: Feature Coverage
154+
score: 5
155+
max: 6
156+
passed: true
157+
comment: 'AR(1) with phi=0.85 clearly shows strong positive autocorrelation.
158+
Minor deduction: only one scenario shown; contrasting with random data would
159+
strengthen diagnostic utility'
160+
- id: DQ-02
161+
name: Realistic Context
162+
score: 5
163+
max: 5
164+
passed: true
165+
comment: Synthetic AR(1) process explicitly listed in spec as example data;
166+
neutral and scientifically plausible
167+
- id: DQ-03
168+
name: Appropriate Scale
169+
score: 4
170+
max: 4
171+
passed: true
172+
comment: phi=0.85 with unit-variance noise yields values in [-4, 6], appropriate
173+
for standardized financial/environmental time series
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)
190+
- id: CQ-03
191+
name: Clean Imports
192+
score: 2
193+
max: 2
194+
passed: true
195+
comment: matplotlib.pyplot, numpy, pandas, seaborn — all used, none superfluous
196+
- id: CQ-04
197+
name: Code Elegance
198+
score: 2
199+
max: 2
200+
passed: true
201+
comment: Clean, Pythonic; appropriate complexity; no fake UI elements
202+
- id: CQ-05
203+
name: Output & API
204+
score: 1
205+
max: 1
206+
passed: true
207+
comment: plt.savefig('plot.png', dpi=300, bbox_inches='tight'); current seaborn
208+
0.13 API
209+
library_features:
210+
score: 7
211+
max: 10
212+
items:
213+
- id: LM-01
214+
name: Idiomatic Usage
215+
score: 4
216+
max: 5
217+
passed: true
218+
comment: 'sns.set_theme with custom rc params, sns.scatterplot with continuous
219+
hue, sns.despine — all idiomatic. Minor deduction: colorbar added via matplotlib
220+
ScalarMappable (legend=False limitation)'
221+
- id: LM-02
222+
name: Distinctive Features
223+
score: 3
224+
max: 5
225+
passed: true
226+
comment: Seaborn's continuous hue encoding in scatterplot with viridis palette
227+
is library-distinctive. Most visual decoration (colorbar, annotation, reference
228+
line) handled through matplotlib directly
229+
verdict: REJECTED
230+
impl_tags:
231+
dependencies: []
232+
techniques:
233+
- colorbar
234+
- annotations
235+
patterns:
236+
- data-generation
237+
- explicit-figure
238+
dataprep: []
239+
styling:
240+
- alpha-blending
241+
- custom-colormap
242+
- edge-highlighting

0 commit comments

Comments
 (0)