From 99e866b7f711e64f74889b8d4ec316c1d4718c17 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Jul 2026 16:17:11 +0000 Subject: [PATCH 1/5] feat(highcharts): implement radar-basic --- .../implementations/javascript/highcharts.js | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 plots/radar-basic/implementations/javascript/highcharts.js diff --git a/plots/radar-basic/implementations/javascript/highcharts.js b/plots/radar-basic/implementations/javascript/highcharts.js new file mode 100644 index 0000000000..d67f64678e --- /dev/null +++ b/plots/radar-basic/implementations/javascript/highcharts.js @@ -0,0 +1,163 @@ +// anyplot.ai +// radar-basic: Basic Radar Chart +// Library: Highcharts 12.6.0 | Node 22 +// License: Highcharts — commercial license, free for non-commercial use (highcharts.com/license) +// Quality: pending | Created: 2026-07-24 +//# anyplot-orientation: square + +// Only the core `highcharts` bundle is loaded (no highcharts-more), so the +// native polar/radar series type isn't available. Instead we project each +// axis's polar coordinate to Cartesian ourselves and draw the grid, spokes, +// labels, and data polygons with the core SVG renderer — same technique the +// gauge-basic implementation uses for its needle overlay. +const t = window.ANYPLOT_TOKENS; + +// --- Data (Employee performance review, two review cycles) ----------------- +const categories = [ + "Communication", + "Technical Skills", + "Teamwork", + "Leadership", + "Problem Solving", + "Adaptability", +]; +const series = [ + { name: "Q3 Review", color: t.palette[0], values: [78, 85, 90, 65, 72, 80] }, + { name: "Q4 Review", color: t.palette[1], values: [88, 82, 92, 75, 85, 78] }, +]; +const MAX_VALUE = 100; +const RING_LEVELS = [20, 40, 60, 80, 100]; +const n = categories.length; + +const TITLE = "radar-basic · javascript · highcharts · anyplot.ai"; +const titleFs = Math.max(15, Math.round(22 * Math.min(1, 67 / TITLE.length))) + "px"; + +// --- Chart (empty core chart used as a canvas for the renderer overlay) ---- +const chart = Highcharts.chart("container", { + chart: { + backgroundColor: "transparent", + animation: false, + style: { fontFamily: "inherit" }, + margin: [110, 80, 130, 80], + }, + credits: { enabled: false }, + title: { + text: TITLE, + style: { color: t.ink, fontSize: titleFs, fontWeight: "600" }, + }, + xAxis: { visible: false, gridLineWidth: 0, lineWidth: 0, tickLength: 0 }, + yAxis: { visible: false, gridLineWidth: 0, lineWidth: 0, tickLength: 0 }, + legend: { enabled: false }, + tooltip: { enabled: false }, + plotOptions: { series: { animation: false } }, + series: [], +}); + +// --- Geometry ---------------------------------------------------------------- +const cx = chart.plotLeft + chart.plotWidth / 2; +const cy = chart.plotTop + chart.plotHeight / 2; +const outerR = Math.min(chart.plotWidth, chart.plotHeight) / 2 - 70; + +// angle 0 points straight up, axes proceed clockwise +const angleOf = (i) => -Math.PI / 2 + i * ((2 * Math.PI) / n); +const pointAt = (i, radiusFrac) => { + const angle = angleOf(i); + return [cx + outerR * radiusFrac * Math.cos(angle), cy + outerR * radiusFrac * Math.sin(angle)]; +}; + +// --- Grid rings -------------------------------------------------------------- +RING_LEVELS.forEach((level) => { + const radiusFrac = level / MAX_VALUE; + const path = ["M"]; + for (let i = 0; i < n; i += 1) { + const [x, y] = pointAt(i, radiusFrac); + path.push(...(i === 0 ? [x, y] : ["L", x, y])); + } + path.push("Z"); + chart.renderer + .path(path) + .attr({ stroke: t.grid, "stroke-width": 1, fill: "none", zIndex: 1 }) + .add(); +}); + +// --- Spokes + axis labels ----------------------------------------------------- +categories.forEach((label, i) => { + const [ox, oy] = pointAt(i, 1); + chart.renderer + .path(["M", cx, cy, "L", ox, oy]) + .attr({ stroke: t.inkSoft, "stroke-width": 1, zIndex: 1 }) + .add(); + + const angle = angleOf(i); + const cos = Math.cos(angle); + const sin = Math.sin(angle); + const [lx, ly] = pointAt(i, 1 + 26 / outerR); + const align = cos > 0.3 ? "left" : cos < -0.3 ? "right" : "center"; + chart.renderer + .text(label, lx, ly + sin * 6 + 5) + .attr({ align, zIndex: 5 }) + .css({ fontSize: "15px", fontWeight: "600", color: t.ink, fontFamily: "inherit" }) + .add(); +}); + +// --- Ring scale labels (along the top spoke) --------------------------------- +RING_LEVELS.forEach((level) => { + const [, ly] = pointAt(0, level / MAX_VALUE); + chart.renderer + .text(String(level), cx + 8, ly + 4) + .attr({ align: "left", zIndex: 4 }) + .css({ fontSize: "12px", color: t.inkSoft, fontFamily: "inherit" }) + .add(); +}); + +// --- Data polygons ------------------------------------------------------------- +series.forEach((s) => { + const vertices = s.values.map((value, i) => pointAt(i, value / MAX_VALUE)); + const path = ["M"]; + vertices.forEach(([x, y], i) => path.push(...(i === 0 ? [x, y] : ["L", x, y]))); + path.push("Z"); + + chart.renderer + .path(path) + .attr({ + fill: s.color, + "fill-opacity": 0.22, + stroke: s.color, + "stroke-width": 2.5, + "stroke-linejoin": "round", + zIndex: 3, + }) + .add(); + + vertices.forEach(([x, y]) => { + chart.renderer + .circle(x, y, 6) + .attr({ fill: s.color, stroke: t.pageBg, "stroke-width": 1.5, zIndex: 4 }) + .add(); + }); +}); + +// --- Legend --------------------------------------------------------------- +const chipSize = 14; +const gap = 28; +const legendFs = 15; +const chipTextWidths = series.map((s) => s.name.length * 8.2); +const legendWidth = series.reduce( + (sum, _s, i) => sum + chipSize + 10 + chipTextWidths[i] + (i < series.length - 1 ? gap : 0), + 0 +); +let legendX = cx - legendWidth / 2; +const legendY = chart.plotTop + chart.plotHeight + 60; + +series.forEach((s, i) => { + chart.renderer + .rect(legendX, legendY - chipSize / 2, chipSize, chipSize, 3) + .attr({ fill: s.color, zIndex: 5 }) + .add(); + chart.renderer + .text(s.name, legendX + chipSize + 10, legendY + chipSize / 2 - 2) + .attr({ align: "left", zIndex: 5 }) + .css({ fontSize: `${legendFs}px`, color: t.ink, fontFamily: "inherit" }) + .add(); + legendX += chipSize + 10 + chipTextWidths[i] + gap; +}); From c70626104e38b75d4e30767997cb1cc1afde910c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Jul 2026 16:17:43 +0000 Subject: [PATCH 2/5] chore(highcharts): add metadata for radar-basic --- .../metadata/javascript/highcharts.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 plots/radar-basic/metadata/javascript/highcharts.yaml diff --git a/plots/radar-basic/metadata/javascript/highcharts.yaml b/plots/radar-basic/metadata/javascript/highcharts.yaml new file mode 100644 index 0000000000..e411aa15b3 --- /dev/null +++ b/plots/radar-basic/metadata/javascript/highcharts.yaml @@ -0,0 +1,21 @@ +# Per-library metadata for highcharts implementation of radar-basic +# Auto-generated by impl-generate.yml + +library: highcharts +language: javascript +specification_id: radar-basic +created: '2026-07-24T16:17:43Z' +updated: '2026-07-24T16:17:43Z' +generated_by: claude-sonnet +workflow_run: 30108052134 +issue: 744 +language_version: 22.23.1 +library_version: 12.6.0 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-dark.html +quality_score: null +review: + strengths: [] + weaknesses: [] From 80030dec1cb46b893b0ff17251a2d0357f322407 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Jul 2026 16:25:25 +0000 Subject: [PATCH 3/5] chore(highcharts): update quality score 88 and review feedback for radar-basic --- .../implementations/javascript/highcharts.js | 5 +- .../metadata/javascript/highcharts.yaml | 258 +++++++++++++++++- 2 files changed, 253 insertions(+), 10 deletions(-) diff --git a/plots/radar-basic/implementations/javascript/highcharts.js b/plots/radar-basic/implementations/javascript/highcharts.js index d67f64678e..024766596f 100644 --- a/plots/radar-basic/implementations/javascript/highcharts.js +++ b/plots/radar-basic/implementations/javascript/highcharts.js @@ -1,8 +1,7 @@ // anyplot.ai // radar-basic: Basic Radar Chart -// Library: Highcharts 12.6.0 | Node 22 -// License: Highcharts — commercial license, free for non-commercial use (highcharts.com/license) -// Quality: pending | Created: 2026-07-24 +// Library: highcharts 12.6.0 | JavaScript 22.23.1 +// Quality: 88/100 | Created: 2026-07-24 //# anyplot-orientation: square // Only the core `highcharts` bundle is loaded (no highcharts-more), so the diff --git a/plots/radar-basic/metadata/javascript/highcharts.yaml b/plots/radar-basic/metadata/javascript/highcharts.yaml index e411aa15b3..eb00bb4763 100644 --- a/plots/radar-basic/metadata/javascript/highcharts.yaml +++ b/plots/radar-basic/metadata/javascript/highcharts.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for highcharts implementation of radar-basic -# Auto-generated by impl-generate.yml - library: highcharts language: javascript specification_id: radar-basic created: '2026-07-24T16:17:43Z' -updated: '2026-07-24T16:17:43Z' +updated: '2026-07-24T16:25:25Z' generated_by: claude-sonnet workflow_run: 30108052134 issue: 744 @@ -15,7 +12,254 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/radar-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-dark.html -quality_score: null +quality_score: 88 review: - strengths: [] - weaknesses: [] + strengths: + - Clean hand-built polar geometry (angleOf/pointAt helpers) produces a well-proportioned + hexagonal radar with balanced margins and no text overlap or edge clipping in + either theme. + - 'Correct Imprint palette usage — first series #009E73 (brand green), second series + #C475FD (canonical position 2) — identical across light and dark renders; theme-adaptive + chrome (ink, inkSoft, grid, pageBg) correctly threads through every drawn element.' + - 'Realistic, well-differentiated data: Q3-to-Q4 employee review scores rise in + most competencies but dip slightly in Adaptability, giving the two overlapping + polygons genuine comparative meaning rather than one series simply dominating.' + - Ring scale labels (20/40/60/80/100), spokes, and outer category labels are all + legible and non-overlapping in both themes, including at the crowded top-spoke + intersection near the highest-value data points. + weaknesses: + - 'The chart renders zero real Highcharts series (series: []) — every visual element + (grid rings, spokes, polygons, markers, legend, even axis labels) is drawn via + chart.renderer primitives, sidestepping Highcharts'' data-binding/series model + entirely. This is the main reason Library Mastery scores low: it''s a generic + SVG-drawing exercise achievable in almost any renderer-capable library, not a + showcase of Highcharts-specific charting strengths.' + - 'Because there is no real series or tooltip, the interactive HTML output (plot-light.html + / plot-dark.html) has no hover functionality at all — for an interactive library + the static PNG and the HTML view are identical. Add an actual scatter series at + the same pixel-projected points with tooltip.enabled: true and a formatter showing + category + value, so the HTML deliverable provides real interactive value on top + of the renderer-drawn visual, and so LM-01 credits genuine series usage instead + of only the renderer overlay.' + - Design Excellence is solid but not exceptional — the two overlapping polygons + rely entirely on default fill/stroke to convey the Q3-to-Q4 comparison; a small + numeric delta callout or highlighting the strongest single-axis change (e.g. Leadership + +10) would sharpen the storytelling (DE-03). + image_description: |- + Light render (plot-light.png): + Background: Warm off-white, consistent with #FAF8F1 — not pure white. + Chrome: Title "radar-basic · javascript · highcharts · anyplot.ai" in bold dark ink, clearly readable. Six bold dark-ink category labels (Communication, Technical Skills, Teamwork, Leadership, Problem Solving, Adaptability) at the outer edge of each axis. Thin gray spokes and pentagon-style grid rings at 20/40/60/80/100 with small gray ring-scale numbers along the top spoke. Legend at bottom center with two rounded color chips ("Q3 Review" green, "Q4 Review" purple) in dark text. + Data: Two overlapping filled hexagonal polygons — Q3 Review in brand green (#009E73) and Q4 Review in lavender/purple (#C475FD) — each with ~22% fill opacity so the overlap region reads as a blended blue-gray, and circular markers with light-colored strokes at each vertex. First series is correctly the Imprint brand green. + Legibility verdict: PASS. All text (title, axis category labels, ring scale numbers, legend) is clearly readable against the light background; no dark-on-light or "light-on-light" failures observed, and no overlapping/clipped text. + + Dark render (plot-dark.png): + Background: Warm near-black, consistent with #1A1A17 — not pure black. + Chrome: Same title now in light/cream text, clearly readable. Category labels are light-colored and legible. Grid rings and spokes render as light thin lines at reduced opacity. Ring-scale numbers (20/40/60/80/100) are a soft light-gray, legible against the dark background. Legend text is light-colored and readable. + Data: Same brand green (#009E73) and lavender (#C475FD) polygons — confirmed identical hex values to the light render — with the overlap region rendering as a muted dark-purple blend appropriate for the dark surface. Markers use dark-colored strokes for contrast against the light fills. + Legibility verdict: PASS. No dark-on-dark failures — all title, axis label, tick/ring label, and legend text is light-colored and clearly visible against the near-black background. Data colors are confirmed identical to the light render; only chrome (background, text, grid) flipped as expected. + criteria_checklist: + visual_quality: + score: 30 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: All font sizes explicitly set (titleFs computed from title length, + 15px category labels, 12px ring labels, 14-15px legend); readable in both + themes with no overflow or clipping. + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: Zoomed crops confirm no overlap at the crowded top-spoke ring-label/marker + area, at side category labels, or in the legend. + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: 6-point sparse dataset with radius-6 markers and 2.5px strokes — + appropriately prominent for the density. + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Green vs. lavender pairing is CVD-distinguishable; alpha-blended + overlap region stays legible; marker strokes add definition. + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Hexagon plus labels span roughly 80% of canvas width with balanced + margins on a 2400x2400 square canvas; legend sits close to the plot. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Descriptive competency category labels plus numeric 0-100 ring scale. + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, second series canonical position 2 (#C475FD), + identical across themes; backgrounds and chrome are theme-correct in both + renders.' + design_excellence: + score: 15 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + passed: true + comment: Thoughtful hand-built typography hierarchy, rounded legend chips, + and clean geometry — clearly above a configured default, though not FiveThirtyEight-level. + - id: DE-02 + name: Visual Refinement + score: 5 + max: 6 + passed: true + comment: Subtle 1px grid rings, no spine/frame clutter, generous whitespace; + minor room for even finer polish. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Overlapping polygons visually communicate the Q3-to-Q4 shift, but + there's no explicit callout of the biggest change — relies on the reader + to compare shapes. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Correct radar/spider chart with closed polygons. + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Filled polygons with alpha (0.22, close to spec's ~0.25), gridlines + at 20/40/60/80/100, outer-edge axis labels, distinct colors + legend, closed + polygons. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: All 6 categories mapped correctly for both series. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches the mandated format exactly; legend labels (Q3 Review + / Q4 Review) match the data series. + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 6 axes, 2 series with genuine per-axis variation (Q4 lower than Q3 + on Adaptability) rather than uniform dominance. + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Neutral, realistic employee-performance-review scenario. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Scores in the 65-92 range on a 0-100 scale are plausible for performance + review competencies. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: Linear top-to-bottom script; the two small geometry lambdas (angleOf/pointAt) + are justified by the manual polar-projection requirement. + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Hardcoded deterministic data. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: No imports beyond the provided globals. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Appropriate complexity given the core-bundle constraint (no highcharts-more + polar support); no fake UI. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Correct mount-node contract, animation disabled, no deprecated calls. + library_mastery: + score: 3 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 2 + max: 5 + passed: false + comment: 'series: [] — the chart never uses Highcharts'' series/data-binding + API; every element is drawn manually via chart.renderer, which is a low-level + escape hatch rather than the library''s recommended high-level pattern.' + - id: LM-02 + name: Distinctive Features + score: 1 + max: 5 + passed: false + comment: The renderer-based path/circle/text drawing is generic SVG composition, + replicable near-identically in D3 or raw SVG; no Highcharts-distinctive + feature (tooltip, native series, animation) is actually exercised, and tooltip + is explicitly disabled. + verdict: REJECTED +impl_tags: + dependencies: [] + techniques: + - polar-projection + - custom-legend + patterns: + - data-generation + - iteration-over-groups + dataprep: [] + styling: + - alpha-blending + - minimal-chrome From b16cd6a882a89efc754dc6e30af2eb5116cda1c2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Jul 2026 20:26:28 +0000 Subject: [PATCH 4/5] fix(highcharts): address review feedback for radar-basic Attempt 1/4 - fixes based on AI review --- .../implementations/javascript/highcharts.js | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/plots/radar-basic/implementations/javascript/highcharts.js b/plots/radar-basic/implementations/javascript/highcharts.js index 024766596f..af53274622 100644 --- a/plots/radar-basic/implementations/javascript/highcharts.js +++ b/plots/radar-basic/implementations/javascript/highcharts.js @@ -47,11 +47,26 @@ const chart = Highcharts.chart("container", { xAxis: { visible: false, gridLineWidth: 0, lineWidth: 0, tickLength: 0 }, yAxis: { visible: false, gridLineWidth: 0, lineWidth: 0, tickLength: 0 }, legend: { enabled: false }, - tooltip: { enabled: false }, + tooltip: { + enabled: true, + backgroundColor: t.elevatedBg, + borderColor: t.grid, + style: { color: t.ink }, + formatter() { + return `${this.series.name}
${this.point.name}: ${this.point.custom.actualValue}`; + }, + }, plotOptions: { series: { animation: false } }, series: [], }); +// Fix the (visible: false) axes to a known pixel-space extent so a real +// scatter series can be data-bound at the same polar-projected coordinates +// the renderer overlay uses below — this keeps the PNG output identical +// while giving the interactive HTML genuine Highcharts series/tooltip usage. +chart.xAxis[0].setExtremes(0, chart.plotWidth, false); +chart.yAxis[0].setExtremes(0, chart.plotHeight, false); + // --- Geometry ---------------------------------------------------------------- const cx = chart.plotLeft + chart.plotWidth / 2; const cy = chart.plotTop + chart.plotHeight / 2; @@ -134,7 +149,35 @@ series.forEach((s) => { .attr({ fill: s.color, stroke: t.pageBg, "stroke-width": 1.5, zIndex: 4 }) .add(); }); + + // Real Highcharts scatter series at the same vertex pixels (mapped through + // the fixed-extent axes above) — markers stay hidden so the PNG is + // untouched, but each point is genuinely data-bound and hoverable in the + // interactive HTML, with the tooltip reporting the actual category/value. + chart.addSeries( + { + type: "scatter", + name: s.name, + color: s.color, + enableMouseTracking: true, + stickyTracking: false, + animation: false, + marker: { + enabled: false, + radius: 7, + states: { hover: { enabled: true, radius: 7, lineWidth: 1.5, lineColor: t.pageBg } }, + }, + data: vertices.map(([x, y], i) => ({ + x: x - chart.plotLeft, + y: chart.plotTop + chart.plotHeight - y, + name: categories[i], + custom: { actualValue: s.values[i] }, + })), + }, + false + ); }); +chart.redraw(); // --- Legend --------------------------------------------------------------- const chipSize = 14; From 8121fe128feb09f312689d403d90d69823434d2f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Jul 2026 20:30:28 +0000 Subject: [PATCH 5/5] chore(highcharts): update quality score 91 and review feedback for radar-basic --- .../implementations/javascript/highcharts.js | 2 +- .../metadata/javascript/highcharts.yaml | 165 ++++++++---------- 2 files changed, 78 insertions(+), 89 deletions(-) diff --git a/plots/radar-basic/implementations/javascript/highcharts.js b/plots/radar-basic/implementations/javascript/highcharts.js index af53274622..a5a27ea502 100644 --- a/plots/radar-basic/implementations/javascript/highcharts.js +++ b/plots/radar-basic/implementations/javascript/highcharts.js @@ -1,7 +1,7 @@ // anyplot.ai // radar-basic: Basic Radar Chart // Library: highcharts 12.6.0 | JavaScript 22.23.1 -// Quality: 88/100 | Created: 2026-07-24 +// Quality: 91/100 | Created: 2026-07-24 //# anyplot-orientation: square // Only the core `highcharts` bundle is loaded (no highcharts-more), so the diff --git a/plots/radar-basic/metadata/javascript/highcharts.yaml b/plots/radar-basic/metadata/javascript/highcharts.yaml index eb00bb4763..e5009d3274 100644 --- a/plots/radar-basic/metadata/javascript/highcharts.yaml +++ b/plots/radar-basic/metadata/javascript/highcharts.yaml @@ -2,7 +2,7 @@ library: highcharts language: javascript specification_id: radar-basic created: '2026-07-24T16:17:43Z' -updated: '2026-07-24T16:25:25Z' +updated: '2026-07-24T20:30:28Z' generated_by: claude-sonnet workflow_run: 30108052134 issue: 744 @@ -12,51 +12,47 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/radar-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/javascript/highcharts/plot-dark.html -quality_score: 88 +quality_score: 91 review: strengths: - Clean hand-built polar geometry (angleOf/pointAt helpers) produces a well-proportioned hexagonal radar with balanced margins and no text overlap or edge clipping in either theme. - - 'Correct Imprint palette usage — first series #009E73 (brand green), second series - #C475FD (canonical position 2) — identical across light and dark renders; theme-adaptive - chrome (ink, inkSoft, grid, pageBg) correctly threads through every drawn element.' + - 'Correct Imprint palette usage — first series #009E73, second series canonical + position 2 (#C475FD) — identical across light and dark renders; theme-adaptive + chrome correctly threads through every drawn element.' + - Repair adds a genuine data-bound Highcharts scatter series at the same vertex + coordinates, with enableMouseTracking and a tooltip formatter reporting the real + category/value — the interactive HTML now provides real hover value beyond the + static PNG, while the PNG output is pixel-identical to attempt 1. - 'Realistic, well-differentiated data: Q3-to-Q4 employee review scores rise in most competencies but dip slightly in Adaptability, giving the two overlapping - polygons genuine comparative meaning rather than one series simply dominating.' - - Ring scale labels (20/40/60/80/100), spokes, and outer category labels are all - legible and non-overlapping in both themes, including at the crowded top-spoke - intersection near the highest-value data points. + polygons genuine comparative meaning.' + - Ring scale labels, spokes, and outer category labels are all legible and non-overlapping + in both themes, including at the crowded top-spoke intersection near the highest-value + data points. weaknesses: - - 'The chart renders zero real Highcharts series (series: []) — every visual element - (grid rings, spokes, polygons, markers, legend, even axis labels) is drawn via - chart.renderer primitives, sidestepping Highcharts'' data-binding/series model - entirely. This is the main reason Library Mastery scores low: it''s a generic - SVG-drawing exercise achievable in almost any renderer-capable library, not a - showcase of Highcharts-specific charting strengths.' - - 'Because there is no real series or tooltip, the interactive HTML output (plot-light.html - / plot-dark.html) has no hover functionality at all — for an interactive library - the static PNG and the HTML view are identical. Add an actual scatter series at - the same pixel-projected points with tooltip.enabled: true and a formatter showing - category + value, so the HTML deliverable provides real interactive value on top - of the renderer-drawn visual, and so LM-01 credits genuine series usage instead - of only the renderer overlay.' - - Design Excellence is solid but not exceptional — the two overlapping polygons - rely entirely on default fill/stroke to convey the Q3-to-Q4 comparison; a small - numeric delta callout or highlighting the strongest single-axis change (e.g. Leadership - +10) would sharpen the storytelling (DE-03). + - 'The core visual (grid rings, spokes, category/ring labels, data polygons, markers, + legend) is still drawn entirely via chart.renderer primitives rather than Highcharts'' + series/data-binding model — the newly added scatter series is a thin, invisible + (marker.enabled: false) layer bolted on purely for tooltip purposes, so Library + Mastery is improved but not maximized.' + - No explicit callout highlighting the single biggest Q3→Q4 change (Leadership 65→75) + — optional polish for Data Storytelling, not required. image_description: |- Light render (plot-light.png): - Background: Warm off-white, consistent with #FAF8F1 — not pure white. - Chrome: Title "radar-basic · javascript · highcharts · anyplot.ai" in bold dark ink, clearly readable. Six bold dark-ink category labels (Communication, Technical Skills, Teamwork, Leadership, Problem Solving, Adaptability) at the outer edge of each axis. Thin gray spokes and pentagon-style grid rings at 20/40/60/80/100 with small gray ring-scale numbers along the top spoke. Legend at bottom center with two rounded color chips ("Q3 Review" green, "Q4 Review" purple) in dark text. - Data: Two overlapping filled hexagonal polygons — Q3 Review in brand green (#009E73) and Q4 Review in lavender/purple (#C475FD) — each with ~22% fill opacity so the overlap region reads as a blended blue-gray, and circular markers with light-colored strokes at each vertex. First series is correctly the Imprint brand green. - Legibility verdict: PASS. All text (title, axis category labels, ring scale numbers, legend) is clearly readable against the light background; no dark-on-light or "light-on-light" failures observed, and no overlapping/clipped text. + Background: Warm off-white, consistent with #FAF8F1 (not pure white). + Chrome: Bold dark-ink title "radar-basic · javascript · highcharts · anyplot.ai" centered at top; six bold dark category labels (Communication, Technical Skills, Teamwork, Leadership, Adaptability, Problem Solving) at the outer edge of each spoke; thin gray grid rings at 20/40/60/80/100 with small gray ring-scale numbers along the top spoke; bottom-center legend with two rounded color chips ("Q3 Review" green, "Q4 Review" purple). All chrome text renders in dark ink against the light background. + Data: Two overlapping filled hexagons — brand green #009E73 (Q3 Review) and lavender #C475FD (Q4 Review) — with ~22% fill opacity so the overlap region reads as a blended tone, plus stroked circular vertex markers on each of the 6 axes per series. + Legibility verdict: PASS — all text (title, axis/category labels, ring-scale numbers, legend) is clearly readable against the warm off-white background; no light-on-light issues. Dark render (plot-dark.png): - Background: Warm near-black, consistent with #1A1A17 — not pure black. - Chrome: Same title now in light/cream text, clearly readable. Category labels are light-colored and legible. Grid rings and spokes render as light thin lines at reduced opacity. Ring-scale numbers (20/40/60/80/100) are a soft light-gray, legible against the dark background. Legend text is light-colored and readable. - Data: Same brand green (#009E73) and lavender (#C475FD) polygons — confirmed identical hex values to the light render — with the overlap region rendering as a muted dark-purple blend appropriate for the dark surface. Markers use dark-colored strokes for contrast against the light fills. - Legibility verdict: PASS. No dark-on-dark failures — all title, axis label, tick/ring label, and legend text is light-colored and clearly visible against the near-black background. Data colors are confirmed identical to the light render; only chrome (background, text, grid) flipped as expected. + Background: Warm near-black, consistent with #1A1A17 (not pure black). + Chrome: Same title, category labels, ring-scale numbers, and legend now render in light/cream text (theme-adaptive ink token) and remain fully legible; grid rings and spokes render in a subtle lighter gray appropriate for the dark surface. + Data: Colors are confirmed identical to the light render — #009E73 (Q3 Review) and #C475FD (Q4 Review); only chrome (background, text, grid) flipped as expected, per the Imprint palette rule that data colors are constant across themes. + Legibility verdict: PASS — no dark-on-dark failures; every chrome element (title, category labels, ring-scale numbers, legend text) is clearly visible against the near-black background. + + Both renders pass the theme-readability checklist. No missing/clipped pixels at either canvas edge (AR-09 clear). Canvas dimensions confirmed 2400x2400 (square format, matches //# anyplot-orientation: square directive). criteria_checklist: visual_quality: score: 30 @@ -67,51 +63,48 @@ review: score: 8 max: 8 passed: true - comment: All font sizes explicitly set (titleFs computed from title length, - 15px category labels, 12px ring labels, 14-15px legend); readable in both - themes with no overflow or clipping. + comment: All font sizes explicitly set (titleFs scales with title length, + 15px category labels, 12px ring labels); readable at full size in both themes - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: Zoomed crops confirm no overlap at the crowded top-spoke ring-label/marker - area, at side category labels, or in the legend. + comment: No collisions between labels, ring numbers, spokes, or legend - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: 6-point sparse dataset with radius-6 markers and 2.5px strokes — - appropriately prominent for the density. + comment: 6px vertex markers and 2.5px strokes well-sized for sparse (6-axis, + 2-series) data - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: Green vs. lavender pairing is CVD-distinguishable; alpha-blended - overlap region stays legible; marker strokes add definition. + comment: Green/lavender pairing with alpha-blended overlap gives good contrast + and CVD-safe distinction - id: VQ-05 name: Layout & Canvas score: 4 max: 4 passed: true - comment: Hexagon plus labels span roughly 80% of canvas width with balanced - margins on a 2400x2400 square canvas; legend sits close to the plot. + comment: Balanced margins, plot fills majority of the 2400x2400 canvas, legend + sits close to the plot - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Descriptive competency category labels plus numeric 0-100 ring scale. + comment: Descriptive category labels plus explicit 20/40/60/80/100 ring scale - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true comment: 'First series #009E73, second series canonical position 2 (#C475FD), - identical across themes; backgrounds and chrome are theme-correct in both - renders.' + identical across themes; backgrounds theme-correct' design_excellence: score: 15 max: 20 @@ -121,23 +114,21 @@ review: score: 6 max: 8 passed: true - comment: Thoughtful hand-built typography hierarchy, rounded legend chips, - and clean geometry — clearly above a configured default, though not FiveThirtyEight-level. + comment: Thoughtful typography hierarchy and hand-built polar geometry, clearly + above a configured default - id: DE-02 name: Visual Refinement score: 5 max: 6 passed: true - comment: Subtle 1px grid rings, no spine/frame clutter, generous whitespace; - minor room for even finer polish. + comment: Subtle grid rings, no frame clutter, generous whitespace - id: DE-03 name: Data Storytelling score: 4 max: 6 passed: true - comment: Overlapping polygons visually communicate the Q3-to-Q4 shift, but - there's no explicit callout of the biggest change — relies on the reader - to compare shapes. + comment: Overlap communicates the Q3-to-Q4 shift; no explicit callout on the + single biggest change (optional polish) spec_compliance: score: 15 max: 15 @@ -147,28 +138,27 @@ review: score: 5 max: 5 passed: true - comment: Correct radar/spider chart with closed polygons. + comment: Correct radar/spider chart - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Filled polygons with alpha (0.22, close to spec's ~0.25), gridlines - at 20/40/60/80/100, outer-edge axis labels, distinct colors + legend, closed - polygons. + comment: Filled polygons with alpha (~0.22), gridlines at 20/40/60/80/100, + outer-edge axis labels, distinct colors + legend, closed polygons - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: All 6 categories mapped correctly for both series. + comment: All 6 category axes correctly mapped for both series - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title matches the mandated format exactly; legend labels (Q3 Review - / Q4 Review) match the data series. + comment: Title format correct; legend labels match series names (Q3 Review + / Q4 Review) data_quality: score: 15 max: 15 @@ -178,21 +168,21 @@ review: score: 6 max: 6 passed: true - comment: 6 axes, 2 series with genuine per-axis variation (Q4 lower than Q3 - on Adaptability) rather than uniform dominance. + comment: Two review cycles with realistic per-axis variation (some up, one + down) - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Neutral, realistic employee-performance-review scenario. + comment: Employee performance review scenario — real, comprehensible, neutral - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Scores in the 65-92 range on a 0-100 scale are plausible for performance - review competencies. + comment: Scores in 65-92 range on a 0-100 scale are plausible for performance + review data code_quality: score: 10 max: 10 @@ -202,62 +192,61 @@ review: score: 3 max: 3 passed: true - comment: Linear top-to-bottom script; the two small geometry lambdas (angleOf/pointAt) - are justified by the manual polar-projection requirement. + comment: Linear data → chart → geometry → draw structure, no classes - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: Hardcoded deterministic data. + comment: Fully hard-coded, deterministic data - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: No imports beyond the provided globals. + comment: No imports beyond the provided Highcharts global - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Appropriate complexity given the core-bundle constraint (no highcharts-more - polar support); no fake UI. + comment: No fake UI or fake-interactivity comments; the added scatter series + is genuinely data-bound, not simulated - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Correct mount-node contract, animation disabled, no deprecated calls. + comment: Uses Highcharts.chart("container", ...) mount-node contract correctly, + animation disabled library_mastery: - score: 3 + score: 6 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 2 + score: 3 max: 5 - passed: false - comment: 'series: [] — the chart never uses Highcharts'' series/data-binding - API; every element is drawn manually via chart.renderer, which is a low-level - escape hatch rather than the library''s recommended high-level pattern.' + passed: true + comment: Correct usage of a real Highcharts series (scatter, addSeries, fixed-extent + axes) added in this repair, but the chart's core visual body still bypasses + series/data-binding via chart.renderer primitives - id: LM-02 name: Distinctive Features - score: 1 + score: 3 max: 5 - passed: false - comment: The renderer-based path/circle/text drawing is generic SVG composition, - replicable near-identically in D3 or raw SVG; no Highcharts-distinctive - feature (tooltip, native series, animation) is actually exercised, and tooltip - is explicitly disabled. - verdict: REJECTED + passed: true + comment: Tooltip formatter with custom point data (this.point.custom.actualValue) + and hover marker states are genuine Highcharts-specific features, addressing + the attempt-1 gap + verdict: APPROVED impl_tags: dependencies: [] techniques: - polar-projection - custom-legend + - hover-tooltips patterns: - - data-generation - iteration-over-groups dataprep: [] styling: