Skip to content

feat(altair): implement timeseries-forecast-uncertainty#7398

Merged
MarkusNeusinger merged 4 commits into
mainfrom
implementation/timeseries-forecast-uncertainty/altair
May 19, 2026
Merged

feat(altair): implement timeseries-forecast-uncertainty#7398
MarkusNeusinger merged 4 commits into
mainfrom
implementation/timeseries-forecast-uncertainty/altair

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: timeseries-forecast-uncertainty - python/altair

Implements the python/altair version of timeseries-forecast-uncertainty.

File: plots/timeseries-forecast-uncertainty/implementations/python/altair.py

Parent Issue: #3188


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 19, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): The plot renders on a warm off-white (#FAF8F1) background. The title "timeseries-forecast-uncertainty · python · altair · anyplot.ai" appears in bold dark text at the top center, with the subtitle "Monthly Sales with 80% and 95% Confidence Intervals" in softer gray beneath it. A solid green (#009E73) line traces the historical sales data from January 2021 through December 2023, showing clear upward trend with seasonal variation. A dashed orange (#D55E00) line covers the 2024 forecast period, with nested semi-transparent bands: a medium-opacity 80% CI band and a lighter 95% CI outer band, both in the same orange/vermillion color family. A dashed vertical rule marks the forecast start at January 2024. Y-axis label "Sales (thousands USD)" and X-axis label "Date" are clearly readable. Tick labels (years and month names) are visible and well-spaced. The legend box in the top-right corner shows "Historical Data", "Forecast", and "80% & 95% CI" entries. All text is readable against the light background. The legend is positioned close to the right canvas edge but all entries appear complete.

Dark render (plot-dark.png): The same plot on a warm near-black (#1A1A17) background. The title and subtitle appear in light (#F0EFE8 / #B8B7B0) text, clearly readable against the dark surface. The historical green line and the forecast orange dashed line retain their identical Okabe-Ito colors — no data color drift between themes. The CI bands render as deeper brownish-orange on the dark background (natural result of the semi-transparent orange fill over near-black), still clearly showing the two confidence levels. The vertical forecast rule is a medium-gray dashed line. Axis labels, tick labels, and legend text all appear as light text on the dark background — no dark-on-dark failures observed. Grid lines are subtle horizontal lines (y-axis only) appropriately faint in both themes. Legibility verdict: PASS for both renders.

Score: 88/100

Category Score Max
Visual Quality 28 30
Design Excellence 12 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 8 10
Total 88 100

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — Font sizes are explicitly set and readable in both themes; canvas is 4800×2700 (1600×900 × scale=3) vs the style-guide-recommended 3200×1800 (800×450 × scale=4), a minor deviation, but text proportions look good in the output
  • VQ-02: No Overlap (6/6) — No text collisions; tick labels well-spaced; annotation-free zones clean
  • VQ-03: Element Visibility (6/6) — Historical line, dashed forecast line, and both CI bands are all clearly distinguishable; appropriate opacity (0.15 / 0.30) for the bands
  • VQ-04: Color Accessibility (2/2) — Green vs. orange is CVD-safe; bands use the same hue family at varying opacity, no red-green conflict
  • VQ-05: Layout & Canvas (3/4) — Canvas deviates from the recommended 800×450 × scale=4 spec; uses 1600×900 × scale=3 instead (4800×2700 vs 3200×1800 output). Legend placement is tight at the right canvas edge
  • VQ-06: Axis Labels & Title (2/2) — Y-axis "Sales (thousands USD)" includes units; X-axis "Date" is appropriate; subtitle adds useful context
  • VQ-07: Palette Compliance (2/2) — First series is #009E73 ✓; forecast uses #D55E00 (Okabe-Ito position 2) ✓; backgrounds are #FAF8F1 / #1A1A17 ✓; theme chrome adapts correctly ✓

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Professional execution: correct palette, appropriate transparency, solid/dashed distinction, subtitle adds context. Not exceptional — standard forecast chart composition without standout creative choices
  • DE-02: Visual Refinement (4/6) — domain=False removes axis lines; tickSize=0 removes tick marks; stroke=None removes view border; y-axis-only subtle grid (opacity=0.10). Legend has fill/stroke box which is acceptable for 3-series. Good but not exceptional refinement
  • DE-03: Data Storytelling (3/6) — The widening CI bands communicate growing uncertainty; vertical rule marks the historical-to-forecast transition clearly. Missing: no annotations or callouts at the transition point, no emphasis on the forecast start value

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Time series line with forecast + uncertainty bands, exactly as specified
  • SC-02: Required Features (4/4) — Solid historical line ✓, dashed forecast line ✓, vertical rule at forecast start ✓, nested 80% + 95% CI bands ✓, legend identifying all series ✓
  • SC-03: Data Mapping (3/3) — Date on X (temporal), sales values on Y (quantitative); all 48 data points visible; shared Y scale consistent
  • SC-04: Title & Legend (3/3) — Title is exactly "timeseries-forecast-uncertainty · python · altair · anyplot.ai" ✓; legend labels "Historical Data", "Forecast", "80% & 95% CI" are clear ✓

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Demonstrates all aspects: historical trend + seasonality + noise, forecast mean line, nested CI bands at two confidence levels, transition marker
  • DQ-02: Realistic Context (5/5) — Monthly sales data with plausible upward trend (100k → 170k over 3 years) and seasonality; neutral business scenario; widening uncertainty over forecast horizon is statistically correct
  • DQ-03: Appropriate Scale (4/4) — 36 historical + 12 forecast points; CI widths grow from ±6.4k (80%) at start to ±25.6k at end — realistic ARIMA/Prophet-style uncertainty; all values sensible for sales in thousands USD

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — No functions or classes; flat linear script ✓
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) ✓
  • CQ-03: Clean Imports (2/2) — os, altair, numpy, pandas — all used ✓
  • CQ-04: Code Elegance (2/2) — Appropriate complexity; clear variable naming; no fake UI ✓
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html ✓; current Altair 6.x API ✓

Library Mastery (8/10)

  • LM-01: Idiomatic Usage (5/5) — alt.layer() composition ✓; correct encoding types (T, Q) ✓; alt.value() for explicit colors in layered chart ✓; configure_axis / configure_view / configure_legend ✓; Y2 encoding for area bands ✓
  • LM-02: Distinctive Features (3/5) — Uses the invisible-points legend technique (a known Altair workaround for layered charts using alt.value() colors) and alt.layer() composition. Solid Altair idioms, but the invisible legend approach is a workaround rather than an elegant feature use; no Altair-native selection or tooltip interaction leveraged

Score Caps Applied

  • None

Strengths

  • Full spec compliance: all required elements (historical line, dashed forecast, nested CI bands, vertical rule, legend) implemented correctly
  • Proper Okabe-Ito palette: #009E73 for historical, #D55E00 for forecast — exact canonical order
  • Clean theme adaptation: all chrome tokens (INK, INK_SOFT, PAGE_BG, ELEVATED_BG) correctly applied in both light and dark renders; no dark-on-dark failures
  • Good statistical realism: CI widths grow with forecast horizon (linspace 5→20 std), matching real forecasting model behavior
  • Clean axis styling: domain lines removed, tick marks removed, x-axis grid disabled, y-axis grid subtle at 0.10 opacity
  • Reproducible with np.random.seed(42) and exports both PNG and HTML

Weaknesses

  • Canvas size deviates from style guide: uses width=1600, height=900, scale_factor=3.0 (→ 4800×2700 px) instead of the recommended width=800, height=450, scale_factor=4.0 (→ 3200×1800 px)
  • DE-03 low: no annotation or callout at the forecast start point; a text annotation (e.g., "Forecast start") near the vertical rule or a labeled data point at the transition would strengthen the storytelling
  • Legend is placed with orient="right" and sits tight against the right canvas edge; consider orient="top-right" or padding to give breathing room

Issues Found

  1. VQ-05 / Canvas size: width=1600, height=900, scale=3.0 produces 4800×2700 px output; style guide recommends 800×450 × scale=4.0 = 3200×1800 px. Fix: change to and .
  2. DE-03 LOW: No annotation at the historical-to-forecast transition. Fix: add an layer with text "Forecast →" near the vertical rule.

AI Feedback for Next Attempt

The implementation is solid and fully spec-compliant. For the next attempt: (1) fix canvas dimensions to width=800, height=450, scale_factor=4.0 per style guide; (2) add a text annotation at the forecast start vertical rule to strengthen data storytelling; (3) consider adding a small mark_point layer on the historical line for the last observed data point to visually anchor the transition.

Verdict: APPROVED

@github-actions github-actions Bot added quality:88 Quality score: 88/100 ai-rejected Quality not OK, triggers update labels May 19, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels May 19, 2026
@github-actions
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
Copy link
Copy Markdown
Contributor

claude Bot commented May 19, 2026

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): Warm off-white #FAF8F1 background (confirmed, not pure white). Title "timeseries-forecast-uncertainty · python · altair · anyplot.ai" in dark near-black text is clearly readable; subtitle "Monthly Sales with 80% and 95% Confidence Intervals" in secondary INK_SOFT tone is also visible. X-axis label "Date" and Y-axis label "Sales (thousands USD)" in dark text, both readable. Tick labels in INK_SOFT. Historical solid green line (#009E73) traces an upward trend with seasonal oscillation from Jan 2021 to Dec 2023. From Jan 2024 onward: dashed orange forecast line with nested CI bands — outer 95% band (opacity=0.15, light peach) visibly surrounds the inner 80% band (opacity=0.30, stronger orange). Dashed vertical rule at Jan 2024 cleanly marks the boundary. Legend top-right correctly labels "Historical Data" (green), "Forecast" (orange), "80% & 95% CI" (orange). All text readable against the light background.

