Skip to content

Commit 17fdb60

Browse files
feat(highcharts): implement point-basic (#2584)
## Implementation: `point-basic` - highcharts Implements the **highcharts** version of `point-basic`. **File:** `plots/point-basic/implementations/highcharts.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20593353051)* --------- 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 6a0e89b commit 17fdb60

2 files changed

Lines changed: 214 additions & 0 deletions

File tree

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
""" pyplots.ai
2+
point-basic: Point Estimate Plot
3+
Library: highcharts unknown | Python 3.13.11
4+
Quality: 92/100 | Created: 2025-12-30
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 highcharts_core.options.series.scatter import ScatterSeries
17+
from selenium import webdriver
18+
from selenium.webdriver.chrome.options import Options
19+
20+
21+
# Data - Performance metrics by department with confidence intervals
22+
np.random.seed(42)
23+
categories = ["Marketing", "Engineering", "Sales", "Operations", "Finance", "HR", "Research", "Customer Support"]
24+
estimates = np.array([72, 85, 68, 79, 74, 66, 88, 71])
25+
# Generate asymmetric confidence intervals
26+
lower_errors = np.random.uniform(3, 8, len(categories))
27+
upper_errors = np.random.uniform(3, 8, len(categories))
28+
lower = estimates - lower_errors
29+
upper = estimates + upper_errors
30+
31+
# Create chart with container (CRITICAL for rendering)
32+
chart = Chart(container="container")
33+
chart.options = HighchartsOptions()
34+
35+
# Chart configuration
36+
chart.options.chart = {
37+
"type": "scatter",
38+
"width": 4800,
39+
"height": 2700,
40+
"backgroundColor": "#ffffff",
41+
"marginLeft": 280,
42+
"marginBottom": 250,
43+
"marginRight": 100,
44+
"marginTop": 150,
45+
"inverted": True, # Horizontal orientation for reading category labels
46+
}
47+
48+
# Title
49+
chart.options.title = {
50+
"text": "point-basic · highcharts · pyplots.ai",
51+
"style": {"fontSize": "48px", "fontWeight": "bold"},
52+
}
53+
54+
# Subtitle
55+
chart.options.subtitle = {
56+
"text": "Department Performance Scores with 95% Confidence Intervals",
57+
"style": {"fontSize": "32px"},
58+
}
59+
60+
# X-axis (categories - appears on left due to inverted)
61+
chart.options.x_axis = {
62+
"categories": list(categories),
63+
"title": {"text": "Department", "style": {"fontSize": "36px"}},
64+
"labels": {"style": {"fontSize": "28px"}},
65+
"lineWidth": 2,
66+
"lineColor": "#333333",
67+
}
68+
69+
# Y-axis (values - appears on bottom due to inverted)
70+
chart.options.y_axis = {
71+
"title": {"text": "Performance Score", "style": {"fontSize": "36px"}, "margin": 20},
72+
"labels": {"style": {"fontSize": "24px"}},
73+
"min": 50,
74+
"max": 100,
75+
"gridLineWidth": 1,
76+
"gridLineColor": "#e0e0e0",
77+
"plotLines": [{"value": 75, "color": "#666666", "width": 3, "dashStyle": "Dash", "zIndex": 5}],
78+
}
79+
80+
# Legend
81+
chart.options.legend = {
82+
"enabled": True,
83+
"itemStyle": {"fontSize": "28px"},
84+
"layout": "horizontal",
85+
"align": "center",
86+
"verticalAlign": "bottom",
87+
"y": 20,
88+
}
89+
90+
# Error bar series (confidence intervals) using columnrange
91+
error_data = []
92+
for i in range(len(categories)):
93+
error_data.append({"x": i, "low": float(lower[i]), "high": float(upper[i])})
94+
95+
error_series = ColumnRangeSeries()
96+
error_series.name = "95% CI"
97+
error_series.data = error_data
98+
error_series.color = "#306998"
99+
error_series.border_width = 0
100+
error_series.point_width = 8
101+
102+
chart.add_series(error_series)
103+
104+
# Point estimate series (scatter points)
105+
point_data = []
106+
for i in range(len(categories)):
107+
point_data.append({"x": i, "y": float(estimates[i])})
108+
109+
point_series = ScatterSeries()
110+
point_series.name = "Point Estimate"
111+
point_series.data = point_data
112+
point_series.color = "#FFD43B"
113+
point_series.marker = {"radius": 16, "symbol": "circle", "lineWidth": 3, "lineColor": "#306998", "fillColor": "#FFD43B"}
114+
115+
chart.add_series(point_series)
116+
117+
# Plot options
118+
chart.options.plot_options = {
119+
"series": {"animation": False},
120+
"scatter": {"marker": {"radius": 16, "states": {"hover": {"enabled": False}}}},
121+
"columnrange": {"groupPadding": 0, "pointPadding": 0},
122+
}
123+
124+
# Credits
125+
chart.options.credits = {"enabled": False}
126+
127+
# Download Highcharts JS (required for headless Chrome)
128+
highcharts_url = "https://code.highcharts.com/highcharts.js"
129+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
130+
highcharts_js = response.read().decode("utf-8")
131+
132+
# Download highcharts-more.js for columnrange
133+
highcharts_more_url = "https://code.highcharts.com/highcharts-more.js"
134+
with urllib.request.urlopen(highcharts_more_url, timeout=30) as response:
135+
highcharts_more_js = response.read().decode("utf-8")
136+
137+
# Generate HTML with INLINE scripts
138+
html_str = chart.to_js_literal()
139+
html_content = f"""<!DOCTYPE html>
140+
<html>
141+
<head>
142+
<meta charset="utf-8">
143+
<script>{highcharts_js}</script>
144+
<script>{highcharts_more_js}</script>
145+
</head>
146+
<body style="margin:0;">
147+
<div id="container" style="width: 4800px; height: 2700px;"></div>
148+
<script>{html_str}</script>
149+
</body>
150+
</html>"""
151+
152+
# Write temp HTML and take screenshot
153+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
154+
f.write(html_content)
155+
temp_path = f.name
156+
157+
chrome_options = Options()
158+
chrome_options.add_argument("--headless")
159+
chrome_options.add_argument("--no-sandbox")
160+
chrome_options.add_argument("--disable-dev-shm-usage")
161+
chrome_options.add_argument("--disable-gpu")
162+
chrome_options.add_argument("--window-size=4800,2700")
163+
164+
driver = webdriver.Chrome(options=chrome_options)
165+
driver.get(f"file://{temp_path}")
166+
time.sleep(5) # Wait for chart to render
167+
driver.save_screenshot("plot.png")
168+
driver.quit()
169+
170+
Path(temp_path).unlink() # Clean up temp file
171+
172+
# Save HTML for interactive version (use CDN links for the HTML file)
173+
html_interactive = f"""<!DOCTYPE html>
174+
<html>
175+
<head>
176+
<meta charset="utf-8">
177+
<script src="https://code.highcharts.com/highcharts.js"></script>
178+
<script src="https://code.highcharts.com/highcharts-more.js"></script>
179+
</head>
180+
<body style="margin:0;">
181+
<div id="container" style="width: 100%; height: 100vh;"></div>
182+
<script>{html_str}</script>
183+
</body>
184+
</html>"""
185+
186+
with open("plot.html", "w", encoding="utf-8") as f:
187+
f.write(html_interactive)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library: highcharts
2+
specification_id: point-basic
3+
created: '2025-12-30T09:33:15Z'
4+
updated: '2025-12-30T09:44:06Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20593353051
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: unknown
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/point-basic/highcharts/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/point-basic/highcharts/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/point-basic/highcharts/plot.html
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent horizontal orientation for category readability
17+
- Clear point estimates with distinct yellow markers and blue confidence interval
18+
bars
19+
- Reference line at 75 adds valuable context for interpretation
20+
- Good use of Highcharts columnrange for confidence intervals combined with scatter
21+
for points
22+
- Colorblind-safe color scheme (blue/yellow)
23+
- Realistic business scenario with department performance scores
24+
- Proper title format following spec-id · library · pyplots.ai convention
25+
weaknesses:
26+
- Confidence intervals lack endpoint caps as mentioned in specification notes
27+
- Legend could be positioned closer to the plot area for better visual cohesion

0 commit comments

Comments
 (0)