Skip to content

Commit 33205a2

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

File tree

2 files changed

+407
-0
lines changed

2 files changed

+407
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
""" pyplots.ai
2+
scatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis
3+
Library: plotly 6.7.0 | Python 3.14.3
4+
Quality: 89/100 | Created: 2026-04-12
5+
"""
6+
7+
import numpy as np
8+
import plotly.graph_objects as go
9+
10+
11+
# Data - synthetic AR(1) temperature process with strong autocorrelation
12+
np.random.seed(42)
13+
n_points = 500
14+
phi = 0.85
15+
noise = np.random.normal(0, 1, n_points)
16+
temperature = np.zeros(n_points)
17+
temperature[0] = 20.0
18+
for i in range(1, n_points):
19+
temperature[i] = phi * temperature[i - 1] + (1 - phi) * 20.0 + noise[i]
20+
21+
lag = 1
22+
y_t = temperature[:-lag]
23+
y_t_lag = temperature[lag:]
24+
time_index = np.arange(len(y_t))
25+
26+
# Correlation coefficient
27+
correlation = np.corrcoef(y_t, y_t_lag)[0, 1]
28+
29+
# Regression line through the data
30+
slope, intercept = np.polyfit(y_t, y_t_lag, 1)
31+
x_fit = np.array([y_t.min(), y_t.max()])
32+
y_fit = slope * x_fit + intercept
33+
34+
# Plot
35+
fig = go.Figure()
36+
37+
# Scatter points with Plasma for stronger visual contrast
38+
fig.add_trace(
39+
go.Scatter(
40+
x=y_t,
41+
y=y_t_lag,
42+
mode="markers",
43+
marker={
44+
"size": 7,
45+
"color": time_index,
46+
"colorscale": "Plasma",
47+
"colorbar": {
48+
"title": {"text": "Time Index", "font": {"size": 18, "color": "#444444"}},
49+
"tickfont": {"size": 16, "color": "#666666"},
50+
"thickness": 18,
51+
"len": 0.65,
52+
"outlinewidth": 0,
53+
"y": 0.5,
54+
},
55+
"opacity": 0.55,
56+
"line": {"width": 0.3, "color": "rgba(255,255,255,0.6)"},
57+
},
58+
hovertemplate=(
59+
"<b>Time %{customdata}</b><br>Temp at t: %{x:.1f} °C<br>Temp at t+1: %{y:.1f} °C<extra></extra>"
60+
),
61+
customdata=time_index,
62+
)
63+
)
64+
65+
# Diagonal reference line (y = x)
66+
data_min = min(y_t.min(), y_t_lag.min())
67+
data_max = max(y_t.max(), y_t_lag.max())
68+
padding = (data_max - data_min) * 0.05
69+
line_min = data_min - padding
70+
line_max = data_max + padding
71+
72+
fig.add_trace(
73+
go.Scatter(
74+
x=[line_min, line_max],
75+
y=[line_min, line_max],
76+
mode="lines",
77+
line={"color": "rgba(0,0,0,0.15)", "width": 1.5, "dash": "dot"},
78+
showlegend=False,
79+
hoverinfo="skip",
80+
name="y = x",
81+
)
82+
)
83+
84+
# Regression trend line
85+
fig.add_trace(
86+
go.Scatter(
87+
x=x_fit,
88+
y=y_fit,
89+
mode="lines",
90+
line={"color": "#306998", "width": 2.5},
91+
showlegend=False,
92+
hoverinfo="skip",
93+
name="trend",
94+
)
95+
)
96+
97+
# Layout with custom background and removed axis borders
98+
fig.update_layout(
99+
title={
100+
"text": "scatter-lag · plotly · pyplots.ai",
101+
"font": {"size": 28, "color": "#333333"},
102+
"x": 0.5,
103+
"xanchor": "center",
104+
"y": 0.96,
105+
},
106+
xaxis={
107+
"title": {"text": "Temperature (°C) at time t", "font": {"size": 22, "color": "#444444"}},
108+
"tickfont": {"size": 18, "color": "#666666"},
109+
"showgrid": True,
110+
"gridcolor": "rgba(0,0,0,0.06)",
111+
"gridwidth": 1,
112+
"zeroline": False,
113+
"showline": False,
114+
"ticks": "",
115+
},
116+
yaxis={
117+
"title": {"text": f"Temperature (°C) at time t+{lag}", "font": {"size": 22, "color": "#444444"}},
118+
"tickfont": {"size": 18, "color": "#666666"},
119+
"showgrid": True,
120+
"gridcolor": "rgba(0,0,0,0.06)",
121+
"gridwidth": 1,
122+
"zeroline": False,
123+
"showline": False,
124+
"ticks": "",
125+
},
126+
template="plotly_white",
127+
plot_bgcolor="#FFFFFF",
128+
paper_bgcolor="#F8F9FA",
129+
showlegend=False,
130+
margin={"l": 90, "r": 130, "t": 100, "b": 90},
131+
)
132+
133+
# Subtitle annotation for context
134+
fig.add_annotation(
135+
text="AR(1) process | lag = 1 | 500 observations",
136+
xref="paper",
137+
yref="paper",
138+
x=0.5,
139+
y=1.06,
140+
showarrow=False,
141+
font={"size": 16, "color": "#999999"},
142+
xanchor="center",
143+
)
144+
145+
# Correlation annotation - prominent and well-styled
146+
fig.add_annotation(
147+
text=f"<b>r = {correlation:.3f}</b>",
148+
xref="paper",
149+
yref="paper",
150+
x=0.03,
151+
y=0.97,
152+
showarrow=False,
153+
font={"size": 24, "color": "#306998"},
154+
bgcolor="rgba(255,255,255,0.9)",
155+
bordercolor="rgba(48,105,152,0.3)",
156+
borderwidth=1.5,
157+
borderpad=10,
158+
)
159+
160+
# Save
161+
fig.write_image("plot.png", width=1600, height=900, scale=3)
162+
fig.write_html("plot.html", include_plotlyjs="cdn")

0 commit comments

Comments
 (0)