Dark render (plot-dark.png): Warm near-black #1A1A17 background (confirmed). Title and subtitle in light #F0EFE8-range text — clearly readable. Axis labels and tick labels in lighter secondary tone — no dark-on-dark failures detected. Legend text is light on elevated-dark background (#242420) — readable. Historical line retains the same #009E73 green (identical to light render) and is vivid and clearly visible on the dark surface. Forecast bands appear as brownish-orange fills on dark — same hue as light render, naturally darker due to the near-black background. The 80% inner band is still distinguishable from the broader 95% outer band. Vertical rule visible as a subtle dashed line.

Both paragraphs confirm all text is readable in both themes. No dark-on-dark failures. Data colors are identical between light and dark renders (only chrome flips).

Score: 88/100

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

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set; both themes fully readable. Minor: "Date" x-axis label at titleFontSize=22 is slightly generous for a 4-char label, though X/Y balance is maintained.
  • VQ-02: No Overlap (6/6) — No overlapping text or data elements; legend cleanly positioned.
  • VQ-03: Element Visibility (6/6) — Historical line, dashed forecast line, and both nested CI bands clearly visible.
  • VQ-04: Color Accessibility (2/2) — Green/orange Okabe-Ito pair is CVD-safe; not red-green.
  • VQ-05: Layout & Canvas (3/4) — Good layout and margins. Minor: canvas 4800×2700 (width=1600, height=900, scale=3.0) exceeds the allowed 3200×1800 target per the style guide.
  • VQ-06: Axis Labels & Title (2/2) — "Sales (thousands USD)" has units; correct title format with subtitle.
  • VQ-07: Palette Compliance (2/2) — First series #009E73, second #D55E00. Backgrounds #FAF8F1 / #1A1A17. Both themes correct.

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Solid professional design with intentional color hierarchy (green vs. orange), subtitle, and nested CI opacity layers. Clearly above configured defaults.
  • DE-02: Visual Refinement (4/6) — tickSize=0, domain=False, x-grid removed, y-grid at opacity=0.10, view border removed — multiple effective refinements.
  • DE-03: Data Storytelling (4/6) — Vertical rule creates a strong forecast boundary narrative. Widening CI bands communicate increasing uncertainty. Green/orange distinction guides the viewer through the historical-to-forecast story.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct: time series with historical line, dashed forecast, nested CI bands.
  • SC-02: Required Features (4/4) — All spec features present: solid historical line, dashed forecast, 80% CI, 95% CI, vertical rule, semi-transparent fills, labeled legend.
  • SC-03: Data Mapping (3/3) — Date on x, Sales on y; both historical (2021–2024) and forecast (2024–2025) periods fully visible.
  • SC-04: Title & Legend (3/3) — Title exactly matches required format. Legend correctly labeled.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all aspects: historical trend + seasonality, forecast continuation, nested widening CI bands, transition marker.
  • DQ-02: Realistic Context (5/5) — Monthly sales, 3-year history + 12-month forecast, neutral business scenario.
  • DQ-03: Appropriate Scale (4/4) — Sales ~100–210K USD plausible; 80% CI narrower than 95% (statistically correct); bands widen over horizon.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Linear: imports → tokens → data → layers → assemble → save. No functions or classes.
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set.
  • CQ-03: Clean Imports (2/2) — os, altair, numpy, pandas — all used.
  • CQ-04: Code Elegance (2/2) — Clean layer composition, no over-engineering, no fake UI.
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html with correct naming.

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — alt.layer(), alt.value(), proper :T/:Q/:N encoding types, configure chain — strong idiomatic Altair.
  • LM-02: Distinctive Features (3/5) — Invisible-points legend pattern (Altair-specific workaround for alt.value() colors), y2 encoding for area bounds, alt.layer() composition.

Score Caps Applied

  • None

Strengths

  • All spec features perfectly implemented: solid historical line, dashed forecast, nested 80%/95% CI bands, dashed vertical rule at forecast start
  • Correct Okabe-Ito palette throughout; both themes work correctly with proper adaptive chrome tokens
  • Strong data storytelling: widening CI bands + vertical boundary rule create a clear "known past vs uncertain future" narrative
  • Excellent code structure: clean alt.layer() composition with idiomatic Altair patterns
  • Subtitle adds meaningful context that complements the main title

Weaknesses

  • Canvas size 4800×2700 (width=1600, height=900, scale_factor=3.0) exceeds the allowed 3200×1800 — use width=800, height=450, scale_factor=4.0 per the Altair library guide
  • Legend combines both CI levels as a single "80% & 95% CI" entry — separate entries with different alpha swatches would better distinguish the two confidence bands visually
  • configure_view(stroke=None) removes view border entirely rather than using stroke=INK_SOFT per the Altair style template

Issues Found

  1. VQ-05 MINOR: Canvas size 4800×2700 is 2.25× the allowed 3200×1800 target
    • Fix: Change to width=800, height=450 with scale_factor=4.0 (or width=1600, height=900 with scale_factor=2.0)
  2. LM-02 OPPORTUNITY: Legend could show separate 80% and 95% CI entries with matching alpha swatches
    • Fix: Add distinct legend entries for "80% CI" and "95% CI" in the invisible-points legend DataFrame

AI Feedback for Next Attempt

The implementation is high quality and meets all spec requirements. The primary fix needed is the canvas size: change width=1600, height=900, scale_factor=3.0 to width=800, height=450, scale_factor=4.0 to produce the required 3200×1800 output. Optionally, split the "80% & 95% CI" legend entry into two separate entries to better distinguish the confidence levels visually.

Verdict: APPROVED

@github-actions github-actions Bot added the ai-approved Quality OK, ready for merge label May 19, 2026
@MarkusNeusinger MarkusNeusinger merged commit 728b72b into main May 19, 2026
@MarkusNeusinger MarkusNeusinger deleted the implementation/timeseries-forecast-uncertainty/altair branch May 19, 2026 13:32
MarkusNeusinger added a commit that referenced this pull request May 19, 2026
…sizing (#7406)

## Summary
Today's bulk-generate fan-out (#7395-#7405) revealed a regen-mindset
bug: 3 of 10 libraries (seaborn #7396, altair #7398, ggplot2 #7403) kept
their OLD 4800×2700 / 3600×3600 canvas + old fontsizes even though the
library prompts had been updated to 3200×1800.

## Root cause
\`impl-generate-claude.md\` already said \"base style wins over previous
implementation\" — but listed only \"palette, theme colors, chrome,
etc.\" as the affected dimensions. Claude treated that list as
exhaustive and assumed canvas / fontsize / marker / line-size changes
were NOT in scope, since the previous review hadn't flagged the
(then-valid) old values.

## Fix
Made the override rule explicit on every axis where the base style has
an opinion:
- canvas size (figsize/dpi, width/height/scale_factor, native
width/height)
- font sizes (title, axis, tick, legend)
- marker + line sizes
- palette + theme tokens + chrome (already covered, kept)

Plus: instruct the AI to **re-read the library prompt's \"Sizing\"
section + the style guide's \"Visual Sizing Defaults\" table on every
regen**, not just rely on what the previous review flagged.

## Test plan
- [ ] CI green
- [ ] After merge: re-trigger seaborn / altair / ggplot2 for
timeseries-forecast-uncertainty → all three should produce 3200×1800
canvas in line with the other 7

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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:88 Quality score: 88/100

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant