From 64b16fa64fc6b81fb72807caaa089df84b5657bc Mon Sep 17 00:00:00 2001
From: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
Date: Mon, 23 Feb 2026 14:50:27 +0100
Subject: [PATCH 1/4] =?UTF-8?q?update(band-basic):=20highcharts=20?=
=?UTF-8?q?=E2=80=94=20comprehensive=20quality=20review?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Comprehensive quality review of highcharts band-basic implementation.
---
.../band-basic/implementations/highcharts.py | 129 ++++++++++--------
plots/band-basic/metadata/highcharts.yaml | 10 +-
plots/band-basic/specification.md | 2 +-
plots/band-basic/specification.yaml | 6 +-
4 files changed, 82 insertions(+), 65 deletions(-)
diff --git a/plots/band-basic/implementations/highcharts.py b/plots/band-basic/implementations/highcharts.py
index b3e7a0a05f..8997588c37 100644
--- a/plots/band-basic/implementations/highcharts.py
+++ b/plots/band-basic/implementations/highcharts.py
@@ -1,7 +1,7 @@
-""" pyplots.ai
+"""pyplots.ai
band-basic: Basic Band Plot
-Library: highcharts unknown | Python 3.13.11
-Quality: 92/100 | Created: 2025-12-23
+Library: highcharts 1.10.3 | Python 3.14
+Quality: /100 | Updated: 2026-02-23
"""
import json
@@ -16,22 +16,26 @@
from selenium.webdriver.chrome.options import Options
-# Data - Time series with 95% confidence interval
+# Data - Daily temperature forecast with 95% prediction interval
np.random.seed(42)
-x = np.linspace(0, 10, 50)
-# Central trend with sinusoidal pattern
-y_center = 50 + 20 * np.sin(x) + x * 2
-# Uncertainty increases with x (heteroscedastic)
-uncertainty = 3 + 0.5 * x
-# Upper and lower bounds
-y_lower = y_center - 1.96 * uncertainty
-y_upper = y_center + 1.96 * uncertainty
+days = np.arange(1, 31)
+# Central forecast: warming trend with daily variation
+temp_center = 12 + 0.3 * days + 4 * np.sin(days * 0.4)
+# Prediction uncertainty widens over the forecast horizon
+uncertainty = 1.5 + 0.08 * days
+temp_lower = temp_center - 1.96 * uncertainty
+temp_upper = temp_center + 1.96 * uncertainty
# Prepare data for Highcharts
# arearange series expects [[x, low, high], ...]
-band_data = [[float(xi), float(lo), float(hi)] for xi, lo, hi in zip(x, y_lower, y_upper, strict=True)]
+band_data = [
+ [int(d), round(float(lo), 1), round(float(hi), 1)] for d, lo, hi in zip(days, temp_lower, temp_upper, strict=True)
+]
# line series expects [[x, y], ...]
-line_data = [[float(xi), float(yi)] for xi, yi in zip(x, y_center, strict=True)]
+line_data = [[int(d), round(float(t), 1)] for d, t in zip(days, temp_center, strict=True)]
+
+# Font stack
+font_family = "'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
# Chart options using arearange for band and line for center
chart_options = {
@@ -40,61 +44,75 @@
"height": 2700,
"backgroundColor": "#ffffff",
"marginBottom": 180,
- "marginLeft": 200,
+ "marginLeft": 220,
"marginRight": 100,
- "style": {"fontFamily": "Arial, sans-serif"},
+ "spacing": [40, 40, 40, 40],
+ "style": {"fontFamily": font_family},
+ },
+ "title": {
+ "text": "30-Day Temperature Forecast \u00b7 band-basic \u00b7 highcharts \u00b7 pyplots.ai",
+ "style": {"fontSize": "48px", "fontWeight": "bold", "fontFamily": font_family},
+ },
+ "subtitle": {
+ "text": "Daily forecast with 95% prediction interval",
+ "style": {"fontSize": "30px", "color": "#555555", "fontFamily": font_family},
},
- "title": {"text": "band-basic · highcharts · pyplots.ai", "style": {"fontSize": "64px", "fontWeight": "bold"}},
- "subtitle": {"text": "Time series with 95% confidence interval", "style": {"fontSize": "38px", "color": "#666666"}},
"xAxis": {
- "title": {"text": "Time", "style": {"fontSize": "48px"}, "margin": 20},
- "labels": {"style": {"fontSize": "36px"}},
- "gridLineWidth": 1,
- "gridLineColor": "rgba(0, 0, 0, 0.1)",
- "gridLineDashStyle": "Dash",
- "tickInterval": 1,
+ "title": {"text": "Forecast Day", "style": {"fontSize": "36px", "fontFamily": font_family}, "margin": 20},
+ "labels": {"style": {"fontSize": "28px", "fontFamily": font_family}},
+ "gridLineWidth": 0,
+ "tickInterval": 5,
+ "lineColor": "#cccccc",
+ "tickColor": "#cccccc",
},
"yAxis": {
- "title": {"text": "Value", "style": {"fontSize": "48px"}, "margin": 20},
- "labels": {"style": {"fontSize": "36px"}},
+ "title": {
+ "text": "Temperature (\u00b0C)",
+ "style": {"fontSize": "36px", "fontFamily": font_family},
+ "margin": 20,
+ },
+ "labels": {"format": "{value}\u00b0", "style": {"fontSize": "28px", "fontFamily": font_family}},
"gridLineWidth": 1,
- "gridLineColor": "rgba(0, 0, 0, 0.1)",
- "gridLineDashStyle": "Dash",
+ "gridLineColor": "rgba(0, 0, 0, 0.08)",
+ "gridLineDashStyle": "Dot",
+ "lineColor": "#cccccc",
+ "lineWidth": 1,
},
"legend": {
"enabled": True,
"align": "right",
"verticalAlign": "top",
"layout": "vertical",
- "x": -50,
- "y": 100,
- "itemStyle": {"fontSize": "36px"},
+ "x": -40,
+ "y": 80,
+ "itemStyle": {"fontSize": "28px", "fontFamily": font_family},
},
"plotOptions": {
- "arearange": {"fillOpacity": 0.3, "lineWidth": 0, "marker": {"enabled": False}},
- "line": {"lineWidth": 6, "marker": {"enabled": False}},
+ "arearange": {"fillOpacity": 0.25, "lineWidth": 0, "marker": {"enabled": False}},
+ "line": {"lineWidth": 5, "marker": {"enabled": False}},
},
"series": [
{
- "name": "95% Confidence Interval",
+ "name": "95% Prediction Interval",
"type": "arearange",
"data": band_data,
"color": "#306998",
- "fillOpacity": 0.3,
+ "fillOpacity": 0.25,
"zIndex": 0,
},
- {"name": "Mean Value", "type": "line", "data": line_data, "color": "#FFD43B", "lineWidth": 6, "zIndex": 1},
+ {"name": "Forecast", "type": "line", "data": line_data, "color": "#FFD43B", "lineWidth": 5, "zIndex": 1},
],
+ "credits": {"enabled": False},
}
-# Download Highcharts JS and highcharts-more (needed for arearange)
-highcharts_url = "https://code.highcharts.com/highcharts.js"
-highcharts_more_url = "https://code.highcharts.com/highcharts-more.js"
-
-with urllib.request.urlopen(highcharts_url, timeout=30) as response:
- highcharts_js = response.read().decode("utf-8")
-with urllib.request.urlopen(highcharts_more_url, timeout=30) as response:
- highcharts_more_js = response.read().decode("utf-8")
+# Download Highcharts JS files (jsDelivr CDN with version pin)
+cdn_base = "https://cdn.jsdelivr.net/npm/highcharts@11.4"
+js_urls = {"highcharts": f"{cdn_base}/highcharts.js", "highcharts_more": f"{cdn_base}/highcharts-more.js"}
+js_modules = {}
+for name, url in js_urls.items():
+ req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
+ with urllib.request.urlopen(req, timeout=30) as response:
+ js_modules[name] = response.read().decode("utf-8")
# Generate HTML with inline scripts
chart_options_json = json.dumps(chart_options)
@@ -102,8 +120,8 @@
-
-
+
+
@@ -120,33 +138,28 @@
f.write(html_content)
temp_path = f.name
-# Also save the HTML for interactive viewing
+# Save HTML for interactive viewing
with open("plot.html", "w", encoding="utf-8") as f:
f.write(html_content)
# Take screenshot with headless Chrome
chrome_options = Options()
-chrome_options.add_argument("--headless=new")
+chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--disable-gpu")
-chrome_options.add_argument("--force-device-scale-factor=1")
+chrome_options.add_argument("--window-size=4800,2900")
driver = webdriver.Chrome(options=chrome_options)
-driver.set_window_size(4900, 2900)
driver.get(f"file://{temp_path}")
time.sleep(5)
-
-# Take screenshot
driver.save_screenshot("plot_raw.png")
driver.quit()
-# Crop/resize to exact 4800x2700 using PIL
+# Crop to exact 4800x2700 dimensions
img = Image.open("plot_raw.png")
-final_img = Image.new("RGB", (4800, 2700), (255, 255, 255))
-final_img.paste(img.crop((0, 0, min(img.width, 4800), min(img.height, 2700))), (0, 0))
-final_img.save("plot.png")
-
-# Clean up
+img_cropped = img.crop((0, 0, 4800, 2700))
+img_cropped.save("plot.png")
Path("plot_raw.png").unlink()
+
Path(temp_path).unlink()
diff --git a/plots/band-basic/metadata/highcharts.yaml b/plots/band-basic/metadata/highcharts.yaml
index 39f2d5145e..8e99d82cab 100644
--- a/plots/band-basic/metadata/highcharts.yaml
+++ b/plots/band-basic/metadata/highcharts.yaml
@@ -1,16 +1,16 @@
library: highcharts
specification_id: band-basic
created: '2025-12-23T09:09:27Z'
-updated: '2025-12-23T09:11:45Z'
-generated_by: claude-opus-4-5-20251101
+updated: '2026-02-23T13:41:00Z'
+generated_by: claude-opus-4-6
workflow_run: 20456388074
issue: 0
-python_version: 3.13.11
-library_version: unknown
+python_version: '3.14'
+library_version: 1.10.3
preview_url: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.png
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot_thumb.png
preview_html: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.html
-quality_score: 92
+quality_score: null
impl_tags:
dependencies:
- pillow
diff --git a/plots/band-basic/specification.md b/plots/band-basic/specification.md
index 4614c2a26c..a18f9caee9 100644
--- a/plots/band-basic/specification.md
+++ b/plots/band-basic/specification.md
@@ -16,7 +16,7 @@ A band plot displays a filled region between two boundary lines, commonly used t
- `x` (numeric) - Independent variable, often representing time or sequence
- `y_lower` (numeric) - Lower boundary values defining the bottom of the band
- `y_upper` (numeric) - Upper boundary values defining the top of the band
-- `y_center` (numeric, optional) - Central trend line values (mean/median)
+- `y_center` (numeric) - Central trend line values (mean/median), shown as a contrasting line
- Size: 20-200 data points
- Example: Time series with 95% confidence interval bounds
diff --git a/plots/band-basic/specification.yaml b/plots/band-basic/specification.yaml
index c239433ec4..76a86a91e9 100644
--- a/plots/band-basic/specification.yaml
+++ b/plots/band-basic/specification.yaml
@@ -6,7 +6,7 @@ title: Basic Band Plot
# Specification tracking
created: 2025-12-15T20:42:54Z
-updated: 2025-12-15T20:42:54Z
+updated: 2026-02-23T12:00:00Z
issue: 979
suggested: MarkusNeusinger
@@ -18,10 +18,14 @@ tags:
data_type:
- numeric
- continuous
+ - timeseries
domain:
- statistics
- science
+ - general
+ - engineering
features:
- basic
- confidence-interval
- uncertainty
+ - 2d
From 2330c514541c9ae3e57b7ad37e19c828d9fe1a18 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 23 Feb 2026 13:55:45 +0000
Subject: [PATCH 2/4] chore(highcharts): update quality score 88 and review
feedback for band-basic
---
.../band-basic/implementations/highcharts.py | 4 +-
plots/band-basic/metadata/highcharts.yaml | 244 +++++++++---------
2 files changed, 129 insertions(+), 119 deletions(-)
diff --git a/plots/band-basic/implementations/highcharts.py b/plots/band-basic/implementations/highcharts.py
index 8997588c37..1c1bbf3d1c 100644
--- a/plots/band-basic/implementations/highcharts.py
+++ b/plots/band-basic/implementations/highcharts.py
@@ -1,7 +1,7 @@
-"""pyplots.ai
+""" pyplots.ai
band-basic: Basic Band Plot
Library: highcharts 1.10.3 | Python 3.14
-Quality: /100 | Updated: 2026-02-23
+Quality: 88/100 | Updated: 2026-02-23
"""
import json
diff --git a/plots/band-basic/metadata/highcharts.yaml b/plots/band-basic/metadata/highcharts.yaml
index 8e99d82cab..039b19c375 100644
--- a/plots/band-basic/metadata/highcharts.yaml
+++ b/plots/band-basic/metadata/highcharts.yaml
@@ -1,7 +1,7 @@
library: highcharts
specification_id: band-basic
created: '2025-12-23T09:09:27Z'
-updated: '2026-02-23T13:41:00Z'
+updated: '2026-02-23T13:55:45Z'
generated_by: claude-opus-4-6
workflow_run: 20456388074
issue: 0
@@ -10,11 +10,11 @@ library_version: 1.10.3
preview_url: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.png
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot_thumb.png
preview_html: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.html
-quality_score: null
+quality_score: 88
impl_tags:
dependencies:
- - pillow
- selenium
+ - pillow
techniques:
- html-export
patterns:
@@ -22,151 +22,155 @@ impl_tags:
dataprep: []
styling:
- alpha-blending
+ - grid-styling
review:
strengths:
- - Excellent use of Highcharts arearange series for band visualization with proper
- upper/lower bounds
- - Very clear visual hierarchy with contrasting band (blue, 0.3 alpha) and center
- line (yellow, solid)
- - Heteroscedastic uncertainty pattern demonstrates the value of band plots effectively
- - Proper zIndex layering ensures center line renders on top of band
- - Large, readable text sizes throughout (64px title, 48px axis labels, 36px tick
- labels)
- - Clean Selenium-based PNG export with proper image cropping
+ - Excellent use of Highcharts arearange type for band visualization
+ - Widening prediction interval data creates genuine data storytelling about growing
+ forecast uncertainty
+ - All font sizes explicitly set and clearly readable at target resolution
+ - Perfect spec compliance with all required features implemented correctly
+ - Clean well-structured code with deterministic seed and sensible data generation
weaknesses:
- - Axis labels lack units (e.g., "Time (s)" or "Value (units)" would be more informative)
- - Uses raw dictionary configuration instead of highcharts-core Python library classes
- as shown in library rules
- - Legend could be slightly larger for the 4800x2700 canvas size
- image_description: 'The plot displays a band chart with a light blue semi-transparent
- area representing the 95% confidence interval, and a golden-yellow center line
- showing the mean value. The visualization follows a sinusoidal pattern over time
- (x-axis: 0-10), with values ranging approximately from 24 to 104 on the y-axis.
- The uncertainty band visibly widens as time increases, demonstrating heteroscedastic
- behavior. The title "band-basic · highcharts · pyplots.ai" appears at the top
- in bold, with a subtitle "Time series with 95% confidence interval". A legend
- in the top-right corner identifies both the confidence interval band and mean
- value line. The background is clean white with subtle dashed grid lines.'
+ - Yellow forecast line (#FFD43B) is too bright and saturated for refined color harmony
+ - Raw JSON dict approach bypasses highcharts-core Python wrapper reducing idiomatic
+ library usage
+ - Could push visual refinement further with softer axis lines and tighter legend
+ placement
+ image_description: The plot displays a 30-day temperature forecast band chart on
+ a white background. A light blue semi-transparent band (arearange) represents
+ the 95% prediction interval, clearly widening from left to right as forecast uncertainty
+ increases over the horizon. A bright yellow line (#FFD43B) shows the central forecast
+ trend, exhibiting a sinusoidal warming pattern ranging roughly from 12°C to 22°C.
+ The title reads "30-Day Temperature Forecast · band-basic · highcharts · pyplots.ai"
+ in bold, with a gray subtitle "Daily forecast with 95% prediction interval". The
+ x-axis is labeled "Forecast Day" (ticks at 5, 10, 15, 20, 25, 30) and the y-axis
+ "Temperature (°C)" with degree symbols from 5° to 30°. A vertical legend in the
+ upper right shows "95% Prediction Interval" (blue) and "Forecast" (yellow). The
+ y-axis has subtle dotted grid lines; x-axis grid is removed. Overall layout is
+ clean with generous margins.
criteria_checklist:
visual_quality:
- score: 37
- max: 40
+ score: 29
+ max: 30
items:
- id: VQ-01
name: Text Legibility
- score: 10
- max: 10
+ score: 8
+ max: 8
passed: true
- comment: Title at 64px, axis labels at 48px, tick labels at 36px - all perfectly
- readable at 4800x2700
+ comment: 'All font sizes explicitly set: title 48px, subtitle 30px, axis titles
+ 36px, labels 28px, legend 28px'
- id: VQ-02
name: No Overlap
- score: 8
- max: 8
+ score: 6
+ max: 6
passed: true
- comment: No overlapping text elements anywhere
+ comment: No overlapping elements anywhere
- id: VQ-03
name: Element Visibility
- score: 8
- max: 8
+ score: 5
+ max: 6
passed: true
- comment: Band and line clearly visible with appropriate opacity (0.3 for band),
- line width of 6
+ comment: Band visible at 0.25 opacity, yellow line has moderate contrast against
+ light background
- id: VQ-04
name: Color Accessibility
- score: 5
- max: 5
+ score: 4
+ max: 4
passed: true
- comment: Blue (#306998) and yellow (#FFD43B) are colorblind-safe and high
- contrast
+ comment: Blue-yellow scheme is colorblind-safe
- id: VQ-05
- name: Layout Balance
+ name: Layout & Canvas
score: 4
- max: 5
+ max: 4
passed: true
- comment: Good proportions with appropriate margins, slight excess whitespace
- on right side
+ comment: Well-balanced margins, plot fills ~65% of canvas
- id: VQ-06
- name: Axis Labels
- score: 1
+ name: Axis Labels & Title
+ score: 2
max: 2
passed: true
- comment: Labels are descriptive ("Time", "Value") but lack units
- - id: VQ-07
- name: Grid & Legend
- score: 1
- max: 2
+ comment: Temperature (°C) with units, Forecast Day descriptive
+ design_excellence:
+ score: 13
+ max: 20
+ items:
+ - id: DE-01
+ name: Aesthetic Sophistication
+ score: 5
+ max: 8
+ passed: true
+ comment: Intentional palette and font stack, above defaults but bright yellow
+ is garish
+ - id: DE-02
+ name: Visual Refinement
+ score: 4
+ max: 6
+ passed: true
+ comment: Dotted y-axis-only grid, removed x-axis grid, subtle axis colors,
+ markers disabled
+ - id: DE-03
+ name: Data Storytelling
+ score: 4
+ max: 6
passed: true
- comment: Grid is subtle with dashed style and 0.1 alpha, legend well-placed
- but could be larger
+ comment: Widening prediction interval tells clear uncertainty story with visual
+ hierarchy
spec_compliance:
- score: 25
- max: 25
+ score: 15
+ max: 15
items:
- id: SC-01
name: Plot Type
- score: 8
- max: 8
- passed: true
- comment: Correct band/arearange chart type
- - id: SC-02
- name: Data Mapping
score: 5
max: 5
passed: true
- comment: X mapped to time, Y to value with proper upper/lower bounds
- - id: SC-03
+ comment: Correct band plot using arearange + line series
+ - id: SC-02
name: Required Features
- score: 5
- max: 5
+ score: 4
+ max: 4
passed: true
- comment: Band with upper/lower bounds, center line, semi-transparent fill
- (0.3 alpha)
- - id: SC-04
- name: Data Range
+ comment: Semi-transparent fill, central line, smooth interpolation, uncertainty
+ source in subtitle
+ - id: SC-03
+ name: Data Mapping
score: 3
max: 3
passed: true
- comment: All data visible, axes auto-scaled appropriately
- - id: SC-05
- name: Legend Accuracy
- score: 2
- max: 2
- passed: true
- comment: Legend correctly labels "95% Confidence Interval" and "Mean Value"
- - id: SC-06
- name: Title Format
- score: 2
- max: 2
+ comment: X=days, band boundaries correct, center line correct
+ - id: SC-04
+ name: Title & Legend
+ score: 3
+ max: 3
passed: true
- comment: 'Uses exact format: "band-basic · highcharts · pyplots.ai"'
+ comment: Title format correct with descriptive prefix, legend labels match
+ data
data_quality:
- score: 18
- max: 20
+ score: 15
+ max: 15
items:
- id: DQ-01
name: Feature Coverage
- score: 7
- max: 8
+ score: 6
+ max: 6
passed: true
- comment: Shows sinusoidal trend with heteroscedastic uncertainty (widening
- with x), demonstrates key band plot features
+ comment: Shows widening uncertainty, sinusoidal variation with warming trend
- id: DQ-02
name: Realistic Context
- score: 6
- max: 7
+ score: 5
+ max: 5
passed: true
- comment: Time series with confidence interval is plausible; generic "Value"
- label slightly reduces real-world applicability
+ comment: Temperature forecasting is real-world neutral scenario
- id: DQ-03
name: Appropriate Scale
- score: 5
- max: 5
+ score: 4
+ max: 4
passed: true
- comment: Values in reasonable 24-104 range, 50 data points appropriate for
- smooth band
+ comment: Temperatures 5-30°C realistic for 30-day forecast
code_quality:
- score: 9
+ score: 10
max: 10
items:
- id: CQ-01
@@ -174,40 +178,46 @@ review:
score: 3
max: 3
passed: true
- comment: 'Linear structure: imports → data → chart config → render → save'
+ comment: 'Linear flow: imports, data, chart options, HTML, screenshot'
- id: CQ-02
name: Reproducibility
- score: 3
- max: 3
+ score: 2
+ max: 2
passed: true
- comment: Uses np.random.seed(42)
+ comment: np.random.seed(42) set
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
- comment: Only necessary imports used
+ comment: All imports used
- id: CQ-04
- name: No Deprecated API
- score: 0
- max: 1
+ name: Code Elegance
+ score: 2
+ max: 2
passed: true
- comment: Using raw dict config instead of highcharts-core library classes
+ comment: Clean, well-organized, appropriate complexity
- id: CQ-05
- name: Output Correct
+ name: Output & API
score: 1
max: 1
passed: true
- comment: Saves as plot.png
- library_features:
- score: 3
- max: 5
+ comment: Saves plot.png, uses current Highcharts v11.4
+ library_mastery:
+ score: 6
+ max: 10
items:
- - id: LF-01
- name: Uses distinctive library features
+ - id: LM-01
+ name: Idiomatic Usage
+ score: 3
+ max: 5
+ passed: false
+ comment: Raw JSON dict approach instead of highcharts-core Python wrapper
+ - id: LM-02
+ name: Distinctive Features
score: 3
max: 5
passed: true
- comment: Uses arearange series type correctly, but doesn't use highcharts-core
- Python library as recommended
- verdict: APPROVED
+ comment: Uses Highcharts-specific arearange type with highcharts-more.js,
+ series zIndex
+ verdict: REJECTED
From 1ceefc2e2048149ce2878287cbd956b68b34c6ca Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 23 Feb 2026 14:00:38 +0000
Subject: [PATCH 3/4] fix(highcharts): address review feedback for band-basic
Attempt 1/3 - fixes based on AI review
---
.../band-basic/implementations/highcharts.py | 183 ++++++++++--------
1 file changed, 101 insertions(+), 82 deletions(-)
diff --git a/plots/band-basic/implementations/highcharts.py b/plots/band-basic/implementations/highcharts.py
index 1c1bbf3d1c..8da4c7a071 100644
--- a/plots/band-basic/implementations/highcharts.py
+++ b/plots/band-basic/implementations/highcharts.py
@@ -1,16 +1,18 @@
-""" pyplots.ai
+"""pyplots.ai
band-basic: Basic Band Plot
Library: highcharts 1.10.3 | Python 3.14
Quality: 88/100 | Updated: 2026-02-23
"""
-import json
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 AreaRangeSeries, LineSeries
from PIL import Image
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
@@ -19,93 +21,118 @@
# Data - Daily temperature forecast with 95% prediction interval
np.random.seed(42)
days = np.arange(1, 31)
-# Central forecast: warming trend with daily variation
temp_center = 12 + 0.3 * days + 4 * np.sin(days * 0.4)
-# Prediction uncertainty widens over the forecast horizon
uncertainty = 1.5 + 0.08 * days
temp_lower = temp_center - 1.96 * uncertainty
temp_upper = temp_center + 1.96 * uncertainty
-# Prepare data for Highcharts
-# arearange series expects [[x, low, high], ...]
band_data = [
[int(d), round(float(lo), 1), round(float(hi), 1)] for d, lo, hi in zip(days, temp_lower, temp_upper, strict=True)
]
-# line series expects [[x, y], ...]
line_data = [[int(d), round(float(t), 1)] for d, t in zip(days, temp_center, strict=True)]
-# Font stack
+# Build chart using highcharts-core Python wrapper
font_family = "'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
-# Chart options using arearange for band and line for center
-chart_options = {
- "chart": {
- "width": 4800,
- "height": 2700,
- "backgroundColor": "#ffffff",
- "marginBottom": 180,
- "marginLeft": 220,
- "marginRight": 100,
- "spacing": [40, 40, 40, 40],
- "style": {"fontFamily": font_family},
- },
+chart = Chart(container="container")
+chart.options = HighchartsOptions()
+
+chart.options.chart = {
+ "width": 4800,
+ "height": 2700,
+ "backgroundColor": "#ffffff",
+ "marginBottom": 180,
+ "marginLeft": 220,
+ "marginRight": 100,
+ "spacing": [40, 40, 40, 40],
+ "style": {"fontFamily": font_family},
+}
+
+chart.options.title = {
+ "text": "30-Day Temperature Forecast \u00b7 band-basic \u00b7 highcharts \u00b7 pyplots.ai",
+ "style": {"fontSize": "48px", "fontWeight": "bold", "fontFamily": font_family},
+}
+
+chart.options.subtitle = {
+ "text": "Daily forecast with 95% prediction interval",
+ "style": {"fontSize": "30px", "color": "#666666", "fontFamily": font_family},
+}
+
+chart.options.x_axis = {
"title": {
- "text": "30-Day Temperature Forecast \u00b7 band-basic \u00b7 highcharts \u00b7 pyplots.ai",
- "style": {"fontSize": "48px", "fontWeight": "bold", "fontFamily": font_family},
- },
- "subtitle": {
- "text": "Daily forecast with 95% prediction interval",
- "style": {"fontSize": "30px", "color": "#555555", "fontFamily": font_family},
- },
- "xAxis": {
- "title": {"text": "Forecast Day", "style": {"fontSize": "36px", "fontFamily": font_family}, "margin": 20},
- "labels": {"style": {"fontSize": "28px", "fontFamily": font_family}},
- "gridLineWidth": 0,
- "tickInterval": 5,
- "lineColor": "#cccccc",
- "tickColor": "#cccccc",
- },
- "yAxis": {
- "title": {
- "text": "Temperature (\u00b0C)",
- "style": {"fontSize": "36px", "fontFamily": font_family},
- "margin": 20,
- },
- "labels": {"format": "{value}\u00b0", "style": {"fontSize": "28px", "fontFamily": font_family}},
- "gridLineWidth": 1,
- "gridLineColor": "rgba(0, 0, 0, 0.08)",
- "gridLineDashStyle": "Dot",
- "lineColor": "#cccccc",
- "lineWidth": 1,
- },
- "legend": {
- "enabled": True,
- "align": "right",
- "verticalAlign": "top",
- "layout": "vertical",
- "x": -40,
- "y": 80,
- "itemStyle": {"fontSize": "28px", "fontFamily": font_family},
+ "text": "Forecast Day",
+ "style": {"fontSize": "36px", "color": "#444444", "fontFamily": font_family},
+ "margin": 20,
},
- "plotOptions": {
- "arearange": {"fillOpacity": 0.25, "lineWidth": 0, "marker": {"enabled": False}},
- "line": {"lineWidth": 5, "marker": {"enabled": False}},
+ "labels": {"style": {"fontSize": "28px", "color": "#555555", "fontFamily": font_family}},
+ "gridLineWidth": 0,
+ "tickInterval": 5,
+ "lineColor": "rgba(0, 0, 0, 0.12)",
+ "lineWidth": 1,
+ "tickColor": "rgba(0, 0, 0, 0.12)",
+ "tickLength": 8,
+}
+
+chart.options.y_axis = {
+ "title": {
+ "text": "Temperature (\u00b0C)",
+ "style": {"fontSize": "36px", "color": "#444444", "fontFamily": font_family},
+ "margin": 20,
},
- "series": [
- {
- "name": "95% Prediction Interval",
- "type": "arearange",
- "data": band_data,
- "color": "#306998",
- "fillOpacity": 0.25,
- "zIndex": 0,
- },
- {"name": "Forecast", "type": "line", "data": line_data, "color": "#FFD43B", "lineWidth": 5, "zIndex": 1},
- ],
- "credits": {"enabled": False},
+ "labels": {"format": "{value}\u00b0", "style": {"fontSize": "28px", "color": "#555555", "fontFamily": font_family}},
+ "gridLineWidth": 1,
+ "gridLineColor": "rgba(0, 0, 0, 0.06)",
+ "gridLineDashStyle": "Dot",
+ "lineColor": "rgba(0, 0, 0, 0.12)",
+ "lineWidth": 1,
+}
+
+chart.options.legend = {
+ "enabled": True,
+ "align": "right",
+ "verticalAlign": "top",
+ "layout": "vertical",
+ "x": -60,
+ "y": 60,
+ "floating": True,
+ "backgroundColor": "rgba(255, 255, 255, 0.85)",
+ "borderWidth": 0,
+ "shadow": False,
+ "itemStyle": {"fontSize": "28px", "fontWeight": "normal", "fontFamily": font_family},
+ "itemMarginBottom": 8,
+ "symbolRadius": 4,
+}
+
+chart.options.plot_options = {
+ "arearange": {"fillOpacity": 0.25, "lineWidth": 0, "marker": {"enabled": False}},
+ "line": {"lineWidth": 5, "marker": {"enabled": False}},
}
-# Download Highcharts JS files (jsDelivr CDN with version pin)
+chart.options.credits = {"enabled": False}
+
+# Band series using AreaRangeSeries
+band = AreaRangeSeries()
+band.data = band_data
+band.name = "95% Prediction Interval"
+band.color = "#306998"
+band.fill_opacity = 0.25
+band.z_index = 0
+
+# Forecast line using LineSeries with refined deep amber color
+forecast = LineSeries()
+forecast.data = line_data
+forecast.name = "Forecast"
+forecast.color = "#C49000"
+forecast.line_width = 5
+forecast.z_index = 1
+
+chart.add_series(band)
+chart.add_series(forecast)
+
+# Generate JS via highcharts-core wrapper
+chart_js = chart.to_js_literal()
+
+# Download Highcharts JS files for inline embedding (headless Chrome cannot load CDN)
cdn_base = "https://cdn.jsdelivr.net/npm/highcharts@11.4"
js_urls = {"highcharts": f"{cdn_base}/highcharts.js", "highcharts_more": f"{cdn_base}/highcharts-more.js"}
js_modules = {}
@@ -114,8 +141,7 @@
with urllib.request.urlopen(req, timeout=30) as response:
js_modules[name] = response.read().decode("utf-8")
-# Generate HTML with inline scripts
-chart_options_json = json.dumps(chart_options)
+# Build HTML with inline Highcharts JS and chart literal from wrapper
html_content = f"""
@@ -125,20 +151,14 @@
-
+
"""
-# Write temp HTML file
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
f.write(html_content)
temp_path = f.name
-# Save HTML for interactive viewing
with open("plot.html", "w", encoding="utf-8") as f:
f.write(html_content)
@@ -156,7 +176,6 @@
driver.save_screenshot("plot_raw.png")
driver.quit()
-# Crop to exact 4800x2700 dimensions
img = Image.open("plot_raw.png")
img_cropped = img.crop((0, 0, 4800, 2700))
img_cropped.save("plot.png")
From f0e5ac44a7d239b366482eaf7596a84b728c7af3 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 23 Feb 2026 14:07:13 +0000
Subject: [PATCH 4/4] chore(highcharts): update quality score 91 and review
feedback for band-basic
---
.../band-basic/implementations/highcharts.py | 4 +-
plots/band-basic/metadata/highcharts.yaml | 142 ++++++++++--------
2 files changed, 81 insertions(+), 65 deletions(-)
diff --git a/plots/band-basic/implementations/highcharts.py b/plots/band-basic/implementations/highcharts.py
index 8da4c7a071..7868c80216 100644
--- a/plots/band-basic/implementations/highcharts.py
+++ b/plots/band-basic/implementations/highcharts.py
@@ -1,7 +1,7 @@
-"""pyplots.ai
+""" pyplots.ai
band-basic: Basic Band Plot
Library: highcharts 1.10.3 | Python 3.14
-Quality: 88/100 | Updated: 2026-02-23
+Quality: 91/100 | Updated: 2026-02-23
"""
import tempfile
diff --git a/plots/band-basic/metadata/highcharts.yaml b/plots/band-basic/metadata/highcharts.yaml
index 039b19c375..744becb772 100644
--- a/plots/band-basic/metadata/highcharts.yaml
+++ b/plots/band-basic/metadata/highcharts.yaml
@@ -1,7 +1,7 @@
library: highcharts
specification_id: band-basic
created: '2025-12-23T09:09:27Z'
-updated: '2026-02-23T13:55:45Z'
+updated: '2026-02-23T14:07:12Z'
generated_by: claude-opus-4-6
workflow_run: 20456388074
issue: 0
@@ -10,7 +10,7 @@ library_version: 1.10.3
preview_url: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.png
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot_thumb.png
preview_html: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.html
-quality_score: 88
+quality_score: 91
impl_tags:
dependencies:
- selenium
@@ -25,33 +25,36 @@ impl_tags:
- grid-styling
review:
strengths:
- - Excellent use of Highcharts arearange type for band visualization
- - Widening prediction interval data creates genuine data storytelling about growing
- forecast uncertainty
- - All font sizes explicitly set and clearly readable at target resolution
- - Perfect spec compliance with all required features implemented correctly
- - Clean well-structured code with deterministic seed and sensible data generation
+ - Excellent visual quality with all font sizes explicitly set and readable
+ - Harmonious blue-amber color pairing with strong contrast and colorblind accessibility
+ - Data storytelling through widening uncertainty band communicates increasing forecast
+ uncertainty over time
+ - Clean well-refined chart with subtle dotted gridlines and minimal visual noise
+ - Realistic temperature forecasting context with statistically plausible 95% prediction
+ intervals
+ - Clean code structure with proper CDN download pattern for headless Chrome
weaknesses:
- - Yellow forecast line (#FFD43B) is too bright and saturated for refined color harmony
- - Raw JSON dict approach bypasses highcharts-core Python wrapper reducing idiomatic
- library usage
- - Could push visual refinement further with softer axis lines and tighter legend
- placement
- image_description: The plot displays a 30-day temperature forecast band chart on
- a white background. A light blue semi-transparent band (arearange) represents
- the 95% prediction interval, clearly widening from left to right as forecast uncertainty
- increases over the horizon. A bright yellow line (#FFD43B) shows the central forecast
- trend, exhibiting a sinusoidal warming pattern ranging roughly from 12°C to 22°C.
- The title reads "30-Day Temperature Forecast · band-basic · highcharts · pyplots.ai"
- in bold, with a gray subtitle "Daily forecast with 95% prediction interval". The
- x-axis is labeled "Forecast Day" (ticks at 5, 10, 15, 20, 25, 30) and the y-axis
- "Temperature (°C)" with degree symbols from 5° to 30°. A vertical legend in the
- upper right shows "95% Prediction Interval" (blue) and "Forecast" (yellow). The
- y-axis has subtle dotted grid lines; x-axis grid is removed. Overall layout is
- clean with generous margins.
+ - Library mastery could be deeper — could leverage more Highcharts-specific features
+ like gradient fills or custom tooltip formatting
+ - Axis lines could be further minimized or removed for a more modern look
+ - Legend symbol (circle) does not perfectly represent the band series visually
+ image_description: The plot displays a 30-day temperature forecast as a band plot
+ on a clean white background. A semi-transparent light blue band (#306998 at 25%
+ opacity) represents the 95% prediction interval, stretching from approximately
+ 5°C to 28°C at its widest. A bold amber/gold center line (#C49000) traces the
+ forecast temperature, following a sinusoidal pattern with peaks near days 4 (~17°C)
+ and 20 (~22°C) and troughs near days 10 (~11.5°C) and 27 (~16°C). The band visibly
+ widens over time, illustrating increasing forecast uncertainty. The title reads
+ "30-Day Temperature Forecast · band-basic · highcharts · pyplots.ai" in bold at
+ the top, with a smaller subtitle "Daily forecast with 95% prediction interval."
+ The y-axis is labeled "Temperature (°C)" with degree-symbol tick labels every
+ 1°C from 5° to 30°, and uses subtle dotted gridlines at very low opacity. The
+ x-axis is labeled "Forecast Day" with ticks at intervals of 5. A floating legend
+ in the upper-right corner identifies "95% Prediction Interval" and "Forecast."
+ No content is cut off and the layout is well-balanced.
criteria_checklist:
visual_quality:
- score: 29
+ score: 30
max: 30
items:
- id: VQ-01
@@ -60,63 +63,66 @@ review:
max: 8
passed: true
comment: 'All font sizes explicitly set: title 48px, subtitle 30px, axis titles
- 36px, labels 28px, legend 28px'
+ 36px, tick labels 28px, legend 28px. All perfectly readable.'
- id: VQ-02
name: No Overlap
score: 6
max: 6
passed: true
- comment: No overlapping elements anywhere
+ comment: No overlapping text. Legend well-positioned in upper right, clear
+ of data. Axis labels well-spaced.
- id: VQ-03
name: Element Visibility
- score: 5
+ score: 6
max: 6
passed: true
- comment: Band visible at 0.25 opacity, yellow line has moderate contrast against
- light background
+ comment: Band clearly visible with semi-transparent fill. Center line at width
+ 5 is prominent. Smooth curves, no markers.
- id: VQ-04
name: Color Accessibility
score: 4
max: 4
passed: true
- comment: Blue-yellow scheme is colorblind-safe
+ comment: Blue and amber are colorblind-safe, distinguishable by hue and luminance.
+ No red-green dependency.
- id: VQ-05
name: Layout & Canvas
score: 4
max: 4
passed: true
- comment: Well-balanced margins, plot fills ~65% of canvas
+ comment: Chart fills ~65-70% of canvas. Balanced margins. No content cut off.
- id: VQ-06
name: Axis Labels & Title
score: 2
max: 2
passed: true
- comment: Temperature (°C) with units, Forecast Day descriptive
+ comment: 'Y-axis: Temperature (°C) with units. X-axis: Forecast Day. Tick
+ labels include degree symbols.'
design_excellence:
- score: 13
+ score: 14
max: 20
items:
- id: DE-01
name: Aesthetic Sophistication
- score: 5
+ score: 6
max: 8
passed: true
- comment: Intentional palette and font stack, above defaults but bright yellow
- is garish
+ comment: Harmonious cool/warm color pairing, custom font stack, clear typographic
+ hierarchy. Clearly above library defaults.
- id: DE-02
name: Visual Refinement
score: 4
max: 6
passed: true
- comment: Dotted y-axis-only grid, removed x-axis grid, subtle axis colors,
- markers disabled
+ comment: Dotted y-grid at low opacity, no x-grid, subtle axis lines, credits
+ disabled, no markers. Clean but axis lines present rather than removed.
- id: DE-03
name: Data Storytelling
score: 4
max: 6
passed: true
- comment: Widening prediction interval tells clear uncertainty story with visual
- hierarchy
+ comment: Widening band communicates increasing uncertainty over time. Warm/cool
+ color contrast creates visual hierarchy. Subtitle contextualizes the visualization.
spec_compliance:
score: 15
max: 15
@@ -126,27 +132,29 @@ review:
score: 5
max: 5
passed: true
- comment: Correct band plot using arearange + line series
+ comment: Correct band/area-range plot with AreaRangeSeries for band and LineSeries
+ for center line.
- id: SC-02
name: Required Features
score: 4
max: 4
passed: true
- comment: Semi-transparent fill, central line, smooth interpolation, uncertainty
- source in subtitle
+ comment: Semi-transparent fill at 0.25, contrasting center line, 30 data points,
+ smooth interpolation, uncertainty context.
- id: SC-03
name: Data Mapping
score: 3
max: 3
passed: true
- comment: X=days, band boundaries correct, center line correct
+ comment: X maps to days, Y maps to temperature. Full data range visible on
+ both axes.
- id: SC-04
name: Title & Legend
score: 3
max: 3
passed: true
- comment: Title format correct with descriptive prefix, legend labels match
- data
+ comment: Title includes band-basic · highcharts · pyplots.ai format. Legend
+ labels accurately describe series.
data_quality:
score: 15
max: 15
@@ -156,19 +164,22 @@ review:
score: 6
max: 6
passed: true
- comment: Shows widening uncertainty, sinusoidal variation with warming trend
+ comment: 'Shows all band plot features: filled region, varying band width,
+ center line, smooth data, multiple oscillation cycles.'
- id: DQ-02
name: Realistic Context
score: 5
max: 5
passed: true
- comment: Temperature forecasting is real-world neutral scenario
+ comment: Temperature forecasting with 95% prediction intervals is a genuine,
+ neutral, real-world scientific application.
- id: DQ-03
name: Appropriate Scale
score: 4
max: 4
passed: true
- comment: Temperatures 5-30°C realistic for 30-day forecast
+ comment: Temperatures 5-28°C realistic for temperate climate. 30-day period
+ standard. Uncertainty widths statistically plausible.
code_quality:
score: 10
max: 10
@@ -178,46 +189,51 @@ review:
score: 3
max: 3
passed: true
- comment: 'Linear flow: imports, data, chart options, HTML, screenshot'
+ comment: 'Linear script: imports, data generation, chart config, series, HTML
+ export, screenshot. No functions or classes.'
- id: CQ-02
name: Reproducibility
score: 2
max: 2
passed: true
- comment: np.random.seed(42) set
+ comment: np.random.seed(42) set at start for deterministic data generation.
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
- comment: All imports used
+ comment: 'All imports used: tempfile, time, urllib.request, Path, numpy, highcharts-core
+ classes, PIL, selenium.'
- id: CQ-04
name: Code Elegance
score: 2
max: 2
passed: true
- comment: Clean, well-organized, appropriate complexity
+ comment: Clean, well-organized. Appropriate complexity. Vectorized numpy operations
+ for data generation.
- id: CQ-05
name: Output & API
score: 1
max: 1
passed: true
- comment: Saves plot.png, uses current Highcharts v11.4
+ comment: Saves as plot.png. Uses current highcharts-core API. Proper temp
+ file cleanup.
library_mastery:
- score: 6
+ score: 7
max: 10
items:
- id: LM-01
name: Idiomatic Usage
- score: 3
+ score: 4
max: 5
- passed: false
- comment: Raw JSON dict approach instead of highcharts-core Python wrapper
+ passed: true
+ comment: 'Uses highcharts-core properly: Chart with container, HighchartsOptions,
+ typed series classes, plot_options, to_js_literal().'
- id: LM-02
name: Distinctive Features
score: 3
max: 5
passed: true
- comment: Uses Highcharts-specific arearange type with highcharts-more.js,
- series zIndex
- verdict: REJECTED
+ comment: Uses AreaRangeSeries, z_index layering, floating legend with transparency,
+ declarative plot_options. Leverages Highcharts strengths.
+ verdict: APPROVED