From 6d17b714509c5b698b81a728035d5097abe9fc41 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 7 May 2026 11:47:19 +0000 Subject: [PATCH 1/3] chore(highcharts): add metadata for shap-waterfall --- .../implementations/python/highcharts.py | 241 ++++++++++++++++++ .../metadata/python/highcharts.yaml | 21 ++ 2 files changed, 262 insertions(+) create mode 100644 plots/shap-waterfall/implementations/python/highcharts.py create mode 100644 plots/shap-waterfall/metadata/python/highcharts.yaml diff --git a/plots/shap-waterfall/implementations/python/highcharts.py b/plots/shap-waterfall/implementations/python/highcharts.py new file mode 100644 index 0000000000..2590f92294 --- /dev/null +++ b/plots/shap-waterfall/implementations/python/highcharts.py @@ -0,0 +1,241 @@ +"""anyplot.ai +shap-waterfall: SHAP Waterfall Plot for Feature Attribution +Library: highcharts | Python 3.13 +Quality: pending | Created: 2026-05-07 +""" + +import base64 +import json +import os +import tempfile +import time +import urllib.request +from pathlib import Path + +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + + +# Theme tokens +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" +GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)" + +BRAND = "#009E73" # Okabe-Ito pos 1 — baseline & prediction bars +POSITIVE_COLOR = "#D55E00" # Okabe-Ito pos 2 — positive SHAP (pushes risk up) +NEGATIVE_COLOR = "#0072B2" # Okabe-Ito pos 3 — negative SHAP (pushes risk down) + +# Data — credit scoring model explaining a single loan application +# Features sorted by absolute SHAP value (largest contribution first = top of chart) +BASE_VALUE = 0.35 # Expected probability of default across all applicants + +features = [ + "Credit Score", + "Debt-to-Income", + "Annual Income", + "Loan Amount", + "Employment Years", + "Payment History", + "Open Accounts", + "Credit Inquiries", + "Credit Age", + "Savings Balance", +] +shap_values = [-0.18, +0.15, -0.12, +0.09, -0.07, -0.05, +0.04, +0.03, -0.02, -0.02] +FINAL_VALUE = round(BASE_VALUE + sum(shap_values), 4) + +# Build waterfall data: base bar → feature deltas → isSum final +categories = ["E[f(x)] Baseline", *features, "f(x) Prediction"] + +data_points = [{"y": BASE_VALUE, "color": BRAND}] +for sv in shap_values: + data_points.append({"y": sv, "color": POSITIVE_COLOR if sv > 0 else NEGATIVE_COLOR}) +data_points.append({"isSum": True, "color": BRAND}) + +# Chart configuration (JSON-serializable; JS functions injected via string replace) +chart_config = { + "chart": { + "type": "waterfall", + "inverted": True, + "width": 4800, + "height": 2700, + "backgroundColor": PAGE_BG, + "marginLeft": 340, + "marginRight": 220, + "marginTop": 130, + "marginBottom": 220, + "style": {"fontFamily": "Arial, sans-serif", "color": INK}, + }, + "title": { + "text": "Credit Default Risk · shap-waterfall · highcharts · anyplot.ai", + "style": {"fontSize": "28px", "fontWeight": "normal", "color": INK}, + "align": "left", + "x": 340, + }, + "xAxis": { + "categories": categories, + "title": {"text": "Feature", "style": {"fontSize": "22px", "color": INK}}, + "labels": {"style": {"fontSize": "20px", "color": INK_SOFT}}, + "lineColor": INK_SOFT, + "tickColor": INK_SOFT, + "gridLineColor": GRID, + }, + "yAxis": { + "title": {"text": "Probability of Default", "style": {"fontSize": "22px", "color": INK}}, + "labels": {"style": {"fontSize": "18px", "color": INK_SOFT}, "formatter": "__YAXIS_FORMATTER__"}, + "lineColor": INK_SOFT, + "tickColor": INK_SOFT, + "gridLineColor": GRID, + "gridLineWidth": 1, + "min": -0.02, + "max": 0.50, + "plotLines": [ + { + "value": BASE_VALUE, + "color": INK_SOFT, + "width": 2, + "dashStyle": "Dash", + "zIndex": 2, + "label": { + "text": f"Baseline {BASE_VALUE:.2f}", + "align": "right", + "rotation": 0, + "x": -6, + "y": -12, + "style": {"fontSize": "16px", "color": INK_SOFT}, + }, + }, + { + "value": FINAL_VALUE, + "color": BRAND, + "width": 2, + "dashStyle": "ShortDot", + "zIndex": 2, + "label": { + "text": f"Prediction {FINAL_VALUE:.2f}", + "align": "right", + "rotation": 0, + "x": -6, + "y": -12, + "style": {"fontSize": "16px", "color": BRAND}, + }, + }, + ], + }, + "legend": {"enabled": False}, + "tooltip": {"enabled": False}, + "plotOptions": { + "waterfall": { + "lineWidth": 2, + "lineColor": INK_SOFT, + "borderWidth": 0, + "groupPadding": 0.05, + "pointPadding": 0.08, + "dataLabels": { + "enabled": True, + "formatter": "__DATA_LABEL_FORMATTER__", + "style": {"fontSize": "18px", "fontWeight": "bold", "color": INK, "textOutline": "none"}, + "inside": False, + }, + } + }, + "series": [{"name": "SHAP Attribution", "data": data_points}], +} + +# Inject JavaScript formatter functions (not JSON-serializable, so replace placeholders) +config_json = json.dumps(chart_config) + +yaxis_formatter = """function() { + return Highcharts.numberFormat(this.value, 2); +}""" +config_json = config_json.replace('"__YAXIS_FORMATTER__"', yaxis_formatter) + +data_label_formatter = """function() { + if (this.point.isSum) { + return 'f(x) = ' + Highcharts.numberFormat(this.y, 2); + } + if (this.point.index === 0) { + return 'E[f(x)] = ' + Highcharts.numberFormat(this.y, 2); + } + var sign = this.y > 0 ? '+' : ''; + return sign + Highcharts.numberFormat(this.y, 3); +}""" +config_json = config_json.replace('"__DATA_LABEL_FORMATTER__"', data_label_formatter) + + +# Download Highcharts JS with multiple CDN fallbacks +def download_js(paths, timeout=15): + cdn_bases = [ + "https://cdn.jsdelivr.net/npm/highcharts@11/", + "https://unpkg.com/highcharts@11/", + "https://code.highcharts.com/", + ] + for path in paths: + for base in cdn_bases: + url = base + path + for attempt in range(2): + try: + req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(req, timeout=timeout) as resp: + return resp.read().decode("utf-8") + except Exception: + if attempt == 0: + time.sleep(1) + return None + + +highcharts_js = download_js(["highcharts.js"]) +if highcharts_js is None: + raise RuntimeError("Failed to download highcharts.js from all CDNs") + +# Waterfall chart type lives in highcharts-more.js +highcharts_more_js = download_js(["highcharts-more.js"]) +if highcharts_more_js is None: + raise RuntimeError("Failed to download highcharts-more.js from all CDNs") + +# Generate HTML with inline Highcharts JS (core + more module for waterfall type) +html_content = f""" + + + + + + + +
+ + +""" + +# Save interactive HTML artifact +with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f: + f.write(html_content) + +# Screenshot via headless Chrome with CDP for full-resolution capture +with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: + f.write(html_content) + temp_path = f.name + +chrome_options = Options() +chrome_options.add_argument("--headless=new") +chrome_options.add_argument("--no-sandbox") +chrome_options.add_argument("--disable-dev-shm-usage") +chrome_options.add_argument("--disable-gpu") +chrome_options.add_argument("--hide-scrollbars") +chrome_options.add_argument("--force-device-scale-factor=1") + +driver = webdriver.Chrome(options=chrome_options) +driver.get(f"file://{temp_path}") +time.sleep(5) + +screenshot_config = {"captureBeyondViewport": True, "clip": {"x": 0, "y": 0, "width": 4800, "height": 2700, "scale": 1}} +result = driver.execute_cdp_cmd("Page.captureScreenshot", screenshot_config) +with open(f"plot-{THEME}.png", "wb") as f: + f.write(base64.b64decode(result["data"])) +driver.quit() + +Path(temp_path).unlink() diff --git a/plots/shap-waterfall/metadata/python/highcharts.yaml b/plots/shap-waterfall/metadata/python/highcharts.yaml new file mode 100644 index 0000000000..1d5c61aec8 --- /dev/null +++ b/plots/shap-waterfall/metadata/python/highcharts.yaml @@ -0,0 +1,21 @@ +# Per-library metadata for highcharts implementation of shap-waterfall +# Auto-generated by impl-generate.yml + +library: highcharts +language: python +specification_id: shap-waterfall +created: '2026-05-07T11:47:19Z' +updated: '2026-05-07T11:47:19Z' +generated_by: claude-sonnet +workflow_run: 25493326647 +issue: 5237 +python_version: 3.13.13 +library_version: unknown +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-dark.html +quality_score: null +review: + strengths: [] + weaknesses: [] From 7c29aae75196b210b1ffaeb8527c8e338999e818 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 7 May 2026 11:53:28 +0000 Subject: [PATCH 2/3] chore(highcharts): update quality score 86 and review feedback for shap-waterfall --- .../implementations/python/highcharts.py | 6 +- .../metadata/python/highcharts.yaml | 238 +++++++++++++++++- 2 files changed, 234 insertions(+), 10 deletions(-) diff --git a/plots/shap-waterfall/implementations/python/highcharts.py b/plots/shap-waterfall/implementations/python/highcharts.py index 2590f92294..7965200888 100644 --- a/plots/shap-waterfall/implementations/python/highcharts.py +++ b/plots/shap-waterfall/implementations/python/highcharts.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai shap-waterfall: SHAP Waterfall Plot for Feature Attribution -Library: highcharts | Python 3.13 -Quality: pending | Created: 2026-05-07 +Library: highcharts unknown | Python 3.13.13 +Quality: 86/100 | Created: 2026-05-07 """ import base64 diff --git a/plots/shap-waterfall/metadata/python/highcharts.yaml b/plots/shap-waterfall/metadata/python/highcharts.yaml index 1d5c61aec8..efdd44bd93 100644 --- a/plots/shap-waterfall/metadata/python/highcharts.yaml +++ b/plots/shap-waterfall/metadata/python/highcharts.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for highcharts implementation of shap-waterfall -# Auto-generated by impl-generate.yml - library: highcharts language: python specification_id: shap-waterfall created: '2026-05-07T11:47:19Z' -updated: '2026-05-07T11:47:19Z' +updated: '2026-05-07T11:53:28Z' generated_by: claude-sonnet workflow_run: 25493326647 issue: 5237 @@ -15,7 +12,234 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/shap-wate preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/shap-waterfall/python/highcharts/plot-dark.html -quality_score: null +quality_score: 86 review: - strengths: [] - weaknesses: [] + strengths: + - Native Highcharts waterfall series with isSum:true for the prediction bar — idiomatic + and correct + - Semantic Okabe-Ito color assignment (green = anchor bars, orange = positive SHAP, + blue = negative SHAP) clearly communicates the plot meaning + - Fully theme-adaptive chrome — all text, grid, and background tokens flip correctly + between light and dark without any dark-on-dark failures + - Realistic credit-scoring domain with internally consistent SHAP values that sum + to the correct prediction + - CDP screenshot technique delivers precise 4800x2700 PNG without window-size tricks + weaknesses: + - Title format must be shap-waterfall · highcharts · anyplot.ai — remove the Credit + Default Risk · prefix + - download_js() helper function violates KISS; inline the CDN download logic directly + - 'X-axis has 52 tick marks at 0.01 intervals — replace with tickInterval: 0.05 + to reduce density' + - 'Y-axis max: 0.50 wastes ~30% of canvas width; reduce to ~0.42' + - Reference line annotation font size is 16px; raise to 18px + - No subtitle or contextual framing for non-expert viewers + image_description: |- + Light render (plot-light.png): + Background: Warm off-white #FAF8F1 — correct + Chrome: Title "Credit Default Risk · shap-waterfall · highcharts · anyplot.ai" in dark ink, readable; feature labels (Credit Score, Debt-to-Income, etc.) in dark gray INK_SOFT; x-axis tick labels in dark gray at 18px; y-axis label "Probability of Default" at 22px — all readable + Data: Green #009E73 baseline bar (0 to 0.35), orange #D55E00 positive SHAP bars, blue #0072B2 negative SHAP bars, green #009E73 prediction bar (0 to 0.20); data labels beside bars in dark INK at 18px + Legibility verdict: PASS — all text readable; note: 52 x-axis ticks (0.01 intervals) are dense and right canvas has ~30% empty space (axis to 0.50, data peaks at 0.35) + + Dark render (plot-dark.png): + Background: Warm near-black #1A1A17 — correct + Chrome: Title in light cream #F0EFE8 readable against dark background; feature labels in light gray #B8B7B0; x-axis tick labels in light gray; no dark-on-dark failures detected; grid lines subtle at 10% white opacity + Data: Colors identical to light render — #009E73 baseline/prediction bars, #D55E00 positive SHAP, #0072B2 negative SHAP; data labels in light #F0EFE8 at 18px, readable against dark background + Legibility verdict: PASS — all chrome tokens flip correctly to dark-theme values; no text visibility failures + criteria_checklist: + visual_quality: + score: 27 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: All sizes explicitly set; reference line annotation labels at 16px + are below 18px minimum + - id: VQ-02 + name: No Overlap + score: 5 + max: 6 + passed: true + comment: 52 x-axis ticks at 0.01 intervals (–0.02 to 0.50) are very dense; + no true overlap at 4800px but crowded + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: All bars clearly visible, colors well-contrasted in both themes + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Okabe-Ito palette is CVD-safe; orange/blue distinction clear + - id: VQ-05 + name: Layout & Canvas + score: 3 + max: 4 + passed: true + comment: Right ~30% of canvas is empty; axis max 0.50 but data peaks near + 0.35 + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Probability of Default and Feature are descriptive + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: '#009E73 baseline/prediction, #D55E00 positive, #0072B2 negative; + correct backgrounds and chrome' + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Semantic color mapping above default; not publication-ready + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: borderWidth 0, subtle grid, generous margins, no legend + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Features sorted by |SHAP|, semantic color coding, reference lines; + lacks subtitle/context framing + spec_compliance: + score: 14 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Native Highcharts waterfall series with inverted:true for horizontal + orientation + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: 'All spec features present: ordering, cumulative stacking, color + by sign, reference lines, data labels, horizontal layout' + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X-axis probability space, y-axis features, data flows E[f(x)]=0.35 + to f(x)=0.20 + - id: SC-04 + name: Title & Legend + score: 2 + max: 3 + passed: false + comment: Title has extra Credit Default Risk · prefix; should be shap-waterfall + · highcharts · anyplot.ai + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: Both positive and negative SHAP, wide magnitude range, baseline and + prediction bars + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Credit scoring loan application; authentic features; neutral business + domain + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: BASE=0.35, FINAL=0.20; SHAP values sum correctly to -0.15 delta + code_quality: + score: 9 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 2 + max: 3 + passed: false + comment: download_js() helper function defined; KISS requires no functions/classes + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: All data hardcoded; fully deterministic + - 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: JSON placeholder approach for JS functions is pragmatic; CDP screenshot + is correct approach + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png and plot-{THEME}.html; current Highcharts + 11 API + library_mastery: + score: 8 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Native waterfall series, isSum:true, inverted:true, plotLines, dataLabels + with Highcharts.numberFormat + - id: LM-02 + name: Distinctive Features + score: 4 + max: 5 + passed: true + comment: isSum:true for running-total bar, highcharts-more.js waterfall module, + CDP captureScreenshot for exact dimensions + verdict: REJECTED +impl_tags: + dependencies: + - selenium + techniques: + - html-export + - annotations + patterns: + - data-generation + - iteration-over-groups + dataprep: + - cumulative-sum + styling: + - edge-highlighting From 221519cdde562ca59d321d9f85806885b09ce276 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 7 May 2026 12:06:19 +0000 Subject: [PATCH 3/3] chore(highcharts): update quality score 86 and review feedback for shap-waterfall --- .../metadata/python/highcharts.yaml | 153 +++++++++--------- 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/plots/shap-waterfall/metadata/python/highcharts.yaml b/plots/shap-waterfall/metadata/python/highcharts.yaml index efdd44bd93..0839827531 100644 --- a/plots/shap-waterfall/metadata/python/highcharts.yaml +++ b/plots/shap-waterfall/metadata/python/highcharts.yaml @@ -2,7 +2,7 @@ library: highcharts language: python specification_id: shap-waterfall created: '2026-05-07T11:47:19Z' -updated: '2026-05-07T11:53:28Z' +updated: '2026-05-07T12:06:19Z' generated_by: claude-sonnet workflow_run: 25493326647 issue: 5237 @@ -15,39 +15,42 @@ preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/shap-wate quality_score: 86 review: strengths: - - Native Highcharts waterfall series with isSum:true for the prediction bar — idiomatic - and correct - - Semantic Okabe-Ito color assignment (green = anchor bars, orange = positive SHAP, - blue = negative SHAP) clearly communicates the plot meaning - - Fully theme-adaptive chrome — all text, grid, and background tokens flip correctly - between light and dark without any dark-on-dark failures - - Realistic credit-scoring domain with internally consistent SHAP values that sum - to the correct prediction - - CDP screenshot technique delivers precise 4800x2700 PNG without window-size tricks + - Native Highcharts waterfall chart type with isSum flag correctly models the cumulative + SHAP attribution chain from baseline to final prediction + - Semantic Okabe-Ito color assignment (orange = positive/risk-up, blue = negative/risk-down, + green = anchors) creates an immediate, intuitive visual narrative that needs no + legend + - 'Complete theme-adaptive chrome: all INK, INK_SOFT, GRID, and PAGE_BG tokens applied + to every axis, label, and background element in both renders' + - Multi-CDN fallback download logic with retry ensures robust CI execution even + when a CDN is unreachable + - Dual plotLines (baseline dashed, prediction dotted) with branded label styling + fulfil the spec's labeled reference lines requirement weaknesses: - - Title format must be shap-waterfall · highcharts · anyplot.ai — remove the Credit - Default Risk · prefix - - download_js() helper function violates KISS; inline the CDN download logic directly - - 'X-axis has 52 tick marks at 0.01 intervals — replace with tickInterval: 0.05 - to reduce density' - - 'Y-axis max: 0.50 wastes ~30% of canvas width; reduce to ~0.42' - - Reference line annotation font size is 16px; raise to 18px - - No subtitle or contextual framing for non-expert viewers + - Title prefix 'Credit Default Risk · ' is non-standard; must be exactly 'shap-waterfall + · highcharts · anyplot.ai' + - 'yAxis.max: 0.50 wastes ~30% of canvas width to the right of the Baseline 0.35 + line; trim to ~0.40-0.42' + - Data label fontSize 18px is slightly small for a 4800x2700 canvas; 20-22px would + improve legibility + - download_js() helper function violates KISS; inline the CDN logic or simplify + to a single URL + - Raw JSON construction bypasses highcharts_core Python API; LM-01 capped at 3/5 image_description: |- Light render (plot-light.png): - Background: Warm off-white #FAF8F1 — correct - Chrome: Title "Credit Default Risk · shap-waterfall · highcharts · anyplot.ai" in dark ink, readable; feature labels (Credit Score, Debt-to-Income, etc.) in dark gray INK_SOFT; x-axis tick labels in dark gray at 18px; y-axis label "Probability of Default" at 22px — all readable - Data: Green #009E73 baseline bar (0 to 0.35), orange #D55E00 positive SHAP bars, blue #0072B2 negative SHAP bars, green #009E73 prediction bar (0 to 0.20); data labels beside bars in dark INK at 18px - Legibility verdict: PASS — all text readable; note: 52 x-axis ticks (0.01 intervals) are dense and right canvas has ~30% empty space (axis to 0.50, data peaks at 0.35) + Background: Warm off-white #FAF8F1 — correct, not pure white + Chrome: Title visible as dark ink at top-left; y-axis feature labels (Credit Score, Debt-to-Income, etc.) readable as dark text; x-axis tick labels (0.00, 0.05, ... 0.45) readable; axis titles ("Probability of Default", "Feature") clear; reference line labels ("Baseline 0.35", "Prediction 0.20") legible + Data: Baseline bar in brand green #009E73 spanning ~0 to 0.35; feature bars in orange #D55E00 (positive SHAP) and blue #0072B2 (negative SHAP); prediction bar in green #009E73 spanning ~0 to 0.20; SHAP value labels (+0.150, -0.180, etc.) shown beside each bar + Legibility verdict: PASS Dark render (plot-dark.png): - Background: Warm near-black #1A1A17 — correct - Chrome: Title in light cream #F0EFE8 readable against dark background; feature labels in light gray #B8B7B0; x-axis tick labels in light gray; no dark-on-dark failures detected; grid lines subtle at 10% white opacity - Data: Colors identical to light render — #009E73 baseline/prediction bars, #D55E00 positive SHAP, #0072B2 negative SHAP; data labels in light #F0EFE8 at 18px, readable against dark background - Legibility verdict: PASS — all chrome tokens flip correctly to dark-theme values; no text visibility failures + Background: Warm near-black #1A1A17 — correct, not pure black + Chrome: Title appears as light-colored text against dark background; y-axis feature labels readable as light gray #B8B7B0; x-axis tick labels visible as light gray; axis titles in light #F0EFE8; grid lines very subtle; reference line labels legible ("Prediction 0.20" in green, "Baseline 0.35" in soft gray); no dark-on-dark text failures detected + Data: Bar colors identical to light render — green #009E73 for baseline/prediction, orange #D55E00 for positive SHAP, blue #0072B2 for negative SHAP; all bars clearly distinguishable against dark background + Legibility verdict: PASS criteria_checklist: visual_quality: - score: 27 + score: 28 max: 30 items: - id: VQ-01 @@ -55,47 +58,47 @@ review: score: 7 max: 8 passed: true - comment: All sizes explicitly set; reference line annotation labels at 16px - are below 18px minimum + comment: All font sizes explicitly set (title 28px, axis 22px, ticks 18-20px, + data labels 18px); data labels slightly small, 20-22px would be better - id: VQ-02 name: No Overlap - score: 5 + score: 6 max: 6 passed: true - comment: 52 x-axis ticks at 0.01 intervals (–0.02 to 0.50) are very dense; - no true overlap at 4800px but crowded + comment: No text or element collisions in either render - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: All bars clearly visible, colors well-contrasted in both themes + comment: All bars sized and padded well, clearly distinct in both themes - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: Okabe-Ito palette is CVD-safe; orange/blue distinction clear + comment: Orange/blue are high-contrast and CVD-safe; green reference bars + unambiguous - id: VQ-05 name: Layout & Canvas score: 3 max: 4 passed: true - comment: Right ~30% of canvas is empty; axis max 0.50 but data peaks near - 0.35 + comment: 'Chart fills canvas well but yAxis.max: 0.50 extends 15+ points beyond + Baseline 0.35, wasting right-side canvas' - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Probability of Default and Feature are descriptive + comment: Probability of Default (x-axis) and Feature (y-axis) are descriptive - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true - comment: '#009E73 baseline/prediction, #D55E00 positive, #0072B2 negative; - correct backgrounds and chrome' + comment: 'Okabe-Ito positions 1-3 used correctly; backgrounds #FAF8F1/#1A1A17; + chrome tokens applied to all elements' design_excellence: score: 13 max: 20 @@ -105,20 +108,22 @@ review: score: 5 max: 8 passed: true - comment: Semantic color mapping above default; not publication-ready + comment: 'Above defaults: semantic color coding for direction, brand green + for reference bars, clean typography; not yet publication-level' - id: DE-02 name: Visual Refinement score: 4 max: 6 passed: true - comment: borderWidth 0, subtle grid, generous margins, no legend + comment: 'borderWidth: 0 removes bar outlines, legend/tooltip disabled, subtle + grid; top/right axes still present' - id: DE-03 name: Data Storytelling score: 4 max: 6 passed: true - comment: Features sorted by |SHAP|, semantic color coding, reference lines; - lacks subtitle/context framing + comment: Color instantly signals contribution direction; magnitude-ordered + features guide the eye; clear flow from baseline to prediction spec_compliance: score: 14 max: 15 @@ -128,29 +133,30 @@ review: score: 5 max: 5 passed: true - comment: Native Highcharts waterfall series with inverted:true for horizontal - orientation + comment: 'Native Highcharts waterfall type with inverted: true — correct horizontal + waterfall' - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: 'All spec features present: ordering, cumulative stacking, color - by sign, reference lines, data labels, horizontal layout' + comment: Cumulative bars, positive/negative color coding, base value bar, + prediction bar, numeric SHAP labels, horizontal layout, reference lines, + magnitude-sorted features, native connector lines - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: X-axis probability space, y-axis features, data flows E[f(x)]=0.35 - to f(x)=0.20 + comment: Features on y-axis, probability of default on x-axis, all 10 features + shown - id: SC-04 name: Title & Legend score: 2 max: 3 passed: false - comment: Title has extra Credit Default Risk · prefix; should be shap-waterfall - · highcharts · anyplot.ai + comment: Title has non-standard prefix 'Credit Default Risk · '; required + format is 'shap-waterfall · highcharts · anyplot.ai' data_quality: score: 15 max: 15 @@ -160,21 +166,22 @@ review: score: 6 max: 6 passed: true - comment: Both positive and negative SHAP, wide magnitude range, baseline and - prediction bars + comment: Both positive and negative contributors shown; baseline and prediction + bookend bars complete the picture - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Credit scoring loan application; authentic features; neutral business - domain + comment: Credit default risk model for single loan application; all feature + names domain-appropriate; neutral business scenario - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: BASE=0.35, FINAL=0.20; SHAP values sum correctly to -0.15 delta + comment: Base value 0.35, final prediction 0.20, SHAP values ±0.18 are all + realistic for probability-scale credit model code_quality: score: 9 max: 10 @@ -184,7 +191,8 @@ review: score: 2 max: 3 passed: false - comment: download_js() helper function defined; KISS requires no functions/classes + comment: download_js() helper function defined; KISS requires flat script + with no functions/classes - id: CQ-02 name: Reproducibility score: 2 @@ -196,50 +204,47 @@ review: score: 2 max: 2 passed: true - comment: All imports used + comment: All 9 imports are used - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: JSON placeholder approach for JS functions is pragmatic; CDP screenshot - is correct approach + comment: JS formatter injection via string-replace is pragmatic; multi-CDN + fallback justified; no fake UI - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot-{THEME}.png and plot-{THEME}.html; current Highcharts - 11 API + comment: Saves plot-{THEME}.png and plot-{THEME}.html correctly library_mastery: - score: 8 + score: 7 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 4 + score: 3 max: 5 passed: true - comment: Native waterfall series, isSum:true, inverted:true, plotLines, dataLabels - with Highcharts.numberFormat + comment: Uses native Highcharts waterfall type correctly but bypasses highcharts_core + Python API in favour of raw JSON construction - id: LM-02 name: Distinctive Features score: 4 max: 5 passed: true - comment: isSum:true for running-total bar, highcharts-more.js waterfall module, - CDP captureScreenshot for exact dimensions - verdict: REJECTED + comment: 'isSum: true for prediction total bar, inverted: true for horizontal + orientation, plotLines with styled labels, CDP-based full-resolution screenshot + — all Highcharts-distinctive' + verdict: APPROVED impl_tags: dependencies: - selenium techniques: - html-export - - annotations patterns: - data-generation - iteration-over-groups - dataprep: - - cumulative-sum - styling: - - edge-highlighting + dataprep: [] + styling: []