From 95c755a3c5ee450a994380e04f29d93f6ee6b36d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 01:19:15 +0000 Subject: [PATCH 1/5] feat(highcharts): implement waveform-audio --- .../implementations/python/highcharts.py | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 plots/waveform-audio/implementations/python/highcharts.py diff --git a/plots/waveform-audio/implementations/python/highcharts.py b/plots/waveform-audio/implementations/python/highcharts.py new file mode 100644 index 0000000000..e9f73e0ada --- /dev/null +++ b/plots/waveform-audio/implementations/python/highcharts.py @@ -0,0 +1,194 @@ +"""anyplot.ai +waveform-audio: Audio Waveform Plot +Library: highcharts_core | Python 3.13 +Quality: pending | Created: 2026-06-03 +""" + +import os +import tempfile +import time +import urllib.request +from pathlib import Path + +import numpy as np +from highcharts_core.chart import Chart +from highcharts_core.options import HighchartsOptions +from highcharts_core.options.series.area import AreaSeries +from PIL import Image +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + + +# Theme tokens — Imprint palette, see prompts/default-style-guide.md +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" +GRID = "rgba(26,26,23,0.15)" if THEME == "light" else "rgba(240,239,232,0.15)" + +IMPRINT_PALETTE = ["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030", "#2ABCCD", "#954477", "#99B314"] +BRAND = IMPRINT_PALETTE[0] # Imprint palette position 1 — ALWAYS first series + +# Data — synthetic speech waveform (two voiced syllables, 2 s at 44 100 Hz) +np.random.seed(42) +SAMPLE_RATE = 44100 +DURATION = 2.0 +n_samples = int(SAMPLE_RATE * DURATION) +t_full = np.linspace(0, DURATION, n_samples) + +# Voiced source: fundamental (130 Hz) + harmonics → vowel-like timbre +f0 = 130 +raw = ( + 0.50 * np.sin(2 * np.pi * 1 * f0 * t_full) + + 0.25 * np.sin(2 * np.pi * 2 * f0 * t_full) + + 0.15 * np.sin(2 * np.pi * 3 * f0 * t_full) + + 0.07 * np.sin(2 * np.pi * 4 * f0 * t_full) + + 0.03 * np.sin(2 * np.pi * 5 * f0 * t_full) +) + +# Amplitude envelope: two syllables separated by a brief pause +envelope = np.zeros(n_samples) +mask1 = (t_full >= 0.15) & (t_full <= 0.65) +envelope[mask1] = np.hanning(mask1.sum()) +mask2 = (t_full >= 0.85) & (t_full <= 1.55) +envelope[mask2] = np.hanning(mask2.sum()) * 0.80 + +raw = raw * envelope + 0.005 * np.random.randn(n_samples) +raw = np.clip(raw, -1.0, 1.0) + +# Downsample to 3 000 display points +n_display = 3000 +step = n_samples // n_display +t_disp = t_full[::step][:n_display] +amp_disp = raw[::step][:n_display] + +data_points = [[round(float(tv), 6), round(float(av), 5)] for tv, av in zip(t_disp, amp_disp, strict=True)] + +# Title — font size scaled to prevent overflow at 3200 px width +title = "Speech Waveform · waveform-audio · python · highcharts · anyplot.ai" +title_px = max(44, round(66 * 67 / len(title))) + +# Chart +chart = Chart(container="container") +chart.options = HighchartsOptions() + +chart.options.chart = { + "type": "area", + "width": 3200, + "height": 1800, + "backgroundColor": PAGE_BG, + "style": {"color": INK}, + "marginBottom": 130, + "marginLeft": 155, + "marginRight": 60, + "marginTop": 90, +} + +chart.options.title = {"text": title, "style": {"fontSize": f"{title_px}px", "color": INK, "fontWeight": "600"}} + +chart.options.x_axis = { + "title": {"text": "Time (seconds)", "style": {"fontSize": "56px", "color": INK}}, + "labels": {"style": {"fontSize": "44px", "color": INK_SOFT}}, + "tickInterval": 0.25, + "lineColor": INK_SOFT, + "tickColor": INK_SOFT, + "gridLineColor": GRID, + "gridLineWidth": 1, +} + +chart.options.y_axis = { + "title": {"text": "Amplitude", "style": {"fontSize": "56px", "color": INK}}, + "labels": {"style": {"fontSize": "44px", "color": INK_SOFT}}, + "min": -1.2, + "max": 1.2, + "tickInterval": 0.5, + "lineColor": INK_SOFT, + "tickColor": INK_SOFT, + "gridLineColor": GRID, + "gridLineWidth": 1, + "plotLines": [{"value": 0, "color": INK_SOFT, "width": 2, "zIndex": 5}], +} + +chart.options.colors = [BRAND] + +chart.options.plot_options = { + "area": { + "marker": {"enabled": False}, + "fillOpacity": 0.35, + "threshold": 0, + "lineWidth": 1.5, + "states": {"hover": {"lineWidth": 1.5}}, + } +} + +chart.options.legend = {"enabled": False} + +chart.options.tooltip = { + "backgroundColor": ELEVATED_BG, + "style": {"color": INK, "fontSize": "36px"}, + "borderColor": INK_SOFT, + "valueDecimals": 4, +} + +# Series +waveform = AreaSeries() +waveform.name = "Amplitude" +waveform.data = data_points +chart.add_series(waveform) + +# Download Highcharts JS — CDN unavailable from file:// in headless Chrome +req = urllib.request.Request( + "https://code.highcharts.com/highcharts.js", + headers={"User-Agent": "Mozilla/5.0", "Referer": "https://www.highcharts.com/"}, +) +with urllib.request.urlopen(req, timeout=30) as resp: + highcharts_js = resp.read().decode("utf-8") + +js_literal = chart.to_js_literal() +html_content = f""" + + + + + + +
+ + +""" + +# Save HTML artifact +with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f: + f.write(html_content) + +# Screenshot via headless Chrome with authoritative CDP viewport override +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("--window-size=3200,1800") + +driver = webdriver.Chrome(options=chrome_options) +driver.execute_cdp_cmd( + "Emulation.setDeviceMetricsOverride", {"width": 3200, "height": 1800, "deviceScaleFactor": 1, "mobile": False} +) +driver.get(f"file://{temp_path}") +time.sleep(5) +driver.save_screenshot(f"plot-{THEME}.png") +driver.quit() + +Path(temp_path).unlink() + +# Pin to exact 3200×1800 — belt-and-braces against ±1-2 px rounding +_img = Image.open(f"plot-{THEME}.png").convert("RGB") +if _img.size != (3200, 1800): + _norm = Image.new("RGB", (3200, 1800), PAGE_BG) + _norm.paste(_img, ((3200 - _img.size[0]) // 2, (1800 - _img.size[1]) // 2)) + _norm.save(f"plot-{THEME}.png") From 7f2859047dd7e5a56fad3465e8bc0ebac581b2c3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 01:19:29 +0000 Subject: [PATCH 2/5] chore(highcharts): add metadata for waveform-audio --- .../metadata/python/highcharts.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 plots/waveform-audio/metadata/python/highcharts.yaml diff --git a/plots/waveform-audio/metadata/python/highcharts.yaml b/plots/waveform-audio/metadata/python/highcharts.yaml new file mode 100644 index 0000000000..73b9b30c19 --- /dev/null +++ b/plots/waveform-audio/metadata/python/highcharts.yaml @@ -0,0 +1,21 @@ +# Per-library metadata for highcharts implementation of waveform-audio +# Auto-generated by impl-generate.yml + +library: highcharts +language: python +specification_id: waveform-audio +created: '2026-06-03T01:19:29Z' +updated: '2026-06-03T01:19:29Z' +generated_by: claude-sonnet +workflow_run: 26857611677 +issue: 4563 +language_version: 3.13.13 +library_version: unknown +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-dark.html +quality_score: null +review: + strengths: [] + weaknesses: [] From 7368c22f2d3a5ad1c23c77c6a24f8cca28edc6cc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 01:26:26 +0000 Subject: [PATCH 3/5] chore(highcharts): update quality score 84 and review feedback for waveform-audio --- .../implementations/python/highcharts.py | 6 +- .../metadata/python/highcharts.yaml | 255 +++++++++++++++++- 2 files changed, 251 insertions(+), 10 deletions(-) diff --git a/plots/waveform-audio/implementations/python/highcharts.py b/plots/waveform-audio/implementations/python/highcharts.py index e9f73e0ada..85a3254ff9 100644 --- a/plots/waveform-audio/implementations/python/highcharts.py +++ b/plots/waveform-audio/implementations/python/highcharts.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai waveform-audio: Audio Waveform Plot -Library: highcharts_core | Python 3.13 -Quality: pending | Created: 2026-06-03 +Library: highcharts unknown | Python 3.13.13 +Quality: 84/100 | Created: 2026-06-03 """ import os diff --git a/plots/waveform-audio/metadata/python/highcharts.yaml b/plots/waveform-audio/metadata/python/highcharts.yaml index 73b9b30c19..5405eba7af 100644 --- a/plots/waveform-audio/metadata/python/highcharts.yaml +++ b/plots/waveform-audio/metadata/python/highcharts.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for highcharts implementation of waveform-audio -# Auto-generated by impl-generate.yml - library: highcharts language: python specification_id: waveform-audio created: '2026-06-03T01:19:29Z' -updated: '2026-06-03T01:19:29Z' +updated: '2026-06-03T01:26:26Z' generated_by: claude-sonnet workflow_run: 26857611677 issue: 4563 @@ -15,7 +12,251 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/waveform- preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-dark.html -quality_score: null +quality_score: 84 review: - strengths: [] - weaknesses: [] + strengths: + - 'Perfect spec compliance: filled area waveform with semi-transparent fill, zero + reference line, and correct time/amplitude axes' + - Full theme adaptation — all chrome tokens (background, INK, INK_SOFT, GRID) properly + branch on ANYPLOT_THEME, both renders pass readability checks + - AreaSeries with threshold:0 correctly produces bidirectional fill from zero — + a Highcharts-specific feature well-suited to waveform visualization + - 'Realistic synthetic speech data: physically accurate fundamental (130 Hz) + harmonics + with Hanning amplitude envelope producing two clearly separated voiced syllables' + - All font sizes explicitly set following the style guide (title 65px dynamically + scaled, axis labels 56px, tick labels 44px); clean KISS code with seed=42 + weaknesses: + - 'Design lacks visual distinction: DE-01/DE-02/DE-03 are at or just above default + — no spine removal, no emphasis technique (color contrast, annotations, highlighted + peaks), and the chart reads as a configured-default rather than a crafted visualization' + - Y-axis auto-extends to ±1.5 (tickInterval 0.5 from min -1.2) while data peaks + at ~0.65 — waveform occupies only ~43% of vertical space, making the signal appear + small; tighten y-axis range to e.g. min:-0.8/max:0.8 or clip to ±1.0 to better + frame actual dynamics + - Spec notes explicitly require min/max envelope rendering to avoid aliasing — implementation + uses simple stride-N decimation (every 29th sample) instead; for a 44 100 Hz signal + downsampled to 3 000 display points this may miss peaks and under-represent transients + in the onset/offset region + - 'No visual hierarchy: syllable onsets/offsets or peak amplitude regions are not + emphasized — even a single vertical annotation or subtle shaded region between + syllables would substantially improve storytelling (DE-03)' + image_description: |- + Light render (plot-light.png): + Background: Warm off-white #FAF8F1 — correct Imprint light surface, not pure white + Chrome: Title "Speech Waveform · waveform-audio · python · highcharts · anyplot.ai" in dark ink, clearly readable. X-axis label "Time (seconds)" and Y-axis label "Amplitude" in dark INK text, proportionally sized. Tick labels (-1.5 to 1.5 on Y, 0 to 1.75 on X) in INK_SOFT — all readable. Subtle grid lines at ~15% opacity. Zero reference line visible across plot. + Data: Two distinct waveform "lobes" in brand green #009E73 with semi-transparent fill (0.35 opacity), one between ~0.15-0.65 s peaking at ~0.65 amplitude and a second between ~0.85-1.55 s peaking at ~0.55. The silence before, between, and after the syllables is clearly visible near the zero baseline. Minor noise floor visible in silent regions. + Legibility verdict: PASS — all text clearly readable against the light background; no light-on-light failures observed. + + Dark render (plot-dark.png): + Background: Warm near-black #1A1A17 — correct Imprint dark surface, not pure black + Chrome: Title in light INK (#F0EFE8), clearly visible against dark background. Axis labels and tick labels in INK_SOFT (#B8B7B0) — all readable. Grid lines are subtle (rgba(240,239,232,0.15)). Zero reference line visible. No dark-on-dark failures detected. + Data: Waveform in identical brand green #009E73 — data colors are unchanged from light render; only chrome elements (background, text, grid, tooltip) have flipped. Both syllable lobes have the same shape and position as in the light render. + Legibility verdict: PASS — all text clearly readable against the dark background; no dark-on-dark failures. + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: 'All font sizes explicitly set (title 65px dynamically scaled, axis + labels 56px, ticks 44px). Both renders readable. Minor deduction: y-axis + labels appear slightly small at the rendered image scale.' + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: No overlapping text or data elements in either render. + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: 'Waveform clearly visible with semi-transparent fill. Minor deduction: + y-axis auto-extends to ±1.5 while data peaks at ~0.65, so the signal occupies + only ~43% of vertical canvas space.' + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: 'Single series in CVD-safe brand green #009E73. No red-green conflict.' + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Canvas gate passed (3200x1800). Good margins, no overflow, no clipping. + Title well-positioned. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: 'X: ''Time (seconds)'' with units. Y: ''Amplitude'' (normalized scale + implied). Title follows spec format.' + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First (only) series is #009E73. Background #FAF8F1 light / #1A1A17 + dark. All chrome tokens theme-correct in both renders.' + design_excellence: + score: 10 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 4 + max: 8 + passed: false + comment: 'Well-configured defaults: Imprint palette, theme tokens, semi-transparent + fill. No distinctive design choices that elevate beyond library defaults.' + - id: DE-02 + name: Visual Refinement + score: 3 + max: 6 + passed: false + comment: Legend disabled for single series, subtle 15% opacity grid, generous + margins, zero reference line. Top/right spines not explicitly removed (Highcharts + defaults to no top/right axis lines, so this is acceptable). + - id: DE-03 + name: Data Storytelling + score: 3 + max: 6 + passed: false + comment: The waveform naturally tells the two-syllable story and the zero + reference line aids interpretation. No deliberate visual hierarchy — syllable + regions are not annotated or emphasized. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: 'Correct: filled area waveform symmetric around zero using AreaSeries + with threshold:0.' + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Semi-transparent fill (0.35 opacity), zero reference line (plotLines + at 0), time x-axis, amplitude y-axis, dense line waveform — all present. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: 'X: time in seconds (0–2 s). Y: normalized amplitude (−1 to +1 range + with slight extension).' + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: 'Title: ''Speech Waveform · waveform-audio · python · highcharts + · anyplot.ai'' — correct prefixed format. Legend disabled (single series).' + data_quality: + score: 14 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 5 + max: 6 + passed: true + comment: 'Two syllables with different peak amplitudes, silence gaps, amplitude + envelope, noise floor in silent regions. Minor deduction: spec recommends + min/max envelope rendering for dense waveforms; implementation uses simple + stride-N decimation instead.' + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Physically accurate speech model (130 Hz F0 + harmonics, Hanning + envelope, 44100 Hz sample rate). Neutral content. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Standard audio sample rate, 2 s duration, normalized ±1 amplitude + range. All values physically plausible. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Linear structure: imports → theme tokens → data → chart → series + → export.' + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: np.random.seed(42) set. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All imports are used. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean, readable, no over-engineering, no fake UI. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png and plot-{THEME}.html. Uses ANYPLOT_THEME + env var. + library_mastery: + score: 7 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Correct container, HighchartsOptions, AreaSeries. Follows the library + guide (CDN download, inline embedding, CDP viewport override). Above-default + idiomatic usage. + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: threshold:0 on AreaSeries produces bidirectional fill (Highcharts-specific); + plotLines at zIndex:5 for zero reference; HTML artifact output. These are + genuine Highcharts-specific features. + verdict: REJECTED +impl_tags: + dependencies: + - selenium + - pillow + techniques: + - html-export + patterns: + - data-generation + dataprep: [] + styling: + - alpha-blending From 35c66a6a02cc2e92ffebca9e2d5afd4fade4514e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 01:32:43 +0000 Subject: [PATCH 4/5] fix(highcharts): address review feedback for waveform-audio Attempt 1/3 - fixes based on AI review --- .../implementations/python/highcharts.py | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/plots/waveform-audio/implementations/python/highcharts.py b/plots/waveform-audio/implementations/python/highcharts.py index 85a3254ff9..e478c87965 100644 --- a/plots/waveform-audio/implementations/python/highcharts.py +++ b/plots/waveform-audio/implementations/python/highcharts.py @@ -1,4 +1,4 @@ -""" anyplot.ai +"""anyplot.ai waveform-audio: Audio Waveform Plot Library: highcharts unknown | Python 3.13.13 Quality: 84/100 | Created: 2026-06-03 @@ -26,6 +26,7 @@ INK = "#1A1A17" if THEME == "light" else "#F0EFE8" INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" GRID = "rgba(26,26,23,0.15)" if THEME == "light" else "rgba(240,239,232,0.15)" +SYLLABLE_BAND = "rgba(0,158,115,0.09)" if THEME == "light" else "rgba(0,158,115,0.13)" IMPRINT_PALETTE = ["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030", "#2ABCCD", "#954477", "#99B314"] BRAND = IMPRINT_PALETTE[0] # Imprint palette position 1 — ALWAYS first series @@ -57,13 +58,23 @@ raw = raw * envelope + 0.005 * np.random.randn(n_samples) raw = np.clip(raw, -1.0, 1.0) -# Downsample to 3 000 display points -n_display = 3000 -step = n_samples // n_display -t_disp = t_full[::step][:n_display] -amp_disp = raw[::step][:n_display] - -data_points = [[round(float(tv), 6), round(float(av), 5)] for tv, av in zip(t_disp, amp_disp, strict=True)] +# Min/max envelope downsampling — captures peaks and troughs per window, avoids aliasing +# 1500 windows × 2 samples (peak + trough) = 3000 display points +n_windows = 1500 +window_size = n_samples // n_windows +t_env = [] +for i in range(n_windows): + start = i * window_size + end = min(start + window_size, n_samples) + w = raw[start:end] + times = t_full[start:end] + max_i = int(np.argmax(w)) + min_i = int(np.argmin(w)) + t_env.append((float(times[max_i]), float(w[max_i]))) + t_env.append((float(times[min_i]), float(w[min_i]))) +t_env.sort() + +data_points = [[round(t, 6), round(a, 5)] for t, a in t_env] # Title — font size scaled to prevent overflow at 3200 px width title = "Speech Waveform · waveform-audio · python · highcharts · anyplot.ai" @@ -82,10 +93,14 @@ "marginBottom": 130, "marginLeft": 155, "marginRight": 60, - "marginTop": 90, + "marginTop": 120, } chart.options.title = {"text": title, "style": {"fontSize": f"{title_px}px", "color": INK, "fontWeight": "600"}} +chart.options.subtitle = { + "text": "Two voiced syllables with harmonic structure (F0 = 130 Hz) separated by a brief silence gap", + "style": {"fontSize": "40px", "color": INK_SOFT}, +} chart.options.x_axis = { "title": {"text": "Time (seconds)", "style": {"fontSize": "56px", "color": INK}}, @@ -95,14 +110,18 @@ "tickColor": INK_SOFT, "gridLineColor": GRID, "gridLineWidth": 1, + "plotBands": [ + {"from": 0.15, "to": 0.65, "color": SYLLABLE_BAND}, + {"from": 0.85, "to": 1.55, "color": SYLLABLE_BAND}, + ], } chart.options.y_axis = { "title": {"text": "Amplitude", "style": {"fontSize": "56px", "color": INK}}, "labels": {"style": {"fontSize": "44px", "color": INK_SOFT}}, - "min": -1.2, - "max": 1.2, - "tickInterval": 0.5, + "min": -0.8, + "max": 0.8, + "tickInterval": 0.4, "lineColor": INK_SOFT, "tickColor": INK_SOFT, "gridLineColor": GRID, @@ -115,7 +134,7 @@ chart.options.plot_options = { "area": { "marker": {"enabled": False}, - "fillOpacity": 0.35, + "fillOpacity": 0.40, "threshold": 0, "lineWidth": 1.5, "states": {"hover": {"lineWidth": 1.5}}, From 10405fb8670d32ecfa246c5f5d00396b1750367f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 01:38:48 +0000 Subject: [PATCH 5/5] chore(highcharts): update quality score 89 and review feedback for waveform-audio --- .../implementations/python/highcharts.py | 4 +- .../metadata/python/highcharts.yaml | 183 ++++++++---------- 2 files changed, 83 insertions(+), 104 deletions(-) diff --git a/plots/waveform-audio/implementations/python/highcharts.py b/plots/waveform-audio/implementations/python/highcharts.py index e478c87965..15f7525997 100644 --- a/plots/waveform-audio/implementations/python/highcharts.py +++ b/plots/waveform-audio/implementations/python/highcharts.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai waveform-audio: Audio Waveform Plot Library: highcharts unknown | Python 3.13.13 -Quality: 84/100 | Created: 2026-06-03 +Quality: 89/100 | Created: 2026-06-03 """ import os diff --git a/plots/waveform-audio/metadata/python/highcharts.yaml b/plots/waveform-audio/metadata/python/highcharts.yaml index 5405eba7af..6ea103369a 100644 --- a/plots/waveform-audio/metadata/python/highcharts.yaml +++ b/plots/waveform-audio/metadata/python/highcharts.yaml @@ -2,7 +2,7 @@ library: highcharts language: python specification_id: waveform-audio created: '2026-06-03T01:19:29Z' -updated: '2026-06-03T01:26:26Z' +updated: '2026-06-03T01:38:48Z' generated_by: claude-sonnet workflow_run: 26857611677 issue: 4563 @@ -12,49 +12,40 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/waveform- preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/waveform-audio/python/highcharts/plot-dark.html -quality_score: 84 +quality_score: 89 review: strengths: - - 'Perfect spec compliance: filled area waveform with semi-transparent fill, zero - reference line, and correct time/amplitude axes' - - Full theme adaptation — all chrome tokens (background, INK, INK_SOFT, GRID) properly - branch on ANYPLOT_THEME, both renders pass readability checks - - AreaSeries with threshold:0 correctly produces bidirectional fill from zero — - a Highcharts-specific feature well-suited to waveform visualization - - 'Realistic synthetic speech data: physically accurate fundamental (130 Hz) + harmonics - with Hanning amplitude envelope producing two clearly separated voiced syllables' - - All font sizes explicitly set following the style guide (title 65px dynamically - scaled, axis labels 56px, tick labels 44px); clean KISS code with seed=42 + - Syllable band overlays (plotBands) are a high-quality design choice that immediately + communicates speech structure to the viewer + - Min/max envelope downsampling (1500 windows x 2 samples) correctly handles the + 88200-sample waveform without aliasing artifacts + - 'Complete theme-adaptive chrome: all INK, INK_SOFT, GRID tokens applied throughout + — both renders look correct' + - Both PNG and HTML artifacts saved correctly; CDP + PIL belt-and-braces ensures + exact 3200x1800 output + - Acoustically realistic synthetic data (harmonics, hanning envelopes, noise floor, + silence gap) weaknesses: - - 'Design lacks visual distinction: DE-01/DE-02/DE-03 are at or just above default - — no spine removal, no emphasis technique (color contrast, annotations, highlighted - peaks), and the chart reads as a configured-default rather than a crafted visualization' - - Y-axis auto-extends to ±1.5 (tickInterval 0.5 from min -1.2) while data peaks - at ~0.65 — waveform occupies only ~43% of vertical space, making the signal appear - small; tighten y-axis range to e.g. min:-0.8/max:0.8 or clip to ±1.0 to better - frame actual dynamics - - Spec notes explicitly require min/max envelope rendering to avoid aliasing — implementation - uses simple stride-N decimation (every 29th sample) instead; for a 44 100 Hz signal - downsampled to 3 000 display points this may miss peaks and under-represent transients - in the onset/offset region - - 'No visual hierarchy: syllable onsets/offsets or peak amplitude regions are not - emphasized — even a single vertical annotation or subtle shaded region between - syllables would substantially improve storytelling (DE-03)' + - 'Y-axis range is ±0.8 instead of the spec-mandated ±1.0 — fix: set min: -1.0, + max: 1.0, tickInterval: 0.5 on y_axis' + - LM-02 could be stronger — no use of Highcharts-specific advanced features beyond + plotBands/plotLines; consider Highcharts Boost module or navigator for dense waveform + data image_description: |- Light render (plot-light.png): - Background: Warm off-white #FAF8F1 — correct Imprint light surface, not pure white - Chrome: Title "Speech Waveform · waveform-audio · python · highcharts · anyplot.ai" in dark ink, clearly readable. X-axis label "Time (seconds)" and Y-axis label "Amplitude" in dark INK text, proportionally sized. Tick labels (-1.5 to 1.5 on Y, 0 to 1.75 on X) in INK_SOFT — all readable. Subtle grid lines at ~15% opacity. Zero reference line visible across plot. - Data: Two distinct waveform "lobes" in brand green #009E73 with semi-transparent fill (0.35 opacity), one between ~0.15-0.65 s peaking at ~0.65 amplitude and a second between ~0.85-1.55 s peaking at ~0.55. The silence before, between, and after the syllables is clearly visible near the zero baseline. Minor noise floor visible in silent regions. - Legibility verdict: PASS — all text clearly readable against the light background; no light-on-light failures observed. + Background: Warm off-white #FAF8F1 — correct theme surface + Chrome: Title "Speech Waveform · waveform-audio · python · highcharts · anyplot.ai" in bold dark ink, spans ~75% canvas width; subtitle in INK_SOFT (muted dark); axis labels "Time (seconds)" and "Amplitude" in dark INK at 56px; tick labels in INK_SOFT at 44px — all readable + Data: Brand green #009E73 area fill with 40% opacity; two syllable bands in rgba(0,158,115,0.09) highlight voiced regions 0.15-0.65s and 0.85-1.55s; zero reference line clearly visible; dense waveform with two syllable peaks and silence gap + Legibility verdict: PASS Dark render (plot-dark.png): - Background: Warm near-black #1A1A17 — correct Imprint dark surface, not pure black - Chrome: Title in light INK (#F0EFE8), clearly visible against dark background. Axis labels and tick labels in INK_SOFT (#B8B7B0) — all readable. Grid lines are subtle (rgba(240,239,232,0.15)). Zero reference line visible. No dark-on-dark failures detected. - Data: Waveform in identical brand green #009E73 — data colors are unchanged from light render; only chrome elements (background, text, grid, tooltip) have flipped. Both syllable lobes have the same shape and position as in the light render. - Legibility verdict: PASS — all text clearly readable against the dark background; no dark-on-dark failures. + Background: Warm near-black #1A1A17 — correct dark theme surface + Chrome: Title and axis labels shift to light cream F0EFE8; tick labels and subtitle shift to B8B7B0; all text clearly readable against dark background; no dark-on-dark failures detected + Data: Waveform color identical to light render — brand green #009E73 unchanged; syllable bands slightly more saturated (rgba(0,158,115,0.13)) but tasteful; zero line visible + Legibility verdict: PASS criteria_checklist: visual_quality: - score: 28 + score: 29 max: 30 items: - id: VQ-01 @@ -62,79 +53,73 @@ review: score: 7 max: 8 passed: true - comment: 'All font sizes explicitly set (title 65px dynamically scaled, axis - labels 56px, ticks 44px). Both renders readable. Minor deduction: y-axis - labels appear slightly small at the rendered image scale.' + comment: All text explicitly sized; dynamically scaled title; both renders + readable; subtitle at 40px is at low end - id: VQ-02 name: No Overlap score: 6 max: 6 passed: true - comment: No overlapping text or data elements in either render. + comment: No text collisions; syllable bands do not obscure labels - id: VQ-03 name: Element Visibility - score: 5 + score: 6 max: 6 passed: true - comment: 'Waveform clearly visible with semi-transparent fill. Minor deduction: - y-axis auto-extends to ±1.5 while data peaks at ~0.65, so the signal occupies - only ~43% of vertical canvas space.' + comment: Min/max envelope rendering produces clean dense waveform; fillOpacity + 0.40 appropriate - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: 'Single series in CVD-safe brand green #009E73. No red-green conflict.' + comment: Single series brand green; CVD-safe - id: VQ-05 name: Layout & Canvas score: 4 max: 4 passed: true - comment: Canvas gate passed (3200x1800). Good margins, no overflow, no clipping. - Title well-positioned. + comment: Canvas 3200x1800 confirmed; generous margins; nothing clipped - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: 'X: ''Time (seconds)'' with units. Y: ''Amplitude'' (normalized scale - implied). Title follows spec format.' + comment: Descriptive labels with units - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true - comment: 'First (only) series is #009E73. Background #FAF8F1 light / #1A1A17 - dark. All chrome tokens theme-correct in both renders.' + comment: 'First series #009E73; backgrounds #FAF8F1/#1A1A17; all chrome tokens + theme-adaptive' design_excellence: - score: 10 + score: 13 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 4 + score: 5 max: 8 - passed: false - comment: 'Well-configured defaults: Imprint palette, theme tokens, semi-transparent - fill. No distinctive design choices that elevate beyond library defaults.' + passed: true + comment: Syllable bands add narrative; subtitle and dynamic title scaling + show care; still within standard area-chart conventions - id: DE-02 name: Visual Refinement - score: 3 + score: 4 max: 6 - passed: false - comment: Legend disabled for single series, subtle 15% opacity grid, generous - margins, zero reference line. Top/right spines not explicitly removed (Highcharts - defaults to no top/right axis lines, so this is acceptable). + passed: true + comment: Semi-transparent fill, subtle grid tokens, zero reference line, clean + axis presentation - id: DE-03 name: Data Storytelling - score: 3 + score: 4 max: 6 - passed: false - comment: The waveform naturally tells the two-syllable story and the zero - reference line aids interpretation. No deliberate visual hierarchy — syllable - regions are not annotated or emphasized. + passed: true + comment: Syllable bands highlight voiced regions; silence gap immediately + visible; subtitle reinforces narrative spec_compliance: - score: 15 + score: 14 max: 15 items: - id: SC-01 @@ -142,56 +127,52 @@ review: score: 5 max: 5 passed: true - comment: 'Correct: filled area waveform symmetric around zero using AreaSeries - with threshold:0.' + comment: Area series with threshold:0 produces mirrored filled waveform as + specified - id: SC-02 name: Required Features - score: 4 + score: 3 max: 4 passed: true - comment: Semi-transparent fill (0.35 opacity), zero reference line (plotLines - at 0), time x-axis, amplitude y-axis, dense line waveform — all present. + comment: Semi-transparent fill, zero line, time axis, synthetic data, envelope + rendering all present; y-axis range is +-0.8 not +-1.0 as spec requires - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: 'X: time in seconds (0–2 s). Y: normalized amplitude (−1 to +1 range - with slight extension).' + comment: X=time in seconds, Y=normalized amplitude; all data visible - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: 'Title: ''Speech Waveform · waveform-audio · python · highcharts - · anyplot.ai'' — correct prefixed format. Legend disabled (single series).' + comment: Correct title format with descriptive prefix; legend disabled for + single series data_quality: - score: 14 + score: 15 max: 15 items: - id: DQ-01 name: Feature Coverage - score: 5 + score: 6 max: 6 passed: true - comment: 'Two syllables with different peak amplitudes, silence gaps, amplitude - envelope, noise floor in silent regions. Minor deduction: spec recommends - min/max envelope rendering for dense waveforms; implementation uses simple - stride-N decimation instead.' + comment: Two syllables, harmonic structure, silence gap, noise floor, hanning + envelopes all demonstrated - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Physically accurate speech model (130 Hz F0 + harmonics, Hanning - envelope, 44100 Hz sample rate). Neutral content. + comment: F0=130 Hz typical male voice; 44100 Hz sample rate; acoustically + realistic and neutral - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: Standard audio sample rate, 2 s duration, normalized ±1 amplitude - range. All values physically plausible. + comment: Normalized amplitude domain; 2s duration; standard audio sample rate code_quality: score: 10 max: 10 @@ -201,54 +182,51 @@ review: score: 3 max: 3 passed: true - comment: 'Linear structure: imports → theme tokens → data → chart → series - → export.' + comment: Linear script, no unnecessary functions - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: np.random.seed(42) set. + comment: np.random.seed(42) - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: All imports are used. + comment: All imports actively used - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean, readable, no over-engineering, no fake UI. + comment: Min/max envelope algorithm clear; no fake UI - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves plot-{THEME}.png and plot-{THEME}.html. Uses ANYPLOT_THEME - env var. + comment: Saves plot-{THEME}.png and plot-{THEME}.html; CDP+PIL ensures exact + 3200x1800 library_mastery: - score: 7 + score: 8 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 4 + score: 5 max: 5 passed: true - comment: Correct container, HighchartsOptions, AreaSeries. Follows the library - guide (CDN download, inline embedding, CDP viewport override). Above-default - idiomatic usage. + comment: Chart(container), HighchartsOptions, AreaSeries, CDN-inline embedding, + CDP viewport override all correct - id: LM-02 name: Distinctive Features score: 3 max: 5 passed: true - comment: threshold:0 on AreaSeries produces bidirectional fill (Highcharts-specific); - plotLines at zIndex:5 for zero reference; HTML artifact output. These are - genuine Highcharts-specific features. - verdict: REJECTED + comment: plotBands and plotLines are Highcharts-specific; bidirectional fill + via threshold:0; could use Boost module or navigator for denser signal work + verdict: APPROVED impl_tags: dependencies: - selenium @@ -257,6 +235,7 @@ impl_tags: - html-export patterns: - data-generation - dataprep: [] + dataprep: + - binning styling: - alpha-blending