From 3a10bfb547882ad740f3b0b7d9283e1cc6fa5565 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 5 Sep 2026 12:23:50 +0000 Subject: [PATCH 1/5] feat(chartjs): implement residual-plot --- .../implementations/javascript/chartjs.js | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 plots/residual-plot/implementations/javascript/chartjs.js diff --git a/plots/residual-plot/implementations/javascript/chartjs.js b/plots/residual-plot/implementations/javascript/chartjs.js new file mode 100644 index 00000000000..202fa8ef220 --- /dev/null +++ b/plots/residual-plot/implementations/javascript/chartjs.js @@ -0,0 +1,157 @@ +// anyplot.ai +// residual-plot: Residual Plot +// Library: chartjs 4.4.7 | JavaScript 22 +// Quality: pending | Created: 2026-09-05 + +const t = window.ANYPLOT_TOKENS; + +// --- Data (in-memory, deterministic LCG) ------------------------------------ +// Simulated linear-regression diagnostics: fitted house-price predictions +// (in $1000s) vs. residuals, with mild heteroscedasticity (variance grows +// with fitted value) so the fan-out pattern is visible. +let seed = 42; +function lcg() { + seed = (seed * 1664525 + 1013904223) % 4294967296; + return seed / 4294967296; +} +function gaussian() { + const u1 = 1 - lcg(); + const u2 = lcg(); + return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); +} + +const n = 220; +const fitted = []; +const residuals = []; +for (let i = 0; i < n; i++) { + const value = 150 + lcg() * 450; // fitted price, $150k-$600k + const noiseScale = 8 + (value - 150) * 0.05; // heteroscedastic spread + fitted.push(value); + residuals.push(gaussian() * noiseScale); +} + +const mean = residuals.reduce((a, b) => a + b, 0) / n; +const variance = residuals.reduce((a, b) => a + (b - mean) ** 2, 0) / n; +const stdDev = Math.sqrt(variance); +const threshold = 2 * stdDev; + +const normalPoints = []; +const outlierPoints = []; +for (let i = 0; i < n; i++) { + const point = { x: fitted[i], y: residuals[i] }; + if (Math.abs(residuals[i]) > threshold) { + outlierPoints.push(point); + } else { + normalPoints.push(point); + } +} + +const xMin = Math.min(...fitted); +const xMax = Math.max(...fitted); + +// --- Mount ------------------------------------------------------------------- +const canvas = document.createElement("canvas"); +document.getElementById("container").appendChild(canvas); + +// --- Chart --------------------------------------------------------------------- +new Chart(canvas, { + type: "scatter", + data: { + datasets: [ + { + label: "±2σ band", + data: [ + { x: xMin, y: threshold }, + { x: xMax, y: threshold }, + ], + showLine: true, + borderColor: t.amber, + borderWidth: 1.5, + borderDash: [6, 4], + pointRadius: 0, + fill: "+2", + backgroundColor: + t.pageBg === "#1A1A17" ? "rgba(240,239,232,0.06)" : "rgba(26,26,23,0.04)", + }, + { + label: "Zero reference", + data: [ + { x: xMin, y: 0 }, + { x: xMax, y: 0 }, + ], + showLine: true, + borderColor: t.ink, + borderWidth: 2, + pointRadius: 0, + }, + { + label: "−2σ band", + data: [ + { x: xMin, y: -threshold }, + { x: xMax, y: -threshold }, + ], + showLine: true, + borderColor: t.amber, + borderWidth: 1.5, + borderDash: [6, 4], + pointRadius: 0, + }, + { + label: "Residuals", + data: normalPoints, + backgroundColor: t.palette[0], + borderColor: t.pageBg, + borderWidth: 1, + pointRadius: 6, + pointHoverRadius: 7, + }, + { + label: "Outliers (>2σ)", + data: outlierPoints, + backgroundColor: t.palette[4], + borderColor: t.pageBg, + borderWidth: 1, + pointRadius: 7, + pointStyle: "triangle", + pointHoverRadius: 8, + }, + ], + }, + options: { + responsive: true, + maintainAspectRatio: false, + animation: false, + plugins: { + title: { + display: true, + text: "residual-plot · javascript · chartjs · anyplot.ai", + color: t.ink, + font: { size: 22, weight: "500" }, + padding: { bottom: 20 }, + }, + legend: { + labels: { + color: t.inkSoft, + font: { size: 14 }, + filter: (item) => item.text !== "±2σ band" && item.text !== "−2σ band", + }, + }, + tooltip: { enabled: false }, + }, + scales: { + x: { + type: "linear", + title: { display: true, text: "Fitted Value ($1,000s)", color: t.ink, font: { size: 16 } }, + ticks: { color: t.inkSoft, font: { size: 14 } }, + grid: { color: t.grid }, + border: { color: t.inkSoft }, + }, + y: { + title: { display: true, text: "Residual ($1,000s)", color: t.ink, font: { size: 16 } }, + ticks: { color: t.inkSoft, font: { size: 14 } }, + grid: { color: t.grid }, + border: { color: t.inkSoft }, + }, + }, + }, +}); From 116bd1e8321e9e9d2f8cfbbf782ab31af42bb6d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 5 Sep 2026 12:23:57 +0000 Subject: [PATCH 2/5] chore(chartjs): add metadata for residual-plot --- .../metadata/javascript/chartjs.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 plots/residual-plot/metadata/javascript/chartjs.yaml diff --git a/plots/residual-plot/metadata/javascript/chartjs.yaml b/plots/residual-plot/metadata/javascript/chartjs.yaml new file mode 100644 index 00000000000..734702d5bbc --- /dev/null +++ b/plots/residual-plot/metadata/javascript/chartjs.yaml @@ -0,0 +1,21 @@ +# Per-library metadata for chartjs implementation of residual-plot +# Auto-generated by impl-generate.yml + +library: chartjs +language: javascript +specification_id: residual-plot +created: '2026-09-05T12:23:57Z' +updated: '2026-09-05T12:23:57Z' +generated_by: claude-sonnet +workflow_run: 33965741710 +issue: 2332 +language_version: 22.23.2 +library_version: 4.4.7 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-dark.html +quality_score: null +review: + strengths: [] + weaknesses: [] From 4c7d639028e356136fec388244392f8b8efe1ecc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 5 Sep 2026 12:28:00 +0000 Subject: [PATCH 3/5] chore(chartjs): update quality score 86 and review feedback for residual-plot --- .../implementations/javascript/chartjs.js | 4 +- .../metadata/javascript/chartjs.yaml | 229 +++++++++++++++++- 2 files changed, 224 insertions(+), 9 deletions(-) diff --git a/plots/residual-plot/implementations/javascript/chartjs.js b/plots/residual-plot/implementations/javascript/chartjs.js index 202fa8ef220..9b857a9a021 100644 --- a/plots/residual-plot/implementations/javascript/chartjs.js +++ b/plots/residual-plot/implementations/javascript/chartjs.js @@ -1,7 +1,7 @@ // anyplot.ai // residual-plot: Residual Plot -// Library: chartjs 4.4.7 | JavaScript 22 -// Quality: pending | Created: 2026-09-05 +// Library: chartjs 4.4.7 | JavaScript 22.23.2 +// Quality: 86/100 | Created: 2026-09-05 const t = window.ANYPLOT_TOKENS; diff --git a/plots/residual-plot/metadata/javascript/chartjs.yaml b/plots/residual-plot/metadata/javascript/chartjs.yaml index 734702d5bbc..f70333a94de 100644 --- a/plots/residual-plot/metadata/javascript/chartjs.yaml +++ b/plots/residual-plot/metadata/javascript/chartjs.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for chartjs implementation of residual-plot -# Auto-generated by impl-generate.yml - library: chartjs language: javascript specification_id: residual-plot created: '2026-09-05T12:23:57Z' -updated: '2026-09-05T12:23:57Z' +updated: '2026-09-05T12:28:00Z' generated_by: claude-sonnet workflow_run: 33965741710 issue: 2332 @@ -15,7 +12,225 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/residual- preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-dark.html -quality_score: null +quality_score: 86 review: - strengths: [] - weaknesses: [] + strengths: + - 'Correct semantic palette use: brand green for the main residual series, palette[4] + matte red AND a triangle marker shape for outliers (redundant, CVD-safe encoding)' + - '±2σ threshold bands implemented via Chart.js''s relative fill: "+2" index trick, + with the legend filter callback cleanly hiding the two band traces so only meaningful + entries show' + - Deterministic LCG-seeded data with realistic heteroscedastic noise (variance grows + with fitted value) — a textbook regression-diagnostics pattern + - Theme-adaptive chrome (zero-reference line, axis borders, tick/text colors) consistently + sourced from ANYPLOT_TOKENS in both themes + weaknesses: + - No alpha transparency on the residual markers despite the spec's guidance to use + alpha for overlapping points — a few clusters (near fitted≈250, fitted≈560) have + touching/overlapping circles + - No optional LOWESS/kernel smoothing trend line — would add diagnostic value for + detecting non-linearity, though this is explicitly optional in the spec + - Visual refinement is solid but generic — no standout design flourish beyond the + functional band/outlier treatment + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1), matches spec target. + Chrome: Title "residual-plot · javascript · chartjs · anyplot.ai" and legend ("Zero reference", "Residuals", "Outliers (>2σ)") render in dark ink; axis titles ("Fitted Value ($1,000s)", "Residual ($1,000s)") and tick labels are dark/secondary-tone and clearly legible. + Data: ~220 green (#009E73) circular points, solid black zero-reference line, amber dashed ±2σ bands with a faint shaded interior, ~11 red (#AE3030) triangular outlier points beyond the bands. + Legibility verdict: PASS + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17), matches spec target. + Chrome: Title and legend render in light/white ink; axis titles and tick labels in a lighter secondary tone. Zero-reference line correctly flips to a light/white stroke (theme-adaptive ink token). No dark-on-dark issues found. + Data: Brand green circles and matte-red triangle outliers are pixel-identical in color to the light render — confirmed only chrome (background, text, zero-reference line color) flips between themes, not data colors. + Legibility verdict: PASS + criteria_checklist: + visual_quality: + score: 27 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: All text readable in both themes at appropriate sizes; slightly conservative + sizing leaves headroom + - id: VQ-02 + name: No Overlap + score: 5 + max: 6 + passed: true + comment: A few marker clusters (near fitted≈250, fitted≈560) touch/overlap + slightly + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Marker size reasonable for n=220, but no alpha used for overlapping + points despite spec guidance + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Outliers use both color (matte red) and shape (triangle) — CVD-safe + redundant encoding + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Clean proportions, nothing clipped, canvas-gate passed + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Descriptive axis titles with units + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: Brand green first series, semantic-red outliers, amber threshold + bands, correct theme backgrounds, identical data colors across themes + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Thoughtful touches (relative-fill band, filtered legend) but fairly + standard composition + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: L-shaped axis borders, subtle grid; no standout refinement + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Outlier highlighting and shaded ±2σ band create a clear focal hierarchy + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Correct residual (scatter) plot + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Zero-reference line, ±2σ bands, outlier color-coding all present + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X = fitted value, Y = residual (y_true - y_pred), full range shown + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches mandated format; legend labels clear and filtered correctly + data_quality: + score: 14 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 5 + max: 6 + passed: true + comment: Covers all required features; missing advisory alpha treatment for + overlap + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Plausible house-price regression scenario with realistic heteroscedastic + noise + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Sensible value ranges for the domain + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Flat script; tiny RNG helpers are the library-recommended deterministic-RNG + pattern + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Fixed-seed LCG, fully deterministic + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: No stray imports; Chart global used directly + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Appropriate complexity, no fake UI/interactivity + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Correct mount-node contract, animation disabled, current API + library_mastery: + score: 7 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Good use of mixed scatter+line datasets and recommended patterns + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Relative dataset fill index technique and legend filter callback + beyond generic usage + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - custom-legend + - layer-composition + patterns: + - data-generation + dataprep: [] + styling: + - alpha-blending From fcca2e7d53cf07216eca48314f247cc00277b15f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 5 Sep 2026 12:32:21 +0000 Subject: [PATCH 4/5] fix(chartjs): address review feedback for residual-plot Attempt 1/4 - fixes based on AI review --- .../implementations/javascript/chartjs.js | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/plots/residual-plot/implementations/javascript/chartjs.js b/plots/residual-plot/implementations/javascript/chartjs.js index 9b857a9a021..0ea6e138241 100644 --- a/plots/residual-plot/implementations/javascript/chartjs.js +++ b/plots/residual-plot/implementations/javascript/chartjs.js @@ -19,6 +19,13 @@ function gaussian() { const u2 = lcg(); return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); } +function hexToRgba(hex, alpha) { + const h = hex.replace("#", ""); + const r = parseInt(h.substring(0, 2), 16); + const g = parseInt(h.substring(2, 4), 16); + const b = parseInt(h.substring(4, 6), 16); + return `rgba(${r}, ${g}, ${b}, ${alpha})`; +} const n = 220; const fitted = []; @@ -49,6 +56,20 @@ for (let i = 0; i < n; i++) { const xMin = Math.min(...fitted); const xMax = Math.max(...fitted); +// Rolling-mean smoothing trend (sorted by fitted value) to surface any +// residual non-linearity — optional per spec, adds diagnostic value. +const sortedIdx = fitted.map((_, i) => i).sort((a, b) => fitted[a] - fitted[b]); +const sortedX = sortedIdx.map((i) => fitted[i]); +const sortedY = sortedIdx.map((i) => residuals[i]); +const windowSize = Math.max(15, Math.round(n * 0.12)); +const trendPoints = sortedX.map((x, i) => { + const lo = Math.max(0, i - Math.floor(windowSize / 2)); + const hi = Math.min(n, i + Math.ceil(windowSize / 2)); + const slice = sortedY.slice(lo, hi); + const avg = slice.reduce((a, b) => a + b, 0) / slice.length; + return { x, y: avg }; +}); + // --- Mount ------------------------------------------------------------------- const canvas = document.createElement("canvas"); document.getElementById("container").appendChild(canvas); @@ -99,12 +120,23 @@ new Chart(canvas, { { label: "Residuals", data: normalPoints, - backgroundColor: t.palette[0], + backgroundColor: hexToRgba(t.palette[0], 0.7), borderColor: t.pageBg, borderWidth: 1, pointRadius: 6, pointHoverRadius: 7, }, + { + label: "Smoothed trend", + data: trendPoints, + showLine: true, + borderColor: t.palette[1], + borderWidth: 2, + borderDash: [3, 3], + pointRadius: 0, + fill: false, + tension: 0.3, + }, { label: "Outliers (>2σ)", data: outlierPoints, From 5dee9faba79bd6bbbe9dc05784dd26a92e178a58 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 5 Sep 2026 12:37:48 +0000 Subject: [PATCH 5/5] chore(chartjs): update quality score 94 and review feedback for residual-plot --- .../implementations/javascript/chartjs.js | 2 +- .../metadata/javascript/chartjs.yaml | 144 ++++++++++-------- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/plots/residual-plot/implementations/javascript/chartjs.js b/plots/residual-plot/implementations/javascript/chartjs.js index 0ea6e138241..f03b22137b6 100644 --- a/plots/residual-plot/implementations/javascript/chartjs.js +++ b/plots/residual-plot/implementations/javascript/chartjs.js @@ -1,7 +1,7 @@ // anyplot.ai // residual-plot: Residual Plot // Library: chartjs 4.4.7 | JavaScript 22.23.2 -// Quality: 86/100 | Created: 2026-09-05 +// Quality: 94/100 | Created: 2026-09-05 const t = window.ANYPLOT_TOKENS; diff --git a/plots/residual-plot/metadata/javascript/chartjs.yaml b/plots/residual-plot/metadata/javascript/chartjs.yaml index f70333a94de..9cf786bb153 100644 --- a/plots/residual-plot/metadata/javascript/chartjs.yaml +++ b/plots/residual-plot/metadata/javascript/chartjs.yaml @@ -2,7 +2,7 @@ library: chartjs language: javascript specification_id: residual-plot created: '2026-09-05T12:23:57Z' -updated: '2026-09-05T12:28:00Z' +updated: '2026-09-05T12:37:47Z' generated_by: claude-sonnet workflow_run: 33965741710 issue: 2332 @@ -12,77 +12,83 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/residual- preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/residual-plot/javascript/chartjs/plot-dark.html -quality_score: 86 +quality_score: 94 review: strengths: - - 'Correct semantic palette use: brand green for the main residual series, palette[4] - matte red AND a triangle marker shape for outliers (redundant, CVD-safe encoding)' - - '±2σ threshold bands implemented via Chart.js''s relative fill: "+2" index trick, - with the legend filter callback cleanly hiding the two band traces so only meaningful - entries show' - - Deterministic LCG-seeded data with realistic heteroscedastic noise (variance grows - with fitted value) — a textbook regression-diagnostics pattern - - Theme-adaptive chrome (zero-reference line, axis borders, tick/text colors) consistently - sourced from ANYPLOT_TOKENS in both themes + - 'Addressed both attempt-1 weaknesses directly: added alpha transparency (rgba + palette[0] at 0.7) on residual markers to soften overlapping clusters, and added + a rolling-mean smoothed trend line to surface non-linear patterns in the residuals' + - 'Correct semantic palette usage: brand green (palette[0]) for the main residual + series, matte-red (palette[4]) AND a triangle marker shape for outliers (redundant, + CVD-safe encoding), amber anchor for the ±2σ threshold lines' + - 'Theme-adaptive ±2σ band shading: the relative-fill overlay tint flips (dark tint + on light bg, light tint on dark bg) so the shaded region stays subtly visible + in both themes instead of a single hardcoded color' + - Deterministic LCG + Box-Muller-style gaussian data generation with realistic heteroscedastic + house-price regression scenario (variance grows with fitted value) + - 'Idiomatic Chart.js technique mix: relative `fill: "+2"` dataset-index trick for + the band, `legend.filter` callback to suppress duplicate band-line legend entries, + mixed scatter+line datasets' weaknesses: - - No alpha transparency on the residual markers despite the spec's guidance to use - alpha for overlapping points — a few clusters (near fitted≈250, fitted≈560) have - touching/overlapping circles - - No optional LOWESS/kernel smoothing trend line — would add diagnostic value for - detecting non-linearity, though this is explicitly optional in the spec - - Visual refinement is solid but generic — no standout design flourish beyond the - functional band/outlier treatment + - A few marker clusters (e.g. near fitted≈250, fitted≈560) still touch slightly + even with alpha=0.7 — a marginally lower alpha or smaller point radius in dense + regions would separate them further + - The two ±2σ threshold lines are filtered out of the legend entirely rather than + merged into one labeled entry — a first-time viewer has no textual cue for what + the dashed amber lines represent + - Visual refinement is professional but not distinctive beyond the functional band/outlier/trend + treatments — no standout design flourish beyond what's functionally required image_description: |- Light render (plot-light.png): - Background: Warm off-white (#FAF8F1), matches spec target. - Chrome: Title "residual-plot · javascript · chartjs · anyplot.ai" and legend ("Zero reference", "Residuals", "Outliers (>2σ)") render in dark ink; axis titles ("Fitted Value ($1,000s)", "Residual ($1,000s)") and tick labels are dark/secondary-tone and clearly legible. - Data: ~220 green (#009E73) circular points, solid black zero-reference line, amber dashed ±2σ bands with a faint shaded interior, ~11 red (#AE3030) triangular outlier points beyond the bands. - Legibility verdict: PASS + Background: warm off-white, matches #FAF8F1 — not pure white, not dark. + Chrome: Title "residual-plot · javascript · chartjs · anyplot.ai" in dark ink, comfortably sized, not overflowing. Legend row below title (Zero reference / Residuals / Smoothed trend / Outliers (>2σ)) in dark text. Axis titles "Fitted Value ($1,000s)" and "Residual ($1,000s)" in dark ink with units. Tick labels in a softer dark grey. Grid lines light grey, subtle but visible. All fully readable. + Data: ~220 green (#009E73) circular residual points at ~0.7 alpha spread over Fitted Value ($150k-$600k) vs Residual (-80 to +80), a solid black zero-reference line, two amber dashed ±2σ lines with a faint shaded band between them, a light-purple dotted rolling-mean smoothed trend line, and ~11 matte-red triangular outlier points beyond the bands. First series correctly uses brand green. + Legibility verdict: PASS. Dark render (plot-dark.png): - Background: Warm near-black (#1A1A17), matches spec target. - Chrome: Title and legend render in light/white ink; axis titles and tick labels in a lighter secondary tone. Zero-reference line correctly flips to a light/white stroke (theme-adaptive ink token). No dark-on-dark issues found. - Data: Brand green circles and matte-red triangle outliers are pixel-identical in color to the light render — confirmed only chrome (background, text, zero-reference line color) flips between themes, not data colors. - Legibility verdict: PASS + Background: warm near-black, matches #1A1A17 — not pure black, not light. + Chrome: Same title and legend, now rendered in light/white ink, fully readable against the dark surface. Axis titles and tick labels in light tones, no dark-on-dark issues anywhere. Zero-reference line correctly flips to a light/white stroke (theme-adaptive ink token). Grid lines subtle dark-grey, still visible. + Data: Green circles, amber dashed bands, purple dotted trend line, and matte-red outlier triangles are pixel-identical in color and position to the light render — confirms only chrome flipped, not data colors. + Legibility verdict: PASS. criteria_checklist: visual_quality: - score: 27 + score: 29 max: 30 items: - id: VQ-01 name: Text Legibility - score: 7 + score: 8 max: 8 passed: true - comment: All text readable in both themes at appropriate sizes; slightly conservative - sizing leaves headroom + comment: All text readable at appropriate sizes in both themes, no dark-on-dark + or light-on-light failures - id: VQ-02 name: No Overlap score: 5 max: 6 passed: true - comment: A few marker clusters (near fitted≈250, fitted≈560) touch/overlap - slightly + comment: Alpha transparency now softens clusters, but a few points near fitted≈250 + and fitted≈560 still touch slightly - id: VQ-03 name: Element Visibility - score: 5 + score: 6 max: 6 passed: true - comment: Marker size reasonable for n=220, but no alpha used for overlapping - points despite spec guidance + comment: Alpha=0.7 and appropriate marker size added for n=220, addressing + the attempt-1 finding - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: Outliers use both color (matte red) and shape (triangle) — CVD-safe - redundant encoding + comment: Outliers use both matte-red color and triangle shape — CVD-safe redundant + encoding - id: VQ-05 name: Layout & Canvas score: 4 max: 4 passed: true - comment: Clean proportions, nothing clipped, canvas-gate passed + comment: Clean proportions, nothing clipped, canvas-gate not triggered - id: VQ-06 name: Axis Labels & Title score: 2 @@ -94,31 +100,33 @@ review: score: 2 max: 2 passed: true - comment: Brand green first series, semantic-red outliers, amber threshold - bands, correct theme backgrounds, identical data colors across themes + comment: Brand green first series, semantic red for outliers, amber anchor + for threshold, correct theme backgrounds, identical data colors across themes design_excellence: - score: 13 + score: 16 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 5 + score: 7 max: 8 passed: true - comment: Thoughtful touches (relative-fill band, filtered legend) but fairly - standard composition + comment: Theme-adaptive band shading, semantic color use, relative-fill technique, + and new trend line show real design thought - id: DE-02 name: Visual Refinement score: 4 max: 6 passed: true - comment: L-shaped axis borders, subtle grid; no standout refinement + comment: Subtle grid, L-shaped axis borders, alpha blending; solid but not + standout - id: DE-03 name: Data Storytelling - score: 4 + score: 5 max: 6 passed: true - comment: Outlier highlighting and shaded ±2σ band create a clear focal hierarchy + comment: Outlier highlighting, shaded threshold band, and new smoothed trend + line create a clear diagnostic focal hierarchy spec_compliance: score: 15 max: 15 @@ -128,13 +136,14 @@ review: score: 5 max: 5 passed: true - comment: Correct residual (scatter) plot + comment: Correct residual scatter plot - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Zero-reference line, ±2σ bands, outlier color-coding all present + comment: Zero-reference line, ±2σ bands, outlier color-coding, alpha, and + smoothing trend all present - id: SC-03 name: Data Mapping score: 3 @@ -146,18 +155,19 @@ review: score: 3 max: 3 passed: true - comment: Title matches mandated format; legend labels clear and filtered correctly + comment: Title matches mandated format; legend labels are clear and correctly + deduplicated data_quality: - score: 14 + score: 15 max: 15 items: - id: DQ-01 name: Feature Coverage - score: 5 + score: 6 max: 6 passed: true - comment: Covers all required features; missing advisory alpha treatment for - overlap + comment: Now covers all spec-listed features including the two previously-missing + optional ones (alpha, smoothing trend) - id: DQ-02 name: Realistic Context score: 5 @@ -180,8 +190,7 @@ review: score: 3 max: 3 passed: true - comment: Flat script; tiny RNG helpers are the library-recommended deterministic-RNG - pattern + comment: Flat script; small RNG/rgba helpers are appropriate, not over-abstracted - id: CQ-02 name: Reproducibility score: 2 @@ -193,7 +202,7 @@ review: score: 2 max: 2 passed: true - comment: No stray imports; Chart global used directly + comment: No stray imports, Chart global used directly - id: CQ-04 name: Code Elegance score: 2 @@ -205,9 +214,10 @@ review: score: 1 max: 1 passed: true - comment: Correct mount-node contract, animation disabled, current API + comment: 'Correct mount-node contract, animation: false, current scatter/fill + API' library_mastery: - score: 7 + score: 9 max: 10 items: - id: LM-01 @@ -215,22 +225,26 @@ review: score: 4 max: 5 passed: true - comment: Good use of mixed scatter+line datasets and recommended patterns + comment: Good use of mixed scatter+line datasets and Chart.js recommended + patterns - id: LM-02 name: Distinctive Features - score: 3 + score: 5 max: 5 passed: true - comment: Relative dataset fill index technique and legend filter callback - beyond generic usage + comment: 'Relative fill: ''+2'' index trick, theme-adaptive band tint, legend + filter callback, and rolling-window trend computation go well beyond generic + usage' verdict: APPROVED impl_tags: dependencies: [] techniques: - - custom-legend - layer-composition + - custom-legend patterns: - data-generation - dataprep: [] + dataprep: + - rolling-window styling: - alpha-blending + - edge-highlighting