Skip to content

feat(plotly): implement timeseries-forecast-uncertainty#7397

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

feat(plotly): implement timeseries-forecast-uncertainty#7397
MarkusNeusinger merged 5 commits into
mainfrom
implementation/timeseries-forecast-uncertainty/plotly

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: timeseries-forecast-uncertainty - python/plotly

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

File: plots/timeseries-forecast-uncertainty/implementations/python/plotly.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): Warm off-white background (#FAF8F1). Title "timeseries-forecast-uncertainty · python · plotly · anyplot.ai" in dark ink, centered. X-axis label "Date", Y-axis label "Monthly Sales (Units)" both readable. Tick labels (Jan 2023 through Jul 2026, values 100–240) in secondary dark ink. Historical data displayed as a solid #009E73 (brand green) line spanning 36 months with upward trend + visible seasonality and noise. A dashed #D55E00 (vermillion) forecast line starts at Jan 2026. Two nested CI bands in orange tones: the 95% CI as a very light salmon fill (0.15 opacity) and the 80% CI as a more saturated orange fill (0.30 opacity) — distinction is clear. A vertical dashed gray line marks the forecast start, with a "Forecast Start" annotation above it. A faint dotted green connector bridges the last historical point to the first forecast point. Legend (top-left, with elevated background and border) shows all four series. All text clearly readable against the light background. Legibility: PASS.

Dark render (plot-dark.png): Warm near-black background (#1A1A17). Title, axis labels, and tick labels all rendered in light-colored text (#F0EFE8 / #B8B7B0 tokens) — clearly readable, no dark-on-dark failures. Legend box uses elevated dark fill (#242420) with border. The data colors are identical to the light render: historical line in #009E73, forecast in #D55E00. CI bands appear as warm orange-brown tones; the 95% outer band is slightly lighter than the 80% inner band, but the distinction is less pronounced than in the light render (both are visible). Brand green #009E73 remains clearly visible on the dark surface. No dark-on-dark text issues. Legibility: PASS.

Score: 85/100

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

Visual Quality (28/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set. At 4800×2700 canvas (1600×900 scale=3), the 22px axis labels scale to ~14.7 effective px — acceptable. Balanced proportions, readable in both themes.
  • VQ-02: No Overlap (6/6) — No text or element collisions in either render.
  • VQ-03: Element Visibility (5/6) — Lines and bands well-visible. 95% CI at opacity 0.15 is subtle but present in light mode; 80% vs 95% distinction less pronounced in dark mode.
  • VQ-04: Color Accessibility (2/2) — Okabe-Ito #009E73 / #D55E00 are CVD-safe; distinction further reinforced by solid vs dashed line styles.
  • VQ-05: Layout & Canvas (4/4) — Good canvas utilization, generous margins, no cut-off content.
  • VQ-06: Axis Labels & Title (2/2) — Y-axis "Monthly Sales (Units)" has units; X-axis "Date" descriptive.
  • VQ-07: Palette Compliance (2/2) — First series #009E73 ✓; second #D55E00 ✓; backgrounds #FAF8F1 / #1A1A17 ✓; data colors identical across themes ✓.

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (4/8) — Well-configured with correct palette, theme-adaptive chrome, and intentional line styles. Sits at "well-configured library default" level — not exceptional.
  • DE-02: Visual Refinement (4/6) — Subtle 10% opacity grid ✓; effectively L-shaped frame ✓; elevated legend box ✓. Missing: X-axis grid adds visual noise for a time series — prefer Y-only grid.
  • DE-03: Data Storytelling (4/6) — Clear visual hierarchy via distinct colors + line styles. "Forecast Start" vertical line + annotation guides the viewer. Dotted connector shows continuity. Solid storytelling structure.

Spec Compliance (14/15)

  • SC-01: Plot Type (5/5) — Correct time series forecast + nested confidence band visualization.
  • SC-02: Required Features (4/4) — All spec elements present: solid historical, dashed forecast, 80% + 95% CI bands, vertical forecast start marker, semi-transparent fills, complete legend.
  • SC-03: Data Mapping (3/3) — Date on X, Monthly Sales (Units) on Y; 36-month history + 12-month forecast fully visible.
  • SC-04: Title & Legend (2/3) — Title correct in rendered image but code has wrong title string: "timeseries-forecast-uncertainty · plotly · pyplots.ai" — missing python · and wrong domain (pyplots.aianyplot.ai). Legend labels correct.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all aspects: upward trend, seasonality, noise, widening CI, historical/forecast transition.
  • DQ-02: Realistic Context (5/5) — Monthly sales forecasting — neutral, realistic business scenario.
  • DQ-03: Appropriate Scale (4/4) — Starting ~105 units, growing to ~170 over 3 years; seasonality ±15 units (~10%); CI widening via sqrt(t) is statistically realistic.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Linear flow: constants → data generation → traces → layout → save.
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set.
  • CQ-03: Clean Imports (2/2) — os, numpy, pandas, plotly.graph_objects — all used.
  • CQ-04: Code Elegance (2/2) — Clean code; fill='toself' with concatenated arrays is the idiomatic plotly CI band pattern.
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html; current plotly API.

Library Mastery (6/10)

  • LM-01: Idiomatic Usage (3/5) — Correct use of go.Figure(), add_trace(), add_shape(), add_annotation(). Good fill='toself' and yref='paper' usage.
  • LM-02: Distinctive Features (3/5) — hovermode='x unified' (plotly-specific cross-trace hover), write_html() for interactive output, custom hover templates.

Score Caps Applied

  • None

Strengths

  • Correct Okabe-Ito palette: historical in #009E73 (brand green) and forecast in #D55E00 (vermillion), reinforced by solid vs dashed line styles
  • Excellent theme-adaptive chrome — both renders fully readable with correct text, grid, and legend tokens
  • All required spec features implemented: historical line, forecast line, both 80% + 95% CI bands, forecast start vertical marker and annotation
  • Perfect data quality: realistic monthly sales scenario with trend + seasonality + noise, statistically realistic widening uncertainty (sqrt growth)
  • Clean idiomatic plotly code using hovermode='x unified', fill='toself' CI polygons, add_shape(yref='paper') for full-height vertical line, write_html() for interactive output

Weaknesses

  • Code title string is wrong: "timeseries-forecast-uncertainty · plotly · pyplots.ai" should be "timeseries-forecast-uncertainty · python · plotly · anyplot.ai" (missing python ·, wrong domain)
  • Both X and Y grid lines are shown; for a time series line chart prefer Y-axis grid only — set xaxis=dict(showgrid=False) to reduce visual clutter
  • 95% vs 80% CI band distinction is less pronounced in dark mode — consider increasing opacity difference (e.g., 0.10 vs 0.32) or slight edge-line on the inner band
  • Canvas is 4800×2700 (width=1600, height=900, scale=3) — use recommended 3200×1800 (width=800, height=450, scale=4)
  • Design lacks refinement touches that would raise DE-01: e.g., remove axis mirror lines with xaxis=dict(mirror=False, showline=True), remove the full rectangular plot border

Issues Found

  1. SC-04 BUG: Title code string is "timeseries-forecast-uncertainty · plotly · pyplots.ai" — must be "timeseries-forecast-uncertainty · python · plotly · anyplot.ai"
    • Fix: Update text= in fig.update_layout(title=dict(...)) to the correct format
  2. DE-02 LOW: X-axis grid lines add visual noise for a time series chart
    • Fix: Add showgrid=False to xaxis dict; keep Y-axis grid only
  3. DE-01 LOW: Full rectangular plot border visible (top + right axis lines); style feels like a configured default rather than a refined visualization
    • Fix: Add mirror=False, showline=True to both axis dicts to achieve clean L-shaped frame; optionally remove top/right border via fig.update_layout(xaxis=dict(showline=True, mirror=False), yaxis=dict(showline=True, mirror=False))
  4. VQ-03 MINOR: 95% CI transparency (0.15) becomes hard to distinguish from 80% CI in dark render
    • Fix: Lower 95% CI opacity to 0.10 and raise 80% CI to 0.32, or add a thin edge line on the 80% CI boundary
  5. CQ-05 MINOR: Canvas size 4800×2700 instead of spec 3200×1800
    • Fix: Change write_image(..., width=1600, height=900, scale=3) to write_image(..., width=800, height=450, scale=4)

AI Feedback for Next Attempt

Fix the title string first (missing python · and wrong domain). Then: (1) use width=800, height=450, scale=4; (2) set xaxis=dict(showgrid=False, showline=True, mirror=False) to remove X-axis grid and the top mirror line; (3) set yaxis=dict(showline=True, mirror=False) to remove the right mirror line; (4) lower 95% CI fill to rgba(213,94,0,0.10) and raise 80% CI to rgba(213,94,0,0.32) for clearer band distinction in dark mode. These four targeted changes should push the score past 90.

Verdict: REJECTED

@github-actions github-actions Bot added quality:85 Quality score 85/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 background (#FAF8F1) — correct theme surface. Title "timeseries-forecast-uncertainty · python · plotly · anyplot.ai" in dark ink (#1A1A17), centered, occupies ~75% of width — expected for the long mandated title format. X-axis label "Date" and Y-axis label "Monthly Sales (Units)" in dark ink; tick labels in secondary dark ink (#4A4A44). Historical line rendered in #009E73 (Okabe-Ito position 1), solid, width=3. Forecast line in #D55E00 (Okabe-Ito position 2), dashed, width=3. 80% CI band shown as medium orange-brown fill (rgba 0.32 alpha); 95% CI as a lighter outer fill (rgba 0.10 alpha). A dotted connection line bridges the historical endpoint to the forecast start. Dashed vertical line marks Jan 2026 "Forecast Start" with annotation above. Legend (top-left) shows 95% CI, 80% CI, Historical, Forecast — all readable. All text is clearly legible against the light background. No overlap issues.

Dark render (plot-dark.png): Warm near-black background (#1A1A17) — correct dark theme surface. Title, axis labels, and tick labels flip to light ink (#F0EFE8 / #B8B7B0) — fully readable against the dark background. No dark-on-dark failures. Legend box uses elevated dark background (#242420) with light text. Data colors are identical to the light render: historical line #009E73, forecast line #D55E00. CI band fills appear more visually saturated against the dark background (expected due to contrast), but the rgba fill values are unchanged. Widening uncertainty pattern equally clear. "Forecast Start" annotation is readable.

Both renders pass legibility and theme checks. Data colors identical across themes; only chrome flips.

Score: 89/100

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

Visual Quality (29/30)

  • VQ-01: Text Legibility (7/8) — All font sizes explicitly set; readable in both themes. Minor: short "Date" label at fontsize=22 is the same size as the longer "Monthly Sales (Units)" label — slight proportional imbalance.
  • VQ-02: No Overlap (6/6) — No overlapping elements; legend placed top-left without obscuring data.
  • VQ-03: Element Visibility (6/6) — Lines (width=3), CI bands (semi-transparent fills), and dotted connector are all well-adapted to data density.
  • VQ-04: Color Accessibility (2/2) — Okabe-Ito #009E73 and #D55E00 are CVD-safe; additional line-style differentiation (solid vs dashed) provides a second channel.
  • VQ-05: Layout & Canvas (4/4) — Balanced margins, nothing cut off, chart fills the canvas well.
  • VQ-06: Axis Labels & Title (2/2) — Y-axis includes units "Monthly Sales (Units)"; title format is correct.
  • VQ-07: Palette Compliance (2/2) — First series #009E73; second #D55E00 (Okabe-Ito order). Backgrounds #FAF8F1 / #1A1A17; all chrome tokens theme-adaptive.

Design Excellence (13/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above defaults: nested CI bands, dotted bridging line, styled legend box, "Forecast Start" annotation, intentional Okabe-Ito application. Not publication-ready: top/right spines still visible (showline=True without explicit spine removal), no further visual differentiation.
  • DE-02: Visual Refinement (4/6) — Y-axis grid only with subtle GRID color, X-axis grid disabled, mirror=False gives L-frame. Could explicitly remove top and right spines and reduce the visible axis lines for a cleaner frame.
  • DE-03: Data Storytelling (4/6) — Clear narrative: historical trend → forecast transition → widening uncertainty. "Forecast Start" annotation and color+style coding guide the viewer. Visual hierarchy present.

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct: time series with forecast and uncertainty bands.
  • SC-02: Required Features (4/4) — All features: solid historical line, dashed forecast, vertical forecast-start marker, 80% CI (darker), 95% CI (lighter), legend, consistent color family.
  • SC-03: Data Mapping (3/3) — X=date, Y=Monthly Sales (Units); full date range visible.
  • SC-04: Title & Legend (3/3) — Title matches required format; legend entries "95% CI", "80% CI", "Historical", "Forecast" — all correct.

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all spec aspects: trend+seasonality+noise in historical period; widening CI bands in forecast; 36-month history + 12-month forecast horizon.
  • DQ-02: Realistic Context (5/5) — Monthly sales forecasting — real-world neutral business scenario with plausible values.
  • DQ-03: Appropriate Scale (4/4) — Sales 100–250 units/month, 2.5-unit/month trend, ±15 seasonal variation; widening uncertainty over forecast horizon is factually correct.

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Linear flow: imports → theme tokens → data generation → traces → layout → save.
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set.
  • CQ-03: Clean Imports (2/2) — os, numpy, pandas, plotly.graph_objects — all used.
  • CQ-04: Code Elegance (2/2) — Clean, Pythonic; fill='toself' pattern is appropriate; no fake UI elements.
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html; current API used.

Library Mastery (7/10)

  • LM-01: Idiomatic Usage (4/5) — fill='toself' for CI polygons is the canonical Plotly approach; hovermode='x unified', hoverinfo='skip' on fill traces, hovertemplate on data traces — all idiomatic Plotly patterns. yref='paper' for shape correctly used.
  • LM-02: Distinctive Features (3/5) — hovermode='x unified' and fill='toself' are Plotly-specific; interactive HTML output adds value. Missing opportunity to leverage rangeslider, spike lines, or rangeselector that would further showcase Plotly's time-series strengths.

Score Caps Applied

  • None

Strengths

  • Correct Okabe-Ito palette (#009E73 historical, #D55E00 forecast) with all theme tokens properly applied in both light and dark renders
  • Full spec compliance: solid historical line, dashed forecast, vertical forecast-start marker, nested 80%/95% CI bands with appropriate alpha, dotted connection bridging the transition
  • Both renders pass legibility checks — no dark-on-dark or light-on-light failures
  • Realistic monthly sales scenario with trend + seasonality + noise; widening CIs correctly modeled
  • KISS code structure, explicit random seed, clean imports, correct plot-{THEME}.png + HTML outputs
  • Idiomatic Plotly usage: fill='toself' for CI polygons, hovermode='x unified', hoverinfo='skip' on fill traces

Weaknesses

  • Design Excellence gap (DE-01=5/8): spines still visible (showline=True; explicitly removing top/right spines would clean up the frame and lift the visual quality
  • Short "Date" axis label at fontsize=22 matches the longer "Monthly Sales (Units)" label — slightly disproportionate for a 4-character label; consider reducing X-axis label size to ~14-16px
  • LM-02 at 3/5: no use of Plotly time-series–specific features like rangeslider, spike lines, or rangeselector that would better showcase Plotly's interactive strengths

Issues Found

  1. DE-01/DE-02 MODERATE: Top and right spines are still visible (showline=True without mirror=False removing them)
    • Fix: Add xaxis=dict(showline=True, mirror=False) with explicit top-spine removal, or use fig.update_xaxes(showline=True, linecolor=INK_SOFT) while ensuring no frame enclosure
  2. VQ-01 MINOR: X-axis label "Date" at fontsize=22 is disproportionately large for a short label
    • Fix: Reduce xaxis title font size to 14-16px

AI Feedback for Next Attempt

The implementation is high quality — spec fully met, palette correct, both themes pass readability. To push above 89: (1) explicitly remove top and right spines by setting showline=False on the top axis or using fig.update_layout(xaxis=dict(showline=True, mirror=False), yaxis=dict(showline=True, mirror=False)) and checking no enclosing frame appears; (2) reduce the "Date" X-axis label fontsize to 14-16px since it's a short label that doesn't need fontsize=22; (3) consider adding a rangeslider or spike lines to better leverage Plotly's interactive time-series capabilities for LM-02.

Verdict: APPROVED

@github-actions github-actions Bot added quality:89 Quality score 89/100 ai-approved Quality OK, ready for merge and removed quality:85 Quality score 85/100 labels May 19, 2026
@MarkusNeusinger MarkusNeusinger merged commit b380abc into main May 19, 2026
@MarkusNeusinger MarkusNeusinger deleted the implementation/timeseries-forecast-uncertainty/plotly branch May 19, 2026 13:34
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