diff --git a/plots/scatter-lag/implementations/altair.py b/plots/scatter-lag/implementations/altair.py new file mode 100644 index 0000000000..f49c4bcaf5 --- /dev/null +++ b/plots/scatter-lag/implementations/altair.py @@ -0,0 +1,112 @@ +""" pyplots.ai +scatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis +Library: altair 6.0.0 | Python 3.14.3 +Quality: 90/100 | Created: 2026-04-12 +""" + +import altair as alt +import numpy as np +import pandas as pd + + +# Data - synthetic AR(1) process with moderate autocorrelation +np.random.seed(42) +n_points = 500 +lag = 1 +phi = 0.85 +noise = np.random.normal(0, 1, n_points) +values = np.zeros(n_points) +values[0] = noise[0] +for i in range(1, n_points): + values[i] = phi * values[i - 1] + noise[i] + +y_t = values[:-lag] +y_t_lag = values[lag:] +r_value = np.corrcoef(y_t, y_t_lag)[0, 1] + +df = pd.DataFrame({"y_t": y_t, "y_t_lag": y_t_lag, "time_index": np.arange(n_points - lag)}) + +# Reference line (y = x diagonal) +margin = 0.5 +axis_min = min(df["y_t"].min(), df["y_t_lag"].min()) - margin +axis_max = max(df["y_t"].max(), df["y_t_lag"].max()) + margin +ref_df = pd.DataFrame({"x": [axis_min, axis_max], "y": [axis_min, axis_max]}) + +# Annotation for correlation coefficient +annot_df = pd.DataFrame({"x": [axis_max - 0.3], "y": [axis_min + 0.5], "label": [f"r = {r_value:.3f}"]}) + +# Reference line +reference_line = ( + alt.Chart(ref_df).mark_line(strokeDash=[8, 6], strokeWidth=1.5, color="#aaaaaa").encode(x="x:Q", y="y:Q") +) + +# Scatter points with reduced size/opacity to prevent overplotting +points = ( + alt.Chart(df) + .mark_point(size=45, filled=True, strokeWidth=0.5, stroke="white", opacity=0.45) + .encode( + x=alt.X("y_t:Q", title="y(t)", scale=alt.Scale(domain=[axis_min, axis_max]), axis=alt.Axis(tickCount=10)), + y=alt.Y( + "y_t_lag:Q", title="y(t + 1)", scale=alt.Scale(domain=[axis_min, axis_max]), axis=alt.Axis(tickCount=10) + ), + color=alt.Color( + "time_index:Q", + scale=alt.Scale(scheme="viridis"), + legend=alt.Legend( + title="Time Index", + titleFontSize=16, + labelFontSize=16, + gradientLength=280, + gradientThickness=14, + orient="right", + offset=10, + ), + ), + tooltip=[ + alt.Tooltip("y_t:Q", title="y(t)", format=".2f"), + alt.Tooltip("y_t_lag:Q", title="y(t+1)", format=".2f"), + alt.Tooltip("time_index:Q", title="Time Index"), + ], + ) +) + +# Correlation annotation +annotation = ( + alt.Chart(annot_df) + .mark_text(align="right", baseline="bottom", fontSize=20, fontWeight="bold", color="#333333") + .encode(x="x:Q", y="y:Q", text="label:N") +) + +chart = ( + (reference_line + points + annotation) + .properties( + width=1600, + height=900, + title=alt.Title( + "scatter-lag · altair · pyplots.ai", + fontSize=28, + subtitle=f"AR(1) process (φ = {phi}) | lag = {lag}", + subtitleFontSize=18, + subtitleColor="#666666", + ), + ) + .configure_axis( + labelFontSize=18, + titleFontSize=22, + grid=True, + gridOpacity=0.15, + gridWidth=0.5, + domainWidth=0, + tickSize=6, + tickWidth=0.8, + tickColor="#999999", + labelColor="#444444", + titleColor="#333333", + ) + .configure_view(strokeWidth=0) + .configure_title(anchor="start", offset=10) +) + +# Save +chart.save("plot.png", scale_factor=3.0) +chart.save("plot.html") diff --git a/plots/scatter-lag/metadata/altair.yaml b/plots/scatter-lag/metadata/altair.yaml new file mode 100644 index 0000000000..1e714cc04e --- /dev/null +++ b/plots/scatter-lag/metadata/altair.yaml @@ -0,0 +1,238 @@ +library: altair +specification_id: scatter-lag +created: '2026-04-12T18:11:36Z' +updated: '2026-04-12T18:24:56Z' +generated_by: claude-opus-4-5-20251101 +workflow_run: 24313009897 +issue: 5251 +python_version: 3.14.3 +library_version: 6.0.0 +preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-lag/altair/plot.png +preview_html: https://storage.googleapis.com/pyplots-images/plots/scatter-lag/altair/plot.html +quality_score: 90 +review: + strengths: + - Viridis colormap with opacity=0.45 and white edge strokes creates a professional, + layered look + - 'All required spec features present: diagonal reference line, time-index color + coding, correlation annotation, configurable lag' + - Altair layer composition (reference_line + points + annotation) is idiomatic and + clean + - Explicit font sizing throughout ensures legibility at 4800x2700px + - Subtle grid (opacity 0.15), no axis border, and removed domain line give a polished + clean background + weaknesses: + - DE-01 held back by lacking a truly distinctive visual signature (e.g., custom + highlight color, marginal distribution element) + - DE-02 could reach 6/6 with more generous outer padding and intentional whitespace + strategy + - 'VQ-06 partial: axis labels use mathematical notation without physical units (appropriate + for abstract data but not 2/2)' + - 'LM-02: could leverage Altair''s selection/brush interactivity or faceting to + show multiple lag values side-by-side' + image_description: A scatter lag plot showing 499 points from a synthetic AR(1) + process (phi=0.85). The x-axis is labeled "y(t)" and the y-axis "y(t + 1)", both + ranging from about -5 to 6. Points are colored using the viridis colormap (purple/blue + = early time index, yellow-green = late time index), with opacity=0.45 and white + edge strokes. A dashed gray diagonal reference line (y=x) runs from bottom-left + to top-right, making the strong positive autocorrelation immediately visible. + A bold "r = 0.834" annotation appears in the lower-right of the plot area. The + title reads "scatter-lag · altair · pyplots.ai" with subtitle "AR(1) process (phi + = 0.85) | lag = 1". A vertical viridis color legend labeled "Time Index" is positioned + on the right. The background is white with an extremely subtle grid, no axis border, + and clean typography throughout. + criteria_checklist: + visual_quality: + score: 29 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: 'All font sizes explicitly set: title 28pt, subtitle 18pt, axis titles + 22pt, tick labels 18pt, legend 16pt, annotation 20pt bold' + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: No text or data element collisions. Legend well-separated from plot + area. + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: 500 points at size=45, opacity=0.45. Matches 300+ guideline. White + strokes help distinguish overlapping points. + - id: VQ-04 + name: Color Accessibility + score: 4 + max: 4 + passed: true + comment: Viridis is perceptually uniform and colorblind-safe. + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Plot fills ~70% of canvas with balanced margins. Well-distributed + elements. + - id: VQ-06 + name: Axis Labels & Title + score: 1 + max: 2 + passed: true + comment: Labels y(t) and y(t+1) are descriptive but carry no physical units. + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: 'Above defaults: viridis colormap, opacity with white edge strokes, + dashed reference line, no border/domain lines. Cohesive but not publication-ready.' + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: Subtle grid (0.15 opacity), removed axis border, no domain line, + soft tick colors. More refined than defaults. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: r=0.834 annotation quantifies the pattern; time coloring reveals + temporal structure; diagonal reference guides interpretation. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: 'Correct lag plot: scatter of y(t) vs y(t+k).' + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Diagonal reference line, color by time index, correlation annotation, + configurable lag variable all present. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X=y(t), Y=y(t+1). Correct orientation. All 499 points visible. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title exactly 'scatter-lag · altair · pyplots.ai'. Legend labeled + 'Time Index'. + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 'Shows all key aspects: autocorrelation pattern, diagonal reference, + temporal coloring, correlation quantification.' + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: AR(1) process (phi=0.85) is a real, neutral statistical scenario. + Parameters clearly labeled in subtitle. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: 500 observations with realistic AR(1) value range (~-5 to 6). Correlation + r=0.834 expected for phi=0.85. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Linear: imports -> data -> chart layers -> 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: altair, numpy, pandas — all used, none unnecessary. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Layer composition (reference_line + points + annotation) is clean + and idiomatic Altair. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot.png with scale_factor=3.0 and plot.html. Current altair + 6.0.0 API. + library_features: + score: 8 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: 'Expert Altair: declarative encoding with typed fields (Q/N), layer + composition via +, alt.Scale/Axis/Legend, configure_* global styling.' + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Layer composition, interactive tooltips, HTML export, declarative + viridis scheme. Distinctly Altair but basic within library capabilities. + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - layer-composition + - annotations + - hover-tooltips + - html-export + patterns: + - data-generation + dataprep: [] + styling: + - custom-colormap + - alpha-blending + - edge-highlighting