Skip to content

feat(altair): implement scatter-connected-temporal#8535

Merged
MarkusNeusinger merged 6 commits into
mainfrom
implementation/scatter-connected-temporal/altair
Jun 9, 2026
Merged

feat(altair): implement scatter-connected-temporal#8535
MarkusNeusinger merged 6 commits into
mainfrom
implementation/scatter-connected-temporal/altair

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Implementation: scatter-connected-temporal - python/altair

Implements the python/altair version of scatter-connected-temporal.

File: plots/scatter-connected-temporal/implementations/python/altair.py

Parent Issue: #4675


🤖 impl-generate workflow

github-actions Bot and others added 2 commits June 9, 2026 23:21
Regen from quality 87. Addressed:
- Canvas: fixed 620×320 inner view + scale_factor=4.0 + PAD-only to 3200×1800
- Color: replaced forbidden viridis with Imprint sequential (#009E73→#4467A3)
- Theme: added full theme-adaptive chrome (PAGE_BG, ELEVATED_BG, INK, INK_SOFT)
- Output: fixed file names to plot-{THEME}.png/html
- Path opacity: 0.35→0.60 for legible temporal trajectory
- Y-axis: tightened domain from [-1.5,5.8] to [-0.8,6.2], removing wasted space
- Annotations: improved nudging for dense lower-left cluster (2015, 2023)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): The plot displays a connected scatter plot on a warm off-white (#FAF8F1) background. Data points (30 total, 1994–2023) are rendered as filled circles colored by year using an Imprint sequential gradient from brand green (#009E73, representing 1994) to blue (#4467A3, representing 2023), with white stroke edges. Points are connected in temporal order by gray lines (INK_SOFT, opacity 0.60). Key years (1994, 2000, 2008, 2010, 2015, 2023) are annotated with bold dark text labels, nudged away from their respective data points. A gradient color bar legend titled "Year" appears on the right side. The title "scatter-connected-temporal · altair · anyplot.ai" is bold and centrally displayed; a subtitle "Unemployment vs. Inflation — tracing the Phillips curve path (1994–2023)" appears below. Axis labels "Unemployment Rate (%)" (x) and "Inflation Rate (%)" (y) are readable, with subtle dashed grid lines at 15% opacity. A dense cluster of post-2015 data points in the lower left (unemployment ~3.0–3.5%, inflation ~0–0.5%) creates some visual noise but annotation labels remain readable. All text is clearly legible against the light background.

Dark render (plot-dark.png): The same plot rendered on a warm near-black (#1A1A17) background. All data colors are identical to the light render — the brand green (#009E73) to blue (#4467A3) temporal gradient on data points is unchanged. Chrome elements correctly switch: title, subtitle, axis labels, tick labels, and legend text all use light text (#F0EFE8 / #B8B7B0). Connecting lines in INK_SOFT become lighter gray (#B8B7B0) and remain clearly visible against the dark background. Year annotation labels render in bright near-white (#F0EFE8) and are readable. No dark-on-dark failures observed. Legend box uses elevated dark background (#242420) with appropriate light text. All text is legible in the dark render.

Score: 86/100

Category Score Max
Visual Quality 28 30
Design Excellence 12 20
Spec Compliance 13 15
Data Quality 14 15
Code Quality 10 10
Library Mastery 9 10
Total 86 100

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All text legible in both themes at full resolution. Annotation labels (11pt bold) in the dense lower-left cluster (2023, 2015) read slightly small at thumbnail scale but are clear at full size.
  • VQ-02: No Overlap (5/6) — Annotations are well-nudged and generally clear. However, the dense post-2015 cluster (overlapping data points in lower-left, unemployment ~3–3.5%) creates visual noise; individual year markers are hard to distinguish in this region.
  • VQ-03: Element Visibility (6/6) — 30 data points at size=200 are prominent and appropriate for this density. White stroke on points aids separation. Connecting lines at opacity=0.60 are visible without dominating.
  • VQ-04: Color Accessibility (2/2) — Imprint sequential scale (green→blue) is CVD-safe; no red-green as sole differentiator.
  • VQ-05: Layout & Canvas (4/4) — Canvas gate passed (no /tmp/anyplot-canvas-gate.txt). No clipping. Title spans ~65% of plot width at fontsize=16 — expected for this title length. Axis labels balanced. Generous whitespace.
  • VQ-06: Axis Labels & Title (2/2) — "Unemployment Rate (%)" and "Inflation Rate (%)" are descriptive with units. Subtitle adds context.
  • VQ-07: Palette Compliance (2/2) — imprint_seq range ["#009E73","#4467A3"] is the correct sequential colormap. Backgrounds are #FAF8F1 (light) and #1A1A17 (dark). Both themes are chrome-correct.

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Intentional use of Imprint sequential scale for temporal encoding, white strokes on markers, subtitle hierarchy, and theme-adaptive chrome. Solid above-default polish, but the overall visual language is clean-functional rather than editorially crafted.
  • DE-02: Visual Refinement (3/6) — Dashed grid at 15% opacity is very subtle; view frame removed (strokeWidth=0); Altair's L-shaped axis default retained. Above default but limited explicit refinement beyond grid and frame styling.
  • DE-03: Data Storytelling (4/6) — Year annotations at key economic inflection points (2000 dot-com era, 2008 crisis, 2010 recovery) create an effective narrative. Subtitle explicitly names the "Phillips curve." Color gradient reinforces temporal direction. However, no directional arrow along the path (as spec suggested), and no visual emphasis at the 2008–2010 recession spike.

Spec Compliance (13/15)

  • SC-01: Plot Type (5/5) — Correct connected scatter plot with temporal path: scatter markers + connecting lines ordered by time.
  • SC-02: Required Features (4/4) — Points connected in chronological order via order="order:Q" ✓; key time point annotations (1994, 2000, 2008, 2010, 2015, 2023) ✓; color gradient along path for temporal direction ✓; visible point markers at each data position ✓.
  • SC-03: Data Mapping (3/3) — Unemployment on x-axis, inflation on y-axis; time encoded as color and line order; all 30 data points within view bounds.
  • SC-04: Title & Legend (1/3) — Title is missing the required python language token. Required format: scatter-connected-temporal · python · altair · anyplot.ai; actual: scatter-connected-temporal · altair · anyplot.ai. Legend (gradient colorbar "Year") is correct.

Data Quality (14/15)

  • DQ-01: Feature Coverage (5/6) — Demonstrates connected scatter, temporal path, cyclical patterns, and regime change (2008 recession spike). Synthetic random-walk data shows the Phillips curve concept adequately; idealized generation limits real economic nuance slightly.
  • DQ-02: Realistic Context (5/5) — US unemployment vs. inflation 1994–2023 is a textbook Phillips curve context — plausible values, neutral economic statistics, realistic recession spike around 2008–2010.
  • DQ-03: Appropriate Scale (4/4) — x-axis [2.5, 8.5] and y-axis [-0.8, 6.2] match realistic US economic ranges; 30 annual data points is ideal for this plot type.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — No functions or classes; linear script with clear section comments.
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set before data generation.
  • CQ-03: Clean Imports (2/2) — All imports are used; importlib/sys workaround is necessary for the naming conflict.
  • CQ-04: Code Elegance (2/2) — Clean layer composition; .interactive() is genuine Altair interactivity (not fake UI); PAD-only guard prevents AR-09.
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html; uses Altair 6 API correctly.

Library Mastery (9/10)

  • LM-01: Idiomatic Usage (5/5) — Correct use of layer composition (path + points + annotations), order channel for line ordering, alt.Color with custom scale, configure_* methods for theme adaptation, per-layer encoding with shared x/y scales.
  • LM-02: Distinctive Features (4/5) — Layer composition for connected scatter, order channel (the key Altair pattern), alt.Title with subtitle and custom font sizes, alt.Legend with gradient bar, interactive tooltips with formatted values. Minor gap: no use of Altair-specific transforms (e.g. transform_calculate) that could have added polish.

Score Caps Applied

  • None

Strengths

  • Correct use of imprint_seq (#009E73→#4467A3) for temporal encoding — exactly the right continuous colormap choice for single-polarity data
  • Idiomatic Altair layer composition (mark_line + mark_point + mark_text) with proper order channel for the temporal path
  • Theme adaptation fully correct — all chrome elements use INK/INK_SOFT tokens; both renders are legible without dark-on-dark failures
  • Canvas sizing follows library rules (620×320 inner view + PAD-only block) — gate passed cleanly

Weaknesses

  • Title missing python language token — fix: change the alt.Title string to "scatter-connected-temporal · python · altair · anyplot.ai"
  • Dense post-2015 cluster (lower left, unemployment ~3–3.5%, inflation ~0–0.5%) has multiple overlapping markers and tangled connecting lines — consider reducing marker size to ~140 or adding slight alpha (opacity=0.75 on points) to improve separation
  • No directional arrow along the temporal path (spec suggested this) — could add an arrow annotation at a mid-path segment to explicitly indicate the direction of time flow

Issues Found

  1. SC-04 FAIL: Title is missing mandatory python language token
    • Fix: Change title string to "scatter-connected-temporal · python · altair · anyplot.ai"
  2. DE-03 LOW: No directional arrow or visual cue for time direction along the path
    • Fix: Add an arrowhead annotation at a mid-path segment, or use mark_point(shape='arrow') at one of the connecting segments

AI Feedback for Next Attempt

Fix the title to include python: "scatter-connected-temporal · python · altair · anyplot.ai". Consider adding a visual time-direction indicator (e.g. an arrow-shaped mark or annotation at a mid-path segment) as specified. For the dense lower-left cluster, reduce marker size to ~140 or add slight opacity (0.75) on points to reduce overlap noise. These changes would bring the score above 90.

Verdict: APPROVED

@github-actions github-actions Bot added quality:86 Quality score 86/100 ai-rejected Quality not OK, triggers update labels Jun 9, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels Jun 9, 2026
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

🔧 Repair Attempt 1/4

Applied fixes based on AI review feedback.

Status: Repair completed, re-triggering review...


🤖 impl-repair

@claude

claude Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): Warm off-white background (#FAF8F1) — correct. Title "scatter-connected-temporal · python · altair · anyplot.ai" rendered in dark ink at 16px, fully readable. Subtitle "Unemployment vs. Inflation — tracing the Phillips curve path (1994–2023)" in INK_SOFT below the title. Axis labels "Unemployment Rate (%)" and "Inflation Rate (%)" with units, tick labels legible at standard size. 30 scatter points sized ~160 Altair area units with white stroke (strokeWidth=1.2), colored on a green (#009E73 at 1994) → blue (#4467A3 at 2023) temporal gradient; connecting path in gray (INK_SOFT, opacity=0.60); bold year annotations at 1994, 2000, 2008, 2010, 2015, 2023 with nudged positions. The 2008 recession spike is clearly visible as a rightward excursion to ~7.9% unemployment; the 2015–2023 cluster compresses into the lower-left. Year gradient legend on the right is correctly labeled. All text is readable against the warm off-white background. Minor observation: the "1994" and "2010" labels are vertically close in the right-centre cluster (~0.35 unit gap) but do not pixel-overlap.

Dark render (plot-dark.png): Warm near-black background (#1A1A17) — correct. Title, axis labels, tick labels, year annotations, and legend labels all rendered in light ink (INK=#F0EFE8 / INK_SOFT=#B8B7B0) — clearly readable against the dark surface. No dark-on-dark failures detected. Data marker colors are identical to the light render (green→blue gradient unchanged); connecting path renders in muted light gray (INK_SOFT in dark mode = #B8B7B0). Grid lines visible as subtle dashed light lines at 0.15 opacity. Legend elevated background (#242420) and legend stroke (INK_SOFT) correctly themed. All text is readable against the dark background.

Both renders pass the theme-readability check. Data colors are identical across themes (only chrome flips).

Score: 89/100

Category Score Max
Visual Quality 28 30
Design Excellence 13 20
Spec Compliance 15 15
Data Quality 14 15
Code Quality 10 10
Library Mastery 9 10
Total 89 100

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set (title=16, subtitle=10, axis=12, ticks=10, annotations=11); proportions well-balanced; minor crowding of "1994"/"2010" labels in the right cluster (vertically close, ~0.35 unit gap)
  • VQ-02: No Overlap (5/6) — Nudge offsets prevent most label-point collisions; "1994" and "2010" are close vertically but do not pixel-overlap; mild crowding in the 2015–2023 left cluster is tolerable
  • VQ-03: Element Visibility (6/6) — 30 points at size=160, opacity=0.85 with white stroke is well-calibrated for the density; connecting path at opacity=0.60 is appropriately subdued
  • VQ-04: Color Accessibility (2/2) — Green→blue gradient differs in both hue and lightness under CVD simulation; white marker strokes provide luminance separation
  • VQ-05: Layout & Canvas (4/4) — Canvas gate passed; plot fills canvas well with balanced margins; no overflow or clipping
  • VQ-06: Axis Labels & Title (2/2) — "Unemployment Rate (%)" and "Inflation Rate (%)" — descriptive with units
  • VQ-07: Palette Compliance (2/2) — imprint_seq gradient #009E73→#4467A3 for continuous temporal data; backgrounds #FAF8F1/#1A1A17 correct; all chrome theme-adaptive in both renders

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above a configured default: temporal gradient encoding is intentional, white-stroked markers add definition, INK_SOFT path color is deliberately subdued to let data colors dominate, subtitle uses soft color. Not yet publication-ready — connecting path has no directional cue (arrowhead or tapered endpoint) which would complete the temporal narrative
  • DE-02: Visual Refinement (4/6) — Dashed grid (gridDash=[3,3]) at 0.15 opacity is subtle; view box removed (strokeWidth=0); legend styled with ELEVATED_BG fill and INK_SOFT stroke; thoughtful padding and titlePadding settings
  • DE-03: Data Storytelling (4/6) — Temporal color gradient + year annotations + subtitle "Phillips curve path" create a coherent narrative; 2008 recession spike visible as dramatic deviation; viewer can follow the chronological path. Slight missed opportunity: no visual emphasis on the 2008 turning point beyond the label (e.g., slightly larger marker or accent color)

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct connected scatter plot: mark_point for markers + mark_line with order:Q encoding for temporal path
  • SC-02: Required Features (4/4) — All spec features present: chronological connection, year annotations, temporal color gradient, visible point markers
  • SC-03: Data Mapping (3/3) — X=Unemployment Rate, Y=Inflation Rate; all 30 years visible within domain
  • SC-04: Title & Legend (3/3) — Title exactly "scatter-connected-temporal · python · altair · anyplot.ai"; Year gradient legend correctly labeled

Data Quality (14/15)

  • DQ-01: Feature Coverage (6/6) — Shows all connected-scatter features: temporal path through 2D space, direction via color gradient, key period annotations, recession spike as dramatic deviation
  • DQ-02: Realistic Context (5/5) — US unemployment vs. inflation (Phillips curve) is a canonical, real-world, neutral economic scenario
  • DQ-03: Appropriate Scale (3/4) — Unemployment 3–10.5% and inflation −0.5% to 6% are realistic US ranges; 2008 spike correctly added; data is synthetic rather than actual BLS/CPI figures

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat: imports → data → encodings → layers → compose → save; importlib workaround is necessary (file named altair.py)
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set
  • CQ-03: Clean Imports (2/2) — altair (via importlib), numpy, pandas, PIL — all used
  • CQ-04: Code Elegance (2/2) — Nudge dict, layer composition via +, configure chain — clean and appropriate; PAD-only canvas handling correctly implemented
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html; current Altair 6.x API

Library Mastery (9/10)

  • LM-01: Idiomatic Usage (5/5) — Expert Altair: order:Q encoding for temporal line ordering, + operator for layer composition, configure_* chain for global theming, alt.Title with subtitle, alt.Scale/Legend with explicit params
  • LM-02: Distinctive Features (4/5) — order:Q encoding is a distinctive Altair/Vega-Lite pattern not available in matplotlib/seaborn; layer composition and interactive tooltips are Altair-native; alt.Title subtitle separation is a VL-specific feature

Score Caps Applied

  • None — no caps triggered (DE-01=5 > 2, DE-02=4 > 2; no cap at 75)

Strengths

  • imprint_seq gradient (#009E73→#4467A3) for temporal encoding is the correct Imprint continuous colormap, applied idiomatically via alt.Scale(range=[...])
  • order:Q encoding for the connecting line is a Vega-Lite-specific feature that correctly enforces chronological ordering independent of data frame order
  • Theme-adaptive chrome is thorough — PAGE_BG, ELEVATED_BG, INK, INK_SOFT all thread through configure_axis, configure_legend, configure_title, and mark_text; both renders pass the legibility check with no dark-on-dark failures
  • Year annotations with explicit nudge offsets prevent naive label-point collisions; the 2008 recession spike is correctly identified and labelled as a notable period
  • PAD-only canvas pattern is implemented exactly per library spec — raises SystemExit on overshoot, pads with PAGE_BG on undershoot, no crop risk

Weaknesses

  • Mild annotation crowding: "1994" (nudged to y≈3.3) and "2010" (nudged to y≈2.95) are vertically close in the right-centre cluster; increasing the y-nudge for 1994 from 0.30 to 0.55 would give the two bold labels a full text-line of separation
  • DQ-03: Data is plausibly realistic but synthetically generated; the 2008 unemployment spike is hand-tuned rather than sourced from actual Bureau of Labor Statistics figures — values are reasonable but not fact-checked against historical records
  • The connecting path uses plain INK_SOFT gray with no directional cue — an arrowhead at the final data point (2023) or a slightly tapered stroke would complete the temporal narrative and lift DE-01 closer to publication quality

Issues Found

  1. VQ-01/VQ-02 MINOR: "1994" and "2010" labels are vertically close (~0.35 unit gap) in the right cluster
    • Fix: Increase nudge for 1994 from (0.28, 0.30) to (0.28, 0.55) to create a full text-height separation
  2. DE-01 MODERATE: No directional cue on the temporal path
    • Fix: Add an arrowhead at the 2023 endpoint using mark_point(shape='arrow', angle=..., size=200) layered at the final data point, or use a rule/point overlay to indicate "end of path"

AI Feedback for Next Attempt

The implementation is strong — imprint_seq gradient, order:Q line encoding, and PAD-only canvas are all correct. Two refinements would push to 93+: (1) increase the y-nudge for the 1994 label from 0.30 to 0.55 to separate it from the "2010" label; (2) add a directional marker at the 2023 endpoint (an Altair mark_point with a triangle/arrow shape) so the temporal direction is explicit without relying solely on the color gradient legend.

Verdict: APPROVED

@github-actions github-actions Bot added quality:89 Quality score 89/100 ai-approved Quality OK, ready for merge and removed quality:86 Quality score 86/100 labels Jun 9, 2026
@MarkusNeusinger MarkusNeusinger merged commit 6bc9491 into main Jun 9, 2026
3 checks passed
@MarkusNeusinger MarkusNeusinger deleted the implementation/scatter-connected-temporal/altair branch June 9, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-approved Quality OK, ready for merge ai-attempt-1 First repair attempt quality:89 Quality score 89/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant