From 18cf3e698a26d5574602b23da76d153a2701dbf1 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 13:18:58 +0000 Subject: [PATCH 1/4] feat(bokeh): implement timeseries-forecast-uncertainty Regen from quality 92. Addressed: - Added HoverTool for both historical and forecast lines (with CI bounds) - Removed enclosing box outline (outline_line_color=None) for L-shaped frame - Canvas corrected to 3200x1800 (from stale 4800x2700) - Font sizes aligned with style guide (18pt/14pt/12pt) - Title updated to include python language token --- .../implementations/python/bokeh.py | 85 +++++++++++++------ 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py b/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py index 5300c3c2c9..6a7599857d 100644 --- a/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py +++ b/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py @@ -1,7 +1,7 @@ -""" anyplot.ai +"""anyplot.ai timeseries-forecast-uncertainty: Time Series Forecast with Uncertainty Band -Library: bokeh 3.9.0 | Python 3.13.13 -Quality: 92/100 | Updated: 2026-05-16 +Library: bokeh | Python 3.13 +Quality: pending | Updated: 2026-05-19 """ import os @@ -11,7 +11,7 @@ import numpy as np import pandas as pd from bokeh.io import output_file, save -from bokeh.models import ColumnDataSource, Legend, Span +from bokeh.models import ColumnDataSource, HoverTool, Legend, Span from bokeh.plotting import figure from selenium import webdriver from selenium.webdriver.chrome.options import Options @@ -26,7 +26,6 @@ OKABE_ITO_1 = "#009E73" # Bluish green (brand) OKABE_ITO_2 = "#D55E00" # Vermillion -OKABE_ITO_3 = "#0072B2" # Blue OKABE_ITO_4 = "#CC79A7" # Reddish purple # Data - Monthly product sales with forecast @@ -58,9 +57,9 @@ # Create figure p = figure( - width=4800, - height=2700, - title="timeseries-forecast-uncertainty · bokeh · anyplot.ai", + width=3200, + height=1800, + title="timeseries-forecast-uncertainty · python · bokeh · anyplot.ai", x_axis_label="Date", y_axis_label="Sales (thousands)", x_axis_type="datetime", @@ -68,23 +67,23 @@ ) # Style title and axes -p.title.text_font_size = "28pt" +p.title.text_font_size = "18pt" p.title.text_color = INK -p.xaxis.axis_label_text_font_size = "22pt" -p.yaxis.axis_label_text_font_size = "22pt" +p.xaxis.axis_label_text_font_size = "14pt" +p.yaxis.axis_label_text_font_size = "14pt" p.xaxis.axis_label_text_color = INK p.yaxis.axis_label_text_color = INK -p.xaxis.major_label_text_font_size = "18pt" -p.yaxis.major_label_text_font_size = "18pt" +p.xaxis.major_label_text_font_size = "12pt" +p.yaxis.major_label_text_font_size = "12pt" p.xaxis.major_label_text_color = INK_SOFT p.yaxis.major_label_text_color = INK_SOFT -# Background and outline +# Background — outline=None removes the enclosing box (top/right spines equivalent) p.background_fill_color = PAGE_BG p.border_fill_color = PAGE_BG -p.outline_line_color = INK_SOFT +p.outline_line_color = None -# Axis styling +# Axis styling — keep left and bottom lines (L-shaped frame) p.xaxis.axis_line_color = INK_SOFT p.yaxis.axis_line_color = INK_SOFT p.xaxis.axis_line_width = 2 @@ -108,17 +107,26 @@ ) band_80 = p.patch(x="x", y="y", source=source_80, fill_color=OKABE_ITO_4, fill_alpha=0.30, line_color=None) -# Historical data line (solid) +# Historical data line (solid) with hover data source_hist = ColumnDataSource(data={"x": dates_hist, "y": actual}) -hist_line = p.line(x="x", y="y", source=source_hist, line_color=OKABE_ITO_1, line_width=4) - -# Forecast line (dashed) -source_forecast = ColumnDataSource(data={"x": dates_forecast, "y": forecast}) -forecast_line = p.line(x="x", y="y", source=source_forecast, line_color=OKABE_ITO_2, line_width=4, line_dash="dashed") +hist_line = p.line(x="x", y="y", source=source_hist, line_color=OKABE_ITO_1, line_width=3) + +# Forecast line (dashed) with CI data for hover tooltip +source_forecast = ColumnDataSource( + data={ + "x": dates_forecast, + "y": forecast, + "lower_80": lower_80, + "upper_80": upper_80, + "lower_95": lower_95, + "upper_95": upper_95, + } +) +forecast_line = p.line(x="x", y="y", source=source_forecast, line_color=OKABE_ITO_2, line_width=3, line_dash="dashed") -# Connection line from last historical to first forecast +# Connection line from last historical point to first forecast point source_connect = ColumnDataSource(data={"x": [dates_hist[-1], dates_forecast[0]], "y": [actual[-1], forecast[0]]}) -p.line(x="x", y="y", source=source_connect, line_color=OKABE_ITO_2, line_width=4, line_dash="dashed") +p.line(x="x", y="y", source=source_connect, line_color=OKABE_ITO_2, line_width=3, line_dash="dashed") # Vertical line at forecast start forecast_start = Span( @@ -126,6 +134,29 @@ ) p.add_layout(forecast_start) +# HoverTool for historical data +hover_hist = HoverTool( + renderers=[hist_line], + tooltips=[("Date", "@x{%b %Y}"), ("Sales", "@y{0.0}k")], + formatters={"@x": "datetime"}, + mode="vline", +) +p.add_tools(hover_hist) + +# HoverTool for forecast with confidence intervals +hover_forecast = HoverTool( + renderers=[forecast_line], + tooltips=[ + ("Date", "@x{%b %Y}"), + ("Forecast", "@y{0.0}k"), + ("80% CI", "[@lower_80{0.0}, @upper_80{0.0}]k"), + ("95% CI", "[@lower_95{0.0}, @upper_95{0.0}]k"), + ], + formatters={"@x": "datetime"}, + mode="vline", +) +p.add_tools(hover_forecast) + # Legend legend = Legend( items=[ @@ -137,7 +168,7 @@ location="top_left", ) -legend.label_text_font_size = "18pt" +legend.label_text_font_size = "12pt" legend.label_text_color = INK_SOFT legend.background_fill_color = ELEVATED_BG legend.background_fill_alpha = 0.95 @@ -149,7 +180,7 @@ legend.glyph_height = 20 p.add_layout(legend) -# Set y-axis range +# Set y-axis range with room for confidence bands p.y_range.start = 55 p.y_range.end = 175 @@ -158,7 +189,7 @@ save(p) # Screenshot with headless Chrome -W, H = 4800, 2700 +W, H = 3200, 1800 opts = Options() for arg in ( "--headless=new", From 2143d6b5684d242f75905f0acd822dc9460b0782 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 19 May 2026 13:19:22 +0000 Subject: [PATCH 2/4] chore(bokeh): add metadata for timeseries-forecast-uncertainty --- .../metadata/python/bokeh.yaml | 230 +----------------- 1 file changed, 9 insertions(+), 221 deletions(-) diff --git a/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml b/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml index 47b7476df8..3d08f4d360 100644 --- a/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml +++ b/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml @@ -1,10 +1,13 @@ +# Per-library metadata for bokeh implementation of timeseries-forecast-uncertainty +# Auto-generated by impl-generate.yml + library: bokeh language: python specification_id: timeseries-forecast-uncertainty created: '2026-01-07T16:30:50Z' -updated: '2026-05-16T22:29:32Z' -generated_by: claude-haiku -workflow_run: 25974524041 +updated: '2026-05-19T13:19:22Z' +generated_by: claude-sonnet +workflow_run: 26099181190 issue: 3188 language_version: 3.13.13 library_version: 3.9.0 @@ -12,222 +15,7 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/timeserie preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-dark.html -quality_score: 92 +quality_score: null review: - strengths: - - Complete spec compliance with all required features present and correctly implemented - - Excellent visual quality with proper theme adaptation to both light and dark modes - - Idiomatic Bokeh usage with ColumnDataSource, figure, patch, Span, and Legend patterns - - Clean code structure with deterministic data generation and proper imports - - Professional styling with proper font sizes, color tokens, spacing, and typography - hierarchy - - Correct Okabe-Ito palette implementation maintaining color identity across themes - - Nested confidence bands with appropriate opacity creating clear visual distinction - weaknesses: - - Limited use of distinctive Bokeh interactive features such as HoverTool or callbacks - - Standard spine treatment could be enhanced by removing top and right spines for - visual refinement - image_description: |- - Light render (plot-light.png): - Background: Warm off-white (#FAF8F1) - correct theme background - Chrome: Title "timeseries-forecast-uncertainty · bokeh · anyplot.ai" in dark text; axis labels "Date" and "Sales (thousands)" clearly visible; all tick labels readable in dark INK_SOFT color - Data: Solid bluish-green line (#009E73) for historical data; dashed vermillion line (#D55E00) for forecast; nested reddish-purple bands (α=0.30 for 80%, α=0.15 for 95%); connection line from last historical to first forecast - Legend: Clearly identifies all four elements with legible text on elevated background (#FFFDF6) - Legibility verdict: PASS - All elements clearly visible and readable on light background - - Dark render (plot-dark.png): - Background: Warm near-black (#1A1A17) - correct theme background - Chrome: Title in light text (#F0EFE8); axis labels readable in light text; tick labels in light INK_SOFT (#B8B7B0) with excellent contrast against dark background - no dark-on-dark failures - Data: Identical colors to light render - bluish-green historical line, vermillion forecast line, reddish-purple confidence bands with same opacity values - Legend: Light text on elevated dark background (#242420) is clearly readable - Legibility verdict: PASS - All text readable with proper theme contrast; no dark-on-dark failures detected - criteria_checklist: - visual_quality: - score: 30 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 8 - max: 8 - passed: true - comment: All text explicitly sized; readable in both themes with proper color - tokens - - id: VQ-02 - name: No Overlap - score: 6 - max: 6 - passed: true - comment: No overlapping elements; legend, lines, bands, labels all clearly - separated - - id: VQ-03 - name: Element Visibility - score: 6 - max: 6 - passed: true - comment: Confidence bands properly opacity-blended; line widths and sizes - appropriate - - id: VQ-04 - name: Color Accessibility - score: 2 - max: 2 - passed: true - comment: Okabe-Ito palette used correctly; colorblind-safe - - id: VQ-05 - name: Layout & Canvas - score: 4 - max: 4 - passed: true - comment: 4800×2700 px well-proportioned; generous margins and padding - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: Descriptive labels with units; title follows spec format - - id: VQ-07 - name: Palette Compliance - score: 2 - max: 2 - passed: true - comment: 'First series #009E73; backgrounds correct; both themes correct' - design_excellence: - score: 14 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 5 - max: 8 - passed: true - comment: Good use of nested confidence bands; professional polish; not maximally - sophisticated - - id: DE-02 - name: Visual Refinement - score: 4 - max: 6 - passed: true - comment: Subtle grid; refined legend styling; could benefit from spine removal - - id: DE-03 - name: Data Storytelling - score: 5 - max: 6 - passed: true - comment: Clear focal point with forecast bands; effective visual hierarchy - through dashing and color - spec_compliance: - score: 15 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct time series forecast plot with uncertainty - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: 'All features present: historical, forecast, confidence bands, vertical - line marker' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: X/Y correct; axes show all data appropriately - - id: SC-04 - name: Title & Legend - score: 3 - max: 3 - passed: true - comment: Correct title format; legend labels match spec - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: 'Shows all aspects: trend, seasonality, forecast uncertainty growth' - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Monthly sales data realistic and neutral - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: Values (80-175 thousands) sensible for domain - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: Simple linear script; no unnecessary functions - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: Seed set with np.random.seed(42) - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: All imports used; no extraneous dependencies - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Appropriate complexity; no fake functionality - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Correctly saves as plot-{THEME}.html and .png - library_mastery: - score: 8 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 5 - max: 5 - passed: true - comment: 'Idiomatic Bokeh: ColumnDataSource, figure, patch, Span, Legend' - - id: LM-02 - name: Distinctive Features - score: 3 - max: 5 - passed: true - comment: Good use of Span and nested patch; could add HoverTool for interactivity - verdict: APPROVED -impl_tags: - dependencies: - - selenium - techniques: - - custom-legend - - html-export - patterns: - - data-generation - - columndatasource - dataprep: - - time-series - styling: - - alpha-blending - - grid-styling + strengths: [] + weaknesses: [] From 808910f808123f2b4d6dc466ed52075a0c51b680 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 19 May 2026 13:26:59 +0000 Subject: [PATCH 3/4] chore(bokeh): update quality score 84 and review feedback for timeseries-forecast-uncertainty --- .../implementations/python/bokeh.py | 6 +- .../metadata/python/bokeh.yaml | 244 +++++++++++++++++- 2 files changed, 240 insertions(+), 10 deletions(-) diff --git a/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py b/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py index 6a7599857d..0d6065bbad 100644 --- a/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py +++ b/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai timeseries-forecast-uncertainty: Time Series Forecast with Uncertainty Band -Library: bokeh | Python 3.13 -Quality: pending | Updated: 2026-05-19 +Library: bokeh 3.9.0 | Python 3.13.13 +Quality: 84/100 | Updated: 2026-05-19 """ import os diff --git a/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml b/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml index 3d08f4d360..3a9c07965e 100644 --- a/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml +++ b/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for bokeh implementation of timeseries-forecast-uncertainty -# Auto-generated by impl-generate.yml - library: bokeh language: python specification_id: timeseries-forecast-uncertainty created: '2026-01-07T16:30:50Z' -updated: '2026-05-19T13:19:22Z' +updated: '2026-05-19T13:26:59Z' generated_by: claude-sonnet workflow_run: 26099181190 issue: 3188 @@ -15,7 +12,240 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/timeserie preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-dark.html -quality_score: null +quality_score: 84 review: - strengths: [] - weaknesses: [] + strengths: + - 'Perfect spec compliance: all required features present (historical line, dashed + forecast, vertical separator, nested 80%+95% CI bands, connection line).' + - Proper theme adaptation throughout — backgrounds, text, grid, legend use correct + tokens for both light and dark renders with no dark-on-dark failures. + - 'Idiomatic Bokeh usage: Span, ColumnDataSource, HoverTool with CI data, and Legend + via add_layout() are library-correct patterns.' + - Clean reproducible code with np.random.seed(42) and linear KISS structure. + - 'Excellent data quality: realistic sales scenario with trend, seasonality, and + growing uncertainty.' + weaknesses: + - 'CI bands use #CC79A7 (Okabe-Ito pos 4, purple) while forecast line uses #D55E00 + (orange) — color-family mismatch breaks visual grouping of forecast+uncertainty. + Fix: change CI band fill_color to OKABE_ITO_2 (#D55E00) with fill_alpha=0.25 (80% + CI) and fill_alpha=0.12 (95% CI).' + - 95% CI outer band at fill_alpha=0.15 is too faint especially in dark theme. With + orange color fix, use 0.25 inner and 0.12 outer. + - y_range.end=175 leaves ~10-15 units of empty space above forecast peak — reduce + to 170 or let Bokeh auto-range. + - Missing p.xaxis.major_tick_line_color = INK_SOFT and p.yaxis.major_tick_line_color + = INK_SOFT — tick marks may default to black in dark theme. + image_description: |- + Light render (plot-light.png): + Background: Warm off-white #FAF8F1 — correct, not pure white. + Chrome: Title "timeseries-forecast-uncertainty · python · bokeh · anyplot.ai" in dark #1A1A17 text — clearly readable. Y-axis label "Sales (thousands)" and tick values (80, 100, 120, 140, 160) in dark/muted tones — all readable. X-axis date tick labels in INK_SOFT gray — present and readable. + Data: Historical solid line in #009E73 (brand green, first series — correct). Forecast dashed line in #D55E00 (orange, Okabe-Ito pos 2). CI bands in #CC79A7 (reddish-purple, Okabe-Ito pos 4) at alpha=0.30 (80%) and alpha=0.15 (95%). Vertical dashed separator at forecast start. Legend top-left with warm elevated background. + Legibility verdict: PASS + + Dark render (plot-dark.png): + Background: Near-black #1A1A17 — correct, not pure black. + Chrome: Title in light #F0EFE8 text — clearly readable. Y-axis label and tick values in light INK_SOFT #B8B7B0 — readable. X-axis date labels in INK_SOFT — readable. Legend background uses #242420 (ELEVATED_BG) with light text — readable. No dark-on-dark failures detected. + Data: Historical green line identical to light render (#009E73). Forecast orange dashed line identical. CI bands retain reddish-purple hue; 95% outer band at alpha=0.15 is noticeably faint on dark background but still visible. All data colors identical to light render — only chrome flipped. + Legibility verdict: PASS + criteria_checklist: + visual_quality: + score: 26 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 6 + max: 8 + passed: true + comment: All font sizes explicitly set; title, axis labels, y-axis ticks clearly + readable in both themes. X-axis date labels present but faint at preview + resolution. + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: No overlapping elements; legend top-left clears all data. + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Historical and forecast lines well-visible. 95% CI at alpha=0.15 + is quite faint especially in dark theme. + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: CVD-safe Okabe-Ito palette; green vs orange distinction not red-green + only. + - id: VQ-05 + name: Layout & Canvas + score: 3 + max: 4 + passed: true + comment: Good canvas utilization but y_range.end=175 leaves empty space above + forecast peak (~165). + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Y-axis has units 'Sales (thousands)'; X-axis 'Date' acceptable. + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, forecast #D55E00, CI bands #CC79A7 — all Okabe-Ito. + Backgrounds #FAF8F1/#1A1A17 correct. Both renders theme-correct.' + design_excellence: + score: 11 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 4 + max: 8 + passed: false + comment: Well-configured style-guide default. CI bands (purple) disconnected + from forecast line (orange) reduces color harmony. + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: X-grid disabled, Y-grid alpha=0.10, L-shaped frame, theme-adaptive + legend. Clearly above defaults. + - id: DE-03 + name: Data Storytelling + score: 3 + max: 6 + passed: false + comment: Solid/dashed contrast and vertical separator create historical-vs-forecast + narrative. Color mismatch between orange forecast and purple CI bands weakens + story coherence. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: 'Correct: time series with forecast and nested uncertainty bands.' + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: 'All required features present: solid historical, dashed forecast, + vertical separator, 80%+95% CI bands, legend.' + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: Datetime X-axis, sales Y-axis, all data within range. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: 'Title exactly correct. Legend labels: Historical Data, Forecast, + 80% CI, 95% CI.' + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 'Full feature set: trend+seasonality in historical, growing forecast + uncertainty, both CI levels.' + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Monthly product sales, 3-year history, 12-month forecast. Neutral, + realistic. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Values 80-165k units realistic; uncertainty grows proportionally + over time. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Clean linear flow: imports → tokens → data → figure → style → glyphs + → save.' + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: np.random.seed(42). + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All imports used. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean Pythonic code; connection line between history/forecast is + elegant. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.html and plot-{THEME}.png; current API. + library_mastery: + score: 7 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: ColumnDataSource throughout, Span model, explicit Legend with add_layout(), + HoverTool with formatters — idiomatic Bokeh. + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: HoverTool with CI data exposed in tooltip is distinctly Bokeh-interactive; + Span for forecast boundary is Bokeh-native. + verdict: REJECTED +impl_tags: + dependencies: + - selenium + techniques: + - hover-tooltips + - html-export + patterns: + - data-generation + - columndatasource + dataprep: + - time-series + styling: + - alpha-blending From 4c5cd3df03d2af891d76287fd0e256ecca2ca804 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 19 May 2026 13:41:29 +0000 Subject: [PATCH 4/4] chore(bokeh): update quality score 88 and review feedback for timeseries-forecast-uncertainty --- .../implementations/python/bokeh.py | 2 +- .../metadata/python/bokeh.yaml | 178 ++++++++++-------- 2 files changed, 97 insertions(+), 83 deletions(-) diff --git a/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py b/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py index 0d6065bbad..0b8ae31315 100644 --- a/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py +++ b/plots/timeseries-forecast-uncertainty/implementations/python/bokeh.py @@ -1,7 +1,7 @@ """ anyplot.ai timeseries-forecast-uncertainty: Time Series Forecast with Uncertainty Band Library: bokeh 3.9.0 | Python 3.13.13 -Quality: 84/100 | Updated: 2026-05-19 +Quality: 88/100 | Updated: 2026-05-19 """ import os diff --git a/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml b/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml index 3a9c07965e..24b05e7a32 100644 --- a/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml +++ b/plots/timeseries-forecast-uncertainty/metadata/python/bokeh.yaml @@ -2,7 +2,7 @@ library: bokeh language: python specification_id: timeseries-forecast-uncertainty created: '2026-01-07T16:30:50Z' -updated: '2026-05-19T13:26:59Z' +updated: '2026-05-19T13:41:28Z' generated_by: claude-sonnet workflow_run: 26099181190 issue: 3188 @@ -12,120 +12,127 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/timeserie preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/python/bokeh/plot-dark.html -quality_score: 84 +quality_score: 88 review: strengths: - - 'Perfect spec compliance: all required features present (historical line, dashed - forecast, vertical separator, nested 80%+95% CI bands, connection line).' - - Proper theme adaptation throughout — backgrounds, text, grid, legend use correct - tokens for both light and dark renders with no dark-on-dark failures. - - 'Idiomatic Bokeh usage: Span, ColumnDataSource, HoverTool with CI data, and Legend - via add_layout() are library-correct patterns.' - - Clean reproducible code with np.random.seed(42) and linear KISS structure. - - 'Excellent data quality: realistic sales scenario with trend, seasonality, and - growing uncertainty.' + - Full spec compliance — all required features (historical line, forecast, 80%/95% + CI bands, vertical divider, legend) implemented correctly + - Perfect data quality — realistic monthly sales scenario with plausible trend, + seasonality, and growing forecast uncertainty + - 'Proper Bokeh idioms: ColumnDataSource throughout, Span for the divider, dual + HoverTools with datetime formatters and CI data' + - Theme-adaptive chrome implemented correctly in both renders — no dark-on-dark + failures + - Nested CI band layering (95% drawn first, 80% on top) creates correct visual nesting weaknesses: - - 'CI bands use #CC79A7 (Okabe-Ito pos 4, purple) while forecast line uses #D55E00 - (orange) — color-family mismatch breaks visual grouping of forecast+uncertainty. - Fix: change CI band fill_color to OKABE_ITO_2 (#D55E00) with fill_alpha=0.25 (80% - CI) and fill_alpha=0.12 (95% CI).' - - 95% CI outer band at fill_alpha=0.15 is too faint especially in dark theme. With - orange color fix, use 0.25 inner and 0.12 outer. - - y_range.end=175 leaves ~10-15 units of empty space above forecast peak — reduce - to 170 or let Bokeh auto-range. - - Missing p.xaxis.major_tick_line_color = INK_SOFT and p.yaxis.major_tick_line_color - = INK_SOFT — tick marks may default to black in dark theme. + - Y-axis range (55–175) is wider than needed for data range (~75–165), leaving ~30% + of vertical canvas as empty whitespace; tighten to ~70–170 or compute from min(lower_95)-10 + - CI bands reach the right canvas edge with no x-axis padding, giving a slightly + clipped appearance; add a small x-range buffer after the last forecast date + - 'Dashed forecast line (3px, #D55E00) becomes hard to see inside the confidence + band fill — increase to line_width=4 or use lighter CI band alpha' + - major_tick_line_color not explicitly set for either axis; set p.xaxis.major_tick_line_color + = INK_SOFT and p.yaxis.major_tick_line_color = INK_SOFT + - Bokeh native Band annotation model would be more idiomatic than the patch-polygon + workaround for CI regions image_description: |- Light render (plot-light.png): - Background: Warm off-white #FAF8F1 — correct, not pure white. - Chrome: Title "timeseries-forecast-uncertainty · python · bokeh · anyplot.ai" in dark #1A1A17 text — clearly readable. Y-axis label "Sales (thousands)" and tick values (80, 100, 120, 140, 160) in dark/muted tones — all readable. X-axis date tick labels in INK_SOFT gray — present and readable. - Data: Historical solid line in #009E73 (brand green, first series — correct). Forecast dashed line in #D55E00 (orange, Okabe-Ito pos 2). CI bands in #CC79A7 (reddish-purple, Okabe-Ito pos 4) at alpha=0.30 (80%) and alpha=0.15 (95%). Vertical dashed separator at forecast start. Legend top-left with warm elevated background. - Legibility verdict: PASS + Background: Warm off-white (#FAF8F1) — correct theme surface. + Chrome: Title "timeseries-forecast-uncertainty · python · bokeh · anyplot.ai" in dark ink (INK token) — readable. Y-axis label "Sales (thousands)" in dark ink — readable. X-axis label "Date" in dark ink — readable. Y-axis tick labels (80, 100, 120, 140, 160) in INK_SOFT — readable. X-axis datetime tick labels present but sparse and small. + Data: Historical line = #009E73 (Okabe-Ito position 1, brand green), solid, 3px — clearly visible. Forecast line = #D55E00 (OI position 2, vermillion), dashed, 3px — visible but partially obscured within CI band fills. 80% CI band = #CC79A7 at fill_alpha=0.30 (darker peach tone). 95% CI band = #CC79A7 at fill_alpha=0.15 (lighter peach tone). Vertical dashed divider at forecast start — visible. Legend in top-left: 4 items readable. Upper y-axis region (~145–175) is largely empty (wasted vertical space). Right edge of CI bands meets canvas boundary with minimal padding. + Legibility verdict: PASS — all text readable, no overflow, no light-on-light failures. Dark render (plot-dark.png): - Background: Near-black #1A1A17 — correct, not pure black. - Chrome: Title in light #F0EFE8 text — clearly readable. Y-axis label and tick values in light INK_SOFT #B8B7B0 — readable. X-axis date labels in INK_SOFT — readable. Legend background uses #242420 (ELEVATED_BG) with light text — readable. No dark-on-dark failures detected. - Data: Historical green line identical to light render (#009E73). Forecast orange dashed line identical. CI bands retain reddish-purple hue; 95% outer band at alpha=0.15 is noticeably faint on dark background but still visible. All data colors identical to light render — only chrome flipped. - Legibility verdict: PASS + Background: Warm near-black (#1A1A17) — correct dark theme surface. + Chrome: Title in light ink (INK token = #F0EFE8) — readable against dark background. Y-axis label and axis labels in light ink — readable. Tick labels in INK_SOFT (#B8B7B0) — readable. Legend background in ELEVATED_BG (#242420) with INK_SOFT label text — readable. No dark-on-dark failures observed. + Data: Historical line = #009E73 — identical to light render as required (data colors constant between themes). Forecast dashed line = #D55E00 — visible. CI bands take on darker brownish-orange appearance due to alpha blending over near-black background (expected behavior with alpha-blended fills). Both CI bands remain visually distinguishable from each other and from the background. + Legibility verdict: PASS — all text elements are light-colored against dark surface, no dark-on-dark failures. criteria_checklist: visual_quality: - score: 26 + score: 27 max: 30 items: - id: VQ-01 name: Text Legibility - score: 6 + score: 7 max: 8 passed: true - comment: All font sizes explicitly set; title, axis labels, y-axis ticks clearly - readable in both themes. X-axis date labels present but faint at preview - resolution. + comment: 'All font sizes explicitly set (title 18pt, axis labels 14pt, ticks + 12pt, legend 12pt). Good proportions. Minor: x-axis datetime tick labels + sparse and potentially small at mobile scale.' - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: No overlapping elements; legend top-left clears all data. + comment: No overlapping text or data collisions. Legend sits cleanly without + intersecting data. - id: VQ-03 name: Element Visibility score: 5 max: 6 passed: true - comment: Historical and forecast lines well-visible. 95% CI at alpha=0.15 - is quite faint especially in dark theme. + comment: 'Lines and bands visible. Minor: dashed forecast line partially obscured + within CI band fills due to alpha overlap; increase line_width or reduce + band alpha.' - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: CVD-safe Okabe-Ito palette; green vs orange distinction not red-green - only. + comment: Okabe-Ito palette is colorblind-safe. Green/orange combination provides + adequate luminance contrast. - id: VQ-05 name: Layout & Canvas score: 3 max: 4 passed: true - comment: Good canvas utilization but y_range.end=175 leaves empty space above - forecast peak (~165). + comment: 'Good horizontal fill. Deduction: y-range 55–175 vs data range ~75–165 + leaves ~30% vertical whitespace. CI bands reach right canvas edge with no + padding.' - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Y-axis has units 'Sales (thousands)'; X-axis 'Date' acceptable. + comment: 'X-axis: ''Date''. Y-axis: ''Sales (thousands)'' with units. Title + correctly formatted.' - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true - comment: 'First series #009E73, forecast #D55E00, CI bands #CC79A7 — all Okabe-Ito. - Backgrounds #FAF8F1/#1A1A17 correct. Both renders theme-correct.' + comment: 'First series #009E73, second #D55E00. CI bands use OI position 4 + (#CC79A7) — intentional design grouping. Background #FAF8F1/#1A1A17 correct. + Chrome fully theme-adaptive.' design_excellence: - score: 11 + score: 13 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 4 + score: 5 max: 8 - passed: false - comment: Well-configured style-guide default. CI bands (purple) disconnected - from forecast line (orange) reduces color harmony. + passed: true + comment: 'Above baseline: distinct color coding for historical vs forecast, + nested CI bands with alpha layering, clean L-shaped spine removal, theme-adaptive + tokens. Not publication-ready.' - id: DE-02 name: Visual Refinement score: 4 max: 6 passed: true - comment: X-grid disabled, Y-grid alpha=0.10, L-shaped frame, theme-adaptive - legend. Clearly above defaults. + comment: 'Y-axis-only grid at 10% opacity. Top/right spines removed. Legend + styled with elevated background. Deduction: wasted vertical whitespace, + missing major_tick_line_color.' - id: DE-03 name: Data Storytelling - score: 3 + score: 4 max: 6 - passed: false - comment: Solid/dashed contrast and vertical separator create historical-vs-forecast - narrative. Color mismatch between orange forecast and purple CI bands weakens - story coherence. + passed: true + comment: Vertical divider marks regime change, growing CI bands convey increasing + uncertainty, green→orange shift distinguishes observed from projected. Clear + narrative without annotation. spec_compliance: score: 15 max: 15 @@ -135,27 +142,29 @@ review: score: 5 max: 5 passed: true - comment: 'Correct: time series with forecast and nested uncertainty bands.' + comment: 'Correct: time series with historical period, forecast projection, + and nested 80%/95% confidence bands.' - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: 'All required features present: solid historical, dashed forecast, - vertical separator, 80%+95% CI bands, legend.' + comment: 'All spec features: solid historical line, dashed forecast, vertical + forecast-start marker, 80% CI, 95% CI, legend.' - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: Datetime X-axis, sales Y-axis, all data within range. + comment: Date on x-axis, Sales (thousands) on y-axis. All 48 data points correctly + mapped. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: 'Title exactly correct. Legend labels: Historical Data, Forecast, - 80% CI, 95% CI.' + comment: 'Title: ''timeseries-forecast-uncertainty · python · bokeh · anyplot.ai''. + Legend: Historical Data, Forecast, 80% CI, 95% CI — all correct.' data_quality: score: 15 max: 15 @@ -165,22 +174,22 @@ review: score: 6 max: 6 passed: true - comment: 'Full feature set: trend+seasonality in historical, growing forecast - uncertainty, both CI levels.' + comment: 'Shows all aspects: trend, seasonality in history, growing uncertainty + width over forecast horizon, two CI levels, smooth handoff at boundary.' - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Monthly product sales, 3-year history, 12-month forecast. Neutral, - realistic. + comment: Monthly product sales with 3-year history and 12-month forecast — + real, neutral, business-relevant scenario. - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Values 80-165k units realistic; uncertainty grows proportionally - over time. + comment: Sales 80–140k, uncertainty ±5–25k growing over forecast. Seasonal + amplitude ~15k. All proportionally realistic. code_quality: score: 10 max: 10 @@ -190,58 +199,63 @@ review: score: 3 max: 3 passed: true - comment: 'Clean linear flow: imports → tokens → data → figure → style → glyphs - → save.' + comment: 'Flat: theme tokens → data generation → figure + styling → glyphs + → legend → save. No functions or classes.' - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: np.random.seed(42). + comment: np.random.seed(42) set. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: All imports used. + comment: 'All imports used: ColumnDataSource, HoverTool, Legend, Span all + referenced.' - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean Pythonic code; connection line between history/forecast is - elegant. + comment: Idiomatic patch-polygon approach for CI bands. HoverTool with datetime + formatters clean and well-parameterized. - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot-{THEME}.html and plot-{THEME}.png; current API. + comment: Saves plot-{THEME}.html + plot-{THEME}.png via Selenium screenshot. + Current Bokeh 3.x API. library_mastery: - score: 7 + score: 8 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 4 + score: 5 max: 5 passed: true - comment: ColumnDataSource throughout, Span model, explicit Legend with add_layout(), - HoverTool with formatters — idiomatic Bokeh. + comment: ColumnDataSource for all renderers, Span for vertical line, manual + Legend with explicit items, HoverTool with formatters and mode=vline. Patch-polygon + for CI bands is correct Bokeh idiom. - id: LM-02 name: Distinctive Features score: 3 max: 5 passed: true - comment: HoverTool with CI data exposed in tooltip is distinctly Bokeh-interactive; - Span for forecast boundary is Bokeh-native. - verdict: REJECTED + comment: Dual HoverTools with CI data formatted for forecast line is Bokeh-distinctive. + HTML export leverages Bokeh's interactivity advantage. Could use native + Band model instead of patch-polygon for more idiomatic approach. + verdict: APPROVED impl_tags: dependencies: - selenium techniques: - hover-tooltips - html-export + - custom-legend patterns: - data-generation - columndatasource