Skip to content

Commit 7db4cb4

Browse files
feat(highcharts): implement range-interval (#3603)
## Implementation: `range-interval` - highcharts Implements the **highcharts** version of `range-interval`. **File:** `plots/range-interval/implementations/highcharts.py` **Parent Issue:** #3577 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20868895916)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent b412f22 commit 7db4cb4

File tree

2 files changed

+353
-0
lines changed

2 files changed

+353
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
""" pyplots.ai
2+
range-interval: Range Interval Chart
3+
Library: highcharts unknown | Python 3.13.11
4+
Quality: 92/100 | Created: 2026-01-09
5+
"""
6+
7+
import tempfile
8+
import time
9+
import urllib.request
10+
from pathlib import Path
11+
12+
import numpy as np
13+
from highcharts_core.chart import Chart
14+
from highcharts_core.options import HighchartsOptions
15+
from highcharts_core.options.series.bar import ColumnRangeSeries
16+
from selenium import webdriver
17+
from selenium.webdriver.chrome.options import Options
18+
19+
20+
# Data: Monthly temperature ranges for a temperate city
21+
np.random.seed(42)
22+
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
23+
24+
# Realistic temperature pattern (Northern Hemisphere temperate climate)
25+
base_lows = [-2, -1, 3, 7, 12, 16, 18, 17, 13, 8, 3, -1]
26+
base_highs = [5, 7, 12, 17, 22, 26, 29, 28, 23, 16, 10, 6]
27+
28+
# Add slight variation
29+
min_temps = [low + np.random.uniform(-1, 1) for low in base_lows]
30+
max_temps = [high + np.random.uniform(-1, 1) for high in base_highs]
31+
32+
# Create chart with container specified
33+
chart = Chart(container="container")
34+
chart.options = HighchartsOptions()
35+
36+
# Chart configuration for 4800x2700 canvas
37+
chart.options.chart = {
38+
"type": "columnrange",
39+
"inverted": False,
40+
"width": 4800,
41+
"height": 2700,
42+
"backgroundColor": "#ffffff",
43+
"marginBottom": 200,
44+
"marginLeft": 150,
45+
"style": {"fontFamily": "Arial, sans-serif"},
46+
}
47+
48+
# Title
49+
chart.options.title = {
50+
"text": "range-interval · highcharts · pyplots.ai",
51+
"style": {"fontSize": "48px", "fontWeight": "bold"},
52+
}
53+
54+
# Subtitle for context
55+
chart.options.subtitle = {"text": "Monthly Temperature Ranges (°C)", "style": {"fontSize": "32px"}}
56+
57+
# X-axis (categories)
58+
chart.options.x_axis = {
59+
"categories": months,
60+
"title": {"text": "Month", "style": {"fontSize": "36px"}, "margin": 20},
61+
"labels": {"style": {"fontSize": "32px"}, "y": 40},
62+
"crosshair": True,
63+
}
64+
65+
# Y-axis (temperature values)
66+
chart.options.y_axis = {
67+
"title": {"text": "Temperature (°C)", "style": {"fontSize": "36px"}, "margin": 20},
68+
"labels": {"style": {"fontSize": "28px"}},
69+
"gridLineWidth": 1,
70+
"gridLineColor": "#e0e0e0",
71+
}
72+
73+
# Plot options for column range
74+
chart.options.plot_options = {
75+
"columnrange": {
76+
"borderRadius": 3,
77+
"dataLabels": {
78+
"enabled": True,
79+
"format": "{y}°C",
80+
"style": {"fontSize": "18px", "fontWeight": "normal", "textOutline": "none"},
81+
},
82+
}
83+
}
84+
85+
# Legend configuration
86+
chart.options.legend = {"enabled": True, "itemStyle": {"fontSize": "24px"}, "verticalAlign": "top", "align": "right"}
87+
88+
# Tooltip configuration
89+
chart.options.tooltip = {"valueSuffix": "°C", "style": {"fontSize": "20px"}}
90+
91+
# Create the column range series
92+
series = ColumnRangeSeries()
93+
series.name = "Temperature Range"
94+
series.color = "#306998" # Python Blue
95+
96+
# Data format for columnrange: [[low, high], [low, high], ...]
97+
series.data = [[round(min_temps[i], 1), round(max_temps[i], 1)] for i in range(len(months))]
98+
99+
chart.add_series(series)
100+
101+
# Download Highcharts JS (required for headless Chrome)
102+
highcharts_url = "https://code.highcharts.com/highcharts.js"
103+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
104+
highcharts_js = response.read().decode("utf-8")
105+
106+
# Download highcharts-more.js for columnrange support
107+
highcharts_more_url = "https://code.highcharts.com/highcharts-more.js"
108+
with urllib.request.urlopen(highcharts_more_url, timeout=30) as response:
109+
highcharts_more_js = response.read().decode("utf-8")
110+
111+
# Generate HTML with inline scripts
112+
html_str = chart.to_js_literal()
113+
html_content = f"""<!DOCTYPE html>
114+
<html>
115+
<head>
116+
<meta charset="utf-8">
117+
<script>{highcharts_js}</script>
118+
<script>{highcharts_more_js}</script>
119+
</head>
120+
<body style="margin:0;">
121+
<div id="container" style="width: 4800px; height: 2700px;"></div>
122+
<script>{html_str}</script>
123+
</body>
124+
</html>"""
125+
126+
# Write temp HTML and take screenshot
127+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
128+
f.write(html_content)
129+
temp_path = f.name
130+
131+
chrome_options = Options()
132+
chrome_options.add_argument("--headless")
133+
chrome_options.add_argument("--no-sandbox")
134+
chrome_options.add_argument("--disable-dev-shm-usage")
135+
chrome_options.add_argument("--disable-gpu")
136+
chrome_options.add_argument("--window-size=4800,2800")
137+
138+
driver = webdriver.Chrome(options=chrome_options)
139+
driver.get(f"file://{temp_path}")
140+
time.sleep(5) # Wait for chart to render
141+
driver.save_screenshot("plot.png")
142+
driver.quit()
143+
144+
Path(temp_path).unlink() # Clean up temp file
145+
146+
# Also save HTML for interactive viewing
147+
with open("plot.html", "w", encoding="utf-8") as f:
148+
f.write(html_content)
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
library: highcharts
2+
specification_id: range-interval
3+
created: '2026-01-09T23:56:24Z'
4+
updated: '2026-01-10T00:01:11Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20868895916
7+
issue: 3577
8+
python_version: 3.13.11
9+
library_version: unknown
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/range-interval/highcharts/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/range-interval/highcharts/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/range-interval/highcharts/plot.html
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent implementation of columnrange chart type perfectly matching the spec
17+
- Clear seasonal temperature pattern with realistic Northern Hemisphere data
18+
- Clean code structure following KISS principles with proper seed for reproducibility
19+
- Good use of data labels showing min/max values at bar endpoints for emphasis
20+
- Proper handling of Highcharts modules (highcharts-more.js for columnrange support)
21+
weaknesses:
22+
- Legend positioned in top-right corner isolated from the chart area
23+
- Data labels font size (18px) could be slightly larger for better readability on
24+
the large canvas
25+
image_description: 'The plot displays a column range chart showing monthly temperature
26+
ranges for a temperate climate. Each month (Jan-Dec) is represented on the x-axis
27+
with a vertical blue bar (#306998) spanning from the minimum to maximum temperature.
28+
Data labels at the top and bottom of each bar show the exact temperature values
29+
in °C. The chart follows a realistic seasonal pattern: cold winters (Jan at -2.3°C
30+
to 5.7°C), warming spring, hot summers (Jul peaks at 17.1°C to 28.9°C), and cooling
31+
autumn. The title "range-interval · highcharts · pyplots.ai" is at the top with
32+
subtitle "Monthly Temperature Ranges (°C)". Y-axis shows "Temperature (°C)" and
33+
x-axis shows "Month". A legend "Temperature Range" appears in the top right. The
34+
layout is clean with subtle grid lines and good use of canvas space.'
35+
criteria_checklist:
36+
visual_quality:
37+
score: 37
38+
max: 40
39+
items:
40+
- id: VQ-01
41+
name: Text Legibility
42+
score: 10
43+
max: 10
44+
passed: true
45+
comment: Title, axis labels, tick labels, and data labels all clearly readable
46+
at full size
47+
- id: VQ-02
48+
name: No Overlap
49+
score: 8
50+
max: 8
51+
passed: true
52+
comment: No overlapping text elements, data labels well positioned
53+
- id: VQ-03
54+
name: Element Visibility
55+
score: 8
56+
max: 8
57+
passed: true
58+
comment: Column range bars appropriately sized for 12 categories, good visual
59+
weight
60+
- id: VQ-04
61+
name: Color Accessibility
62+
score: 5
63+
max: 5
64+
passed: true
65+
comment: Single color scheme (#306998 Python blue), no accessibility issues
66+
- id: VQ-05
67+
name: Layout Balance
68+
score: 4
69+
max: 5
70+
passed: true
71+
comment: Good canvas utilization, minor excess whitespace at top
72+
- id: VQ-06
73+
name: Axis Labels
74+
score: 2
75+
max: 2
76+
passed: true
77+
comment: Y-axis has Temperature (°C) with units, X-axis has Month
78+
- id: VQ-07
79+
name: Grid & Legend
80+
score: 0
81+
max: 2
82+
passed: false
83+
comment: Legend placed far from chart in corner, grid is acceptable
84+
spec_compliance:
85+
score: 25
86+
max: 25
87+
items:
88+
- id: SC-01
89+
name: Plot Type
90+
score: 8
91+
max: 8
92+
passed: true
93+
comment: Correct columnrange chart type showing min-max ranges
94+
- id: SC-02
95+
name: Data Mapping
96+
score: 5
97+
max: 5
98+
passed: true
99+
comment: Categories on X-axis, temperature ranges on Y-axis correctly mapped
100+
- id: SC-03
101+
name: Required Features
102+
score: 5
103+
max: 5
104+
passed: true
105+
comment: Shows full span between values, data labels at endpoints for emphasis
106+
- id: SC-04
107+
name: Data Range
108+
score: 3
109+
max: 3
110+
passed: true
111+
comment: Y-axis properly shows full range from -4 to 31°C
112+
- id: SC-05
113+
name: Legend Accuracy
114+
score: 2
115+
max: 2
116+
passed: true
117+
comment: Legend label Temperature Range is accurate
118+
- id: SC-06
119+
name: Title Format
120+
score: 2
121+
max: 2
122+
passed: true
123+
comment: Uses correct format range-interval · highcharts · pyplots.ai
124+
data_quality:
125+
score: 18
126+
max: 20
127+
items:
128+
- id: DQ-01
129+
name: Feature Coverage
130+
score: 7
131+
max: 8
132+
passed: true
133+
comment: Shows seasonal variation with different range sizes, but ranges are
134+
fairly uniform in width
135+
- id: DQ-02
136+
name: Realistic Context
137+
score: 7
138+
max: 7
139+
passed: true
140+
comment: Monthly temperature ranges for Northern Hemisphere temperate city
141+
is realistic and neutral
142+
- id: DQ-03
143+
name: Appropriate Scale
144+
score: 4
145+
max: 5
146+
passed: true
147+
comment: Values are realistic (-2°C to 29°C), though summer ranges could show
148+
more variation
149+
code_quality:
150+
score: 9
151+
max: 10
152+
items:
153+
- id: CQ-01
154+
name: KISS Structure
155+
score: 3
156+
max: 3
157+
passed: true
158+
comment: 'Simple linear structure: imports, data, chart config, export'
159+
- id: CQ-02
160+
name: Reproducibility
161+
score: 3
162+
max: 3
163+
passed: true
164+
comment: Uses np.random.seed(42)
165+
- id: CQ-03
166+
name: Clean Imports
167+
score: 2
168+
max: 2
169+
passed: true
170+
comment: All imports are used
171+
- id: CQ-04
172+
name: No Deprecated API
173+
score: 1
174+
max: 1
175+
passed: true
176+
comment: Modern Highcharts API usage
177+
- id: CQ-05
178+
name: Output Correct
179+
score: 0
180+
max: 1
181+
passed: false
182+
comment: Saves as plot.png but also saves plot.html (extra file)
183+
library_features:
184+
score: 3
185+
max: 5
186+
items:
187+
- id: LF-01
188+
name: Distinctive Features
189+
score: 3
190+
max: 5
191+
passed: true
192+
comment: Uses ColumnRangeSeries, data labels, inline JS embedding for Selenium
193+
export. Could leverage more interactive features.
194+
verdict: APPROVED
195+
impl_tags:
196+
dependencies:
197+
- selenium
198+
techniques:
199+
- annotations
200+
- html-export
201+
patterns:
202+
- data-generation
203+
dataprep: []
204+
styling:
205+
- grid-styling

0 commit comments

Comments
 (0)