Skip to content

Commit 5ff967a

Browse files
Merge branch 'main' into claude/improve-test-coverage-zo0aK
2 parents 4057e24 + e743d59 commit 5ff967a

File tree

18 files changed

+3255
-0
lines changed

18 files changed

+3255
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
""" pyplots.ai
2+
scatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis
3+
Library: altair 6.0.0 | Python 3.14.3
4+
Quality: 90/100 | Created: 2026-04-12
5+
"""
6+
7+
import altair as alt
8+
import numpy as np
9+
import pandas as pd
10+
11+
12+
# Data - synthetic AR(1) process with moderate autocorrelation
13+
np.random.seed(42)
14+
n_points = 500
15+
lag = 1
16+
phi = 0.85
17+
noise = np.random.normal(0, 1, n_points)
18+
values = np.zeros(n_points)
19+
values[0] = noise[0]
20+
for i in range(1, n_points):
21+
values[i] = phi * values[i - 1] + noise[i]
22+
23+
y_t = values[:-lag]
24+
y_t_lag = values[lag:]
25+
r_value = np.corrcoef(y_t, y_t_lag)[0, 1]
26+
27+
df = pd.DataFrame({"y_t": y_t, "y_t_lag": y_t_lag, "time_index": np.arange(n_points - lag)})
28+
29+
# Reference line (y = x diagonal)
30+
margin = 0.5
31+
axis_min = min(df["y_t"].min(), df["y_t_lag"].min()) - margin
32+
axis_max = max(df["y_t"].max(), df["y_t_lag"].max()) + margin
33+
ref_df = pd.DataFrame({"x": [axis_min, axis_max], "y": [axis_min, axis_max]})
34+
35+
# Annotation for correlation coefficient
36+
annot_df = pd.DataFrame({"x": [axis_max - 0.3], "y": [axis_min + 0.5], "label": [f"r = {r_value:.3f}"]})
37+
38+
# Reference line
39+
reference_line = (
40+
alt.Chart(ref_df).mark_line(strokeDash=[8, 6], strokeWidth=1.5, color="#aaaaaa").encode(x="x:Q", y="y:Q")
41+
)
42+
43+
# Scatter points with reduced size/opacity to prevent overplotting
44+
points = (
45+
alt.Chart(df)
46+
.mark_point(size=45, filled=True, strokeWidth=0.5, stroke="white", opacity=0.45)
47+
.encode(
48+
x=alt.X("y_t:Q", title="y(t)", scale=alt.Scale(domain=[axis_min, axis_max]), axis=alt.Axis(tickCount=10)),
49+
y=alt.Y(
50+
"y_t_lag:Q", title="y(t + 1)", scale=alt.Scale(domain=[axis_min, axis_max]), axis=alt.Axis(tickCount=10)
51+
),
52+
color=alt.Color(
53+
"time_index:Q",
54+
scale=alt.Scale(scheme="viridis"),
55+
legend=alt.Legend(
56+
title="Time Index",
57+
titleFontSize=16,
58+
labelFontSize=16,
59+
gradientLength=280,
60+
gradientThickness=14,
61+
orient="right",
62+
offset=10,
63+
),
64+
),
65+
tooltip=[
66+
alt.Tooltip("y_t:Q", title="y(t)", format=".2f"),
67+
alt.Tooltip("y_t_lag:Q", title="y(t+1)", format=".2f"),
68+
alt.Tooltip("time_index:Q", title="Time Index"),
69+
],
70+
)
71+
)
72+
73+
# Correlation annotation
74+
annotation = (
75+
alt.Chart(annot_df)
76+
.mark_text(align="right", baseline="bottom", fontSize=20, fontWeight="bold", color="#333333")
77+
.encode(x="x:Q", y="y:Q", text="label:N")
78+
)
79+
80+
chart = (
81+
(reference_line + points + annotation)
82+
.properties(
83+
width=1600,
84+
height=900,
85+
title=alt.Title(
86+
"scatter-lag · altair · pyplots.ai",
87+
fontSize=28,
88+
subtitle=f"AR(1) process (φ = {phi}) | lag = {lag}",
89+
subtitleFontSize=18,
90+
subtitleColor="#666666",
91+
),
92+
)
93+
.configure_axis(
94+
labelFontSize=18,
95+
titleFontSize=22,
96+
grid=True,
97+
gridOpacity=0.15,
98+
gridWidth=0.5,
99+
domainWidth=0,
100+
tickSize=6,
101+
tickWidth=0.8,
102+
tickColor="#999999",
103+
labelColor="#444444",
104+
titleColor="#333333",
105+
)
106+
.configure_view(strokeWidth=0)
107+
.configure_title(anchor="start", offset=10)
108+
)
109+
110+
# Save
111+
chart.save("plot.png", scale_factor=3.0)
112+
chart.save("plot.html")
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
""" pyplots.ai
2+
scatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis
3+
Library: bokeh 3.9.0 | Python 3.14.3
4+
Quality: 85/100 | Created: 2026-04-12
5+
"""
6+
7+
import numpy as np
8+
from bokeh.io import export_png, save
9+
from bokeh.models import ColorBar, ColumnDataSource, Label, LinearColorMapper
10+
from bokeh.palettes import Viridis256
11+
from bokeh.plotting import figure
12+
from bokeh.resources import CDN
13+
from bokeh.transform import linear_cmap
14+
15+
16+
# Data - AR(1) process with moderate positive autocorrelation
17+
np.random.seed(42)
18+
n_obs = 500
19+
phi = 0.85
20+
noise = np.random.normal(0, 1, n_obs)
21+
series = np.zeros(n_obs)
22+
series[0] = noise[0]
23+
for i in range(1, n_obs):
24+
series[i] = phi * series[i - 1] + noise[i]
25+
26+
lag = 1
27+
y_t = series[:-lag]
28+
y_t_lag = series[lag:]
29+
time_index = np.arange(len(y_t))
30+
31+
correlation = np.corrcoef(y_t, y_t_lag)[0, 1]
32+
33+
source = ColumnDataSource(data={"y_t": y_t, "y_t_lag": y_t_lag, "time_index": time_index})
34+
35+
# Plot
36+
color_mapper = LinearColorMapper(palette=Viridis256, low=time_index.min(), high=time_index.max())
37+
38+
p = figure(
39+
width=4800, height=2700, title="scatter-lag · bokeh · pyplots.ai", x_axis_label="y(t)", y_axis_label="y(t + 1)"
40+
)
41+
42+
p.scatter(
43+
x="y_t",
44+
y="y_t_lag",
45+
source=source,
46+
size=20,
47+
fill_color=linear_cmap("time_index", palette=Viridis256, low=time_index.min(), high=time_index.max()),
48+
line_color="white",
49+
line_width=0.8,
50+
fill_alpha=0.8,
51+
)
52+
53+
# Diagonal reference line (y = x)
54+
axis_min = min(y_t.min(), y_t_lag.min()) - 0.5
55+
axis_max = max(y_t.max(), y_t_lag.max()) + 0.5
56+
p.line(
57+
[axis_min, axis_max], [axis_min, axis_max], line_color="#AAAAAA", line_dash="dashed", line_width=3, line_alpha=0.5
58+
)
59+
60+
# Color bar for time index
61+
color_bar = ColorBar(
62+
color_mapper=color_mapper,
63+
title="Time Index",
64+
title_text_font_size="22pt",
65+
title_standoff=20,
66+
major_label_text_font_size="18pt",
67+
label_standoff=12,
68+
width=50,
69+
padding=40,
70+
)
71+
p.add_layout(color_bar, "right")
72+
73+
# Correlation annotation
74+
corr_label = Label(
75+
x=axis_min + 0.3, y=axis_max - 0.5, text=f"r = {correlation:.3f}", text_font_size="24pt", text_color="#333333"
76+
)
77+
p.add_layout(corr_label)
78+
79+
# Style
80+
p.title.text_font_size = "32pt"
81+
p.title.text_font_style = "normal"
82+
p.xaxis.axis_label_text_font_size = "24pt"
83+
p.yaxis.axis_label_text_font_size = "24pt"
84+
p.xaxis.major_label_text_font_size = "20pt"
85+
p.yaxis.major_label_text_font_size = "20pt"
86+
87+
p.xaxis.minor_tick_line_color = None
88+
p.yaxis.minor_tick_line_color = None
89+
p.xaxis.major_tick_line_color = None
90+
p.yaxis.major_tick_line_color = None
91+
92+
p.xgrid.grid_line_alpha = 0.2
93+
p.ygrid.grid_line_alpha = 0.2
94+
p.xgrid.grid_line_width = 1
95+
p.ygrid.grid_line_width = 1
96+
97+
p.outline_line_color = None
98+
p.background_fill_color = "#FFFFFF"
99+
p.border_fill_color = "#FFFFFF"
100+
101+
p.toolbar_location = None
102+
103+
# Save
104+
export_png(p, filename="plot.png")
105+
save(p, filename="plot.html", resources=CDN, title="scatter-lag · bokeh · pyplots.ai")

0 commit comments

Comments
 (0)