Skip to content

Commit 64b16fa

Browse files
update(band-basic): highcharts — comprehensive quality review
Comprehensive quality review of highcharts band-basic implementation.
1 parent b634f35 commit 64b16fa

4 files changed

Lines changed: 82 additions & 65 deletions

File tree

Lines changed: 71 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
""" pyplots.ai
1+
"""pyplots.ai
22
band-basic: Basic Band Plot
3-
Library: highcharts unknown | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: highcharts 1.10.3 | Python 3.14
4+
Quality: /100 | Updated: 2026-02-23
55
"""
66

77
import json
@@ -16,22 +16,26 @@
1616
from selenium.webdriver.chrome.options import Options
1717

1818

19-
# Data - Time series with 95% confidence interval
19+
# Data - Daily temperature forecast with 95% prediction interval
2020
np.random.seed(42)
21-
x = np.linspace(0, 10, 50)
22-
# Central trend with sinusoidal pattern
23-
y_center = 50 + 20 * np.sin(x) + x * 2
24-
# Uncertainty increases with x (heteroscedastic)
25-
uncertainty = 3 + 0.5 * x
26-
# Upper and lower bounds
27-
y_lower = y_center - 1.96 * uncertainty
28-
y_upper = y_center + 1.96 * uncertainty
21+
days = np.arange(1, 31)
22+
# Central forecast: warming trend with daily variation
23+
temp_center = 12 + 0.3 * days + 4 * np.sin(days * 0.4)
24+
# Prediction uncertainty widens over the forecast horizon
25+
uncertainty = 1.5 + 0.08 * days
26+
temp_lower = temp_center - 1.96 * uncertainty
27+
temp_upper = temp_center + 1.96 * uncertainty
2928

3029
# Prepare data for Highcharts
3130
# arearange series expects [[x, low, high], ...]
32-
band_data = [[float(xi), float(lo), float(hi)] for xi, lo, hi in zip(x, y_lower, y_upper, strict=True)]
31+
band_data = [
32+
[int(d), round(float(lo), 1), round(float(hi), 1)] for d, lo, hi in zip(days, temp_lower, temp_upper, strict=True)
33+
]
3334
# line series expects [[x, y], ...]
34-
line_data = [[float(xi), float(yi)] for xi, yi in zip(x, y_center, strict=True)]
35+
line_data = [[int(d), round(float(t), 1)] for d, t in zip(days, temp_center, strict=True)]
36+
37+
# Font stack
38+
font_family = "'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
3539

3640
# Chart options using arearange for band and line for center
3741
chart_options = {
@@ -40,70 +44,84 @@
4044
"height": 2700,
4145
"backgroundColor": "#ffffff",
4246
"marginBottom": 180,
43-
"marginLeft": 200,
47+
"marginLeft": 220,
4448
"marginRight": 100,
45-
"style": {"fontFamily": "Arial, sans-serif"},
49+
"spacing": [40, 40, 40, 40],
50+
"style": {"fontFamily": font_family},
51+
},
52+
"title": {
53+
"text": "30-Day Temperature Forecast \u00b7 band-basic \u00b7 highcharts \u00b7 pyplots.ai",
54+
"style": {"fontSize": "48px", "fontWeight": "bold", "fontFamily": font_family},
55+
},
56+
"subtitle": {
57+
"text": "Daily forecast with 95% prediction interval",
58+
"style": {"fontSize": "30px", "color": "#555555", "fontFamily": font_family},
4659
},
47-
"title": {"text": "band-basic · highcharts · pyplots.ai", "style": {"fontSize": "64px", "fontWeight": "bold"}},
48-
"subtitle": {"text": "Time series with 95% confidence interval", "style": {"fontSize": "38px", "color": "#666666"}},
4960
"xAxis": {
50-
"title": {"text": "Time", "style": {"fontSize": "48px"}, "margin": 20},
51-
"labels": {"style": {"fontSize": "36px"}},
52-
"gridLineWidth": 1,
53-
"gridLineColor": "rgba(0, 0, 0, 0.1)",
54-
"gridLineDashStyle": "Dash",
55-
"tickInterval": 1,
61+
"title": {"text": "Forecast Day", "style": {"fontSize": "36px", "fontFamily": font_family}, "margin": 20},
62+
"labels": {"style": {"fontSize": "28px", "fontFamily": font_family}},
63+
"gridLineWidth": 0,
64+
"tickInterval": 5,
65+
"lineColor": "#cccccc",
66+
"tickColor": "#cccccc",
5667
},
5768
"yAxis": {
58-
"title": {"text": "Value", "style": {"fontSize": "48px"}, "margin": 20},
59-
"labels": {"style": {"fontSize": "36px"}},
69+
"title": {
70+
"text": "Temperature (\u00b0C)",
71+
"style": {"fontSize": "36px", "fontFamily": font_family},
72+
"margin": 20,
73+
},
74+
"labels": {"format": "{value}\u00b0", "style": {"fontSize": "28px", "fontFamily": font_family}},
6075
"gridLineWidth": 1,
61-
"gridLineColor": "rgba(0, 0, 0, 0.1)",
62-
"gridLineDashStyle": "Dash",
76+
"gridLineColor": "rgba(0, 0, 0, 0.08)",
77+
"gridLineDashStyle": "Dot",
78+
"lineColor": "#cccccc",
79+
"lineWidth": 1,
6380
},
6481
"legend": {
6582
"enabled": True,
6683
"align": "right",
6784
"verticalAlign": "top",
6885
"layout": "vertical",
69-
"x": -50,
70-
"y": 100,
71-
"itemStyle": {"fontSize": "36px"},
86+
"x": -40,
87+
"y": 80,
88+
"itemStyle": {"fontSize": "28px", "fontFamily": font_family},
7289
},
7390
"plotOptions": {
74-
"arearange": {"fillOpacity": 0.3, "lineWidth": 0, "marker": {"enabled": False}},
75-
"line": {"lineWidth": 6, "marker": {"enabled": False}},
91+
"arearange": {"fillOpacity": 0.25, "lineWidth": 0, "marker": {"enabled": False}},
92+
"line": {"lineWidth": 5, "marker": {"enabled": False}},
7693
},
7794
"series": [
7895
{
79-
"name": "95% Confidence Interval",
96+
"name": "95% Prediction Interval",
8097
"type": "arearange",
8198
"data": band_data,
8299
"color": "#306998",
83-
"fillOpacity": 0.3,
100+
"fillOpacity": 0.25,
84101
"zIndex": 0,
85102
},
86-
{"name": "Mean Value", "type": "line", "data": line_data, "color": "#FFD43B", "lineWidth": 6, "zIndex": 1},
103+
{"name": "Forecast", "type": "line", "data": line_data, "color": "#FFD43B", "lineWidth": 5, "zIndex": 1},
87104
],
105+
"credits": {"enabled": False},
88106
}
89107

90-
# Download Highcharts JS and highcharts-more (needed for arearange)
91-
highcharts_url = "https://code.highcharts.com/highcharts.js"
92-
highcharts_more_url = "https://code.highcharts.com/highcharts-more.js"
93-
94-
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
95-
highcharts_js = response.read().decode("utf-8")
96-
with urllib.request.urlopen(highcharts_more_url, timeout=30) as response:
97-
highcharts_more_js = response.read().decode("utf-8")
108+
# Download Highcharts JS files (jsDelivr CDN with version pin)
109+
cdn_base = "https://cdn.jsdelivr.net/npm/highcharts@11.4"
110+
js_urls = {"highcharts": f"{cdn_base}/highcharts.js", "highcharts_more": f"{cdn_base}/highcharts-more.js"}
111+
js_modules = {}
112+
for name, url in js_urls.items():
113+
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
114+
with urllib.request.urlopen(req, timeout=30) as response:
115+
js_modules[name] = response.read().decode("utf-8")
98116

99117
# Generate HTML with inline scripts
100118
chart_options_json = json.dumps(chart_options)
101119
html_content = f"""<!DOCTYPE html>
102120
<html>
103121
<head>
104122
<meta charset="utf-8">
105-
<script>{highcharts_js}</script>
106-
<script>{highcharts_more_js}</script>
123+
<script>{js_modules["highcharts"]}</script>
124+
<script>{js_modules["highcharts_more"]}</script>
107125
</head>
108126
<body style="margin:0;">
109127
<div id="container" style="width: 4800px; height: 2700px;"></div>
@@ -120,33 +138,28 @@
120138
f.write(html_content)
121139
temp_path = f.name
122140

123-
# Also save the HTML for interactive viewing
141+
# Save HTML for interactive viewing
124142
with open("plot.html", "w", encoding="utf-8") as f:
125143
f.write(html_content)
126144

127145
# Take screenshot with headless Chrome
128146
chrome_options = Options()
129-
chrome_options.add_argument("--headless=new")
147+
chrome_options.add_argument("--headless")
130148
chrome_options.add_argument("--no-sandbox")
131149
chrome_options.add_argument("--disable-dev-shm-usage")
132150
chrome_options.add_argument("--disable-gpu")
133-
chrome_options.add_argument("--force-device-scale-factor=1")
151+
chrome_options.add_argument("--window-size=4800,2900")
134152

135153
driver = webdriver.Chrome(options=chrome_options)
136-
driver.set_window_size(4900, 2900)
137154
driver.get(f"file://{temp_path}")
138155
time.sleep(5)
139-
140-
# Take screenshot
141156
driver.save_screenshot("plot_raw.png")
142157
driver.quit()
143158

144-
# Crop/resize to exact 4800x2700 using PIL
159+
# Crop to exact 4800x2700 dimensions
145160
img = Image.open("plot_raw.png")
146-
final_img = Image.new("RGB", (4800, 2700), (255, 255, 255))
147-
final_img.paste(img.crop((0, 0, min(img.width, 4800), min(img.height, 2700))), (0, 0))
148-
final_img.save("plot.png")
149-
150-
# Clean up
161+
img_cropped = img.crop((0, 0, 4800, 2700))
162+
img_cropped.save("plot.png")
151163
Path("plot_raw.png").unlink()
164+
152165
Path(temp_path).unlink()

plots/band-basic/metadata/highcharts.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
library: highcharts
22
specification_id: band-basic
33
created: '2025-12-23T09:09:27Z'
4-
updated: '2025-12-23T09:11:45Z'
5-
generated_by: claude-opus-4-5-20251101
4+
updated: '2026-02-23T13:41:00Z'
5+
generated_by: claude-opus-4-6
66
workflow_run: 20456388074
77
issue: 0
8-
python_version: 3.13.11
9-
library_version: unknown
8+
python_version: '3.14'
9+
library_version: 1.10.3
1010
preview_url: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.png
1111
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot_thumb.png
1212
preview_html: https://storage.googleapis.com/pyplots-images/plots/band-basic/highcharts/plot.html
13-
quality_score: 92
13+
quality_score: null
1414
impl_tags:
1515
dependencies:
1616
- pillow

plots/band-basic/specification.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ A band plot displays a filled region between two boundary lines, commonly used t
1616
- `x` (numeric) - Independent variable, often representing time or sequence
1717
- `y_lower` (numeric) - Lower boundary values defining the bottom of the band
1818
- `y_upper` (numeric) - Upper boundary values defining the top of the band
19-
- `y_center` (numeric, optional) - Central trend line values (mean/median)
19+
- `y_center` (numeric) - Central trend line values (mean/median), shown as a contrasting line
2020
- Size: 20-200 data points
2121
- Example: Time series with 95% confidence interval bounds
2222

plots/band-basic/specification.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ title: Basic Band Plot
66

77
# Specification tracking
88
created: 2025-12-15T20:42:54Z
9-
updated: 2025-12-15T20:42:54Z
9+
updated: 2026-02-23T12:00:00Z
1010
issue: 979
1111
suggested: MarkusNeusinger
1212

@@ -18,10 +18,14 @@ tags:
1818
data_type:
1919
- numeric
2020
- continuous
21+
- timeseries
2122
domain:
2223
- statistics
2324
- science
25+
- general
26+
- engineering
2427
features:
2528
- basic
2629
- confidence-interval
2730
- uncertainty
31+
- 2d

0 commit comments

Comments
 (0)