Skip to content

Commit 4f90b34

Browse files
feat(highcharts): implement box-horizontal (#2588)
## Implementation: `box-horizontal` - highcharts Implements the **highcharts** version of `box-horizontal`. **File:** `plots/box-horizontal/implementations/highcharts.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20593352509)* --------- 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 44cfd47 commit 4f90b34

2 files changed

Lines changed: 206 additions & 0 deletions

File tree

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
""" pyplots.ai
2+
box-horizontal: Horizontal Box 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.boxplot import BoxPlotSeries
16+
from selenium import webdriver
17+
from selenium.webdriver.chrome.options import Options
18+
19+
20+
# Data - Response times by service type (realistic scenario)
21+
np.random.seed(42)
22+
23+
categories = ["API Gateway", "Database Query", "File Upload", "Authentication", "Payment Processing"]
24+
25+
# Generate data with different distributions for each service
26+
# Each category needs: [low, q1, median, q3, high]
27+
data = []
28+
for cat in categories:
29+
if cat == "API Gateway":
30+
values = np.random.normal(50, 15, 200) # Fast, consistent
31+
elif cat == "Database Query":
32+
values = np.random.normal(120, 40, 200) # Moderate with variation
33+
elif cat == "File Upload":
34+
values = np.random.normal(250, 80, 200) # Slow, high variance
35+
elif cat == "Authentication":
36+
values = np.random.normal(30, 8, 200) # Very fast
37+
else: # Payment Processing
38+
values = np.random.normal(180, 50, 200) # Moderate-slow
39+
40+
# Ensure positive values
41+
values = np.maximum(values, 5)
42+
43+
# Calculate quartiles
44+
q1, median, q3 = np.percentile(values, [25, 50, 75])
45+
iqr = q3 - q1
46+
low = max(values.min(), q1 - 1.5 * iqr)
47+
high = min(values.max(), q3 + 1.5 * iqr)
48+
49+
# Data as list format for Highcharts boxplot: [low, q1, median, q3, high]
50+
data.append([round(low, 1), round(q1, 1), round(median, 1), round(q3, 1), round(high, 1)])
51+
52+
# Create chart with container specified
53+
chart = Chart(container="container")
54+
chart.options = HighchartsOptions()
55+
56+
# Chart configuration - use full 4800x2700 with proper margins
57+
chart.options.chart = {
58+
"type": "boxplot",
59+
"inverted": True, # This makes it horizontal
60+
"width": 4800,
61+
"height": 2700,
62+
"backgroundColor": "#ffffff",
63+
"marginLeft": 450, # Extra space for category labels and axis title
64+
"marginBottom": 220, # Extra space for value axis labels and title
65+
"marginTop": 180,
66+
"marginRight": 120,
67+
}
68+
69+
# Title
70+
chart.options.title = {
71+
"text": "box-horizontal · highcharts · pyplots.ai",
72+
"style": {"fontSize": "64px", "fontWeight": "bold"},
73+
"y": 60,
74+
}
75+
76+
# Subtitle for context
77+
chart.options.subtitle = {
78+
"text": "Response Time Distribution by Service Type",
79+
"style": {"fontSize": "42px", "color": "#666666"},
80+
"y": 120,
81+
}
82+
83+
# X-axis (categories - shown on left due to inverted)
84+
chart.options.x_axis = {
85+
"categories": categories,
86+
"title": {"text": "Service Type", "style": {"fontSize": "42px"}, "margin": 20},
87+
"labels": {"style": {"fontSize": "36px"}, "x": -10},
88+
"lineWidth": 2,
89+
"lineColor": "#333333",
90+
}
91+
92+
# Y-axis (values - shown on bottom due to inverted)
93+
chart.options.y_axis = {
94+
"title": {"text": "Response Time (ms)", "style": {"fontSize": "42px"}, "margin": 20},
95+
"labels": {"style": {"fontSize": "32px"}, "y": 30},
96+
"gridLineColor": "#e0e0e0",
97+
"gridLineWidth": 1,
98+
"min": 0,
99+
"lineWidth": 2,
100+
"lineColor": "#333333",
101+
}
102+
103+
# Legend
104+
chart.options.legend = {"enabled": False}
105+
106+
# Plot options for boxplot styling
107+
chart.options.plot_options = {
108+
"boxplot": {
109+
"fillColor": "rgba(48, 105, 152, 0.7)", # Python Blue with transparency
110+
"color": "#306998", # Box outline color
111+
"lineWidth": 4,
112+
"medianColor": "#FFD43B", # Python Yellow for median
113+
"medianWidth": 8,
114+
"stemColor": "#306998",
115+
"stemWidth": 4,
116+
"whiskerColor": "#306998",
117+
"whiskerLength": "40%",
118+
"whiskerWidth": 4,
119+
"pointWidth": 80,
120+
}
121+
}
122+
123+
# Create box plot series
124+
series = BoxPlotSeries()
125+
series.name = "Response Time"
126+
series.data = data
127+
128+
chart.add_series(series)
129+
130+
# Download Highcharts JS files (required for headless Chrome)
131+
highcharts_url = "https://code.highcharts.com/highcharts.js"
132+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
133+
highcharts_js = response.read().decode("utf-8")
134+
135+
# BoxPlot requires highcharts-more.js
136+
highcharts_more_url = "https://code.highcharts.com/highcharts-more.js"
137+
with urllib.request.urlopen(highcharts_more_url, timeout=30) as response:
138+
highcharts_more_js = response.read().decode("utf-8")
139+
140+
# Generate HTML with INLINE scripts
141+
html_str = chart.to_js_literal()
142+
html_content = f"""<!DOCTYPE html>
143+
<html>
144+
<head>
145+
<meta charset="utf-8">
146+
<script>{highcharts_js}</script>
147+
<script>{highcharts_more_js}</script>
148+
</head>
149+
<body style="margin:0; padding:0; overflow:hidden;">
150+
<div id="container" style="width: 4800px; height: 2700px;"></div>
151+
<script>{html_str}</script>
152+
</body>
153+
</html>"""
154+
155+
# Write temp HTML and take screenshot
156+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
157+
f.write(html_content)
158+
temp_path = f.name
159+
160+
# Also save HTML for interactive version
161+
with open("plot.html", "w", encoding="utf-8") as f:
162+
f.write(html_content)
163+
164+
chrome_options = Options()
165+
chrome_options.add_argument("--headless")
166+
chrome_options.add_argument("--no-sandbox")
167+
chrome_options.add_argument("--disable-dev-shm-usage")
168+
chrome_options.add_argument("--disable-gpu")
169+
chrome_options.add_argument("--window-size=4800,2700")
170+
chrome_options.add_argument("--force-device-scale-factor=1")
171+
172+
driver = webdriver.Chrome(options=chrome_options)
173+
driver.set_window_size(4800, 2700)
174+
driver.get(f"file://{temp_path}")
175+
time.sleep(5) # Wait for chart to render
176+
driver.save_screenshot("plot.png")
177+
driver.quit()
178+
179+
Path(temp_path).unlink() # Clean up temp file
180+
181+
print("Generated plot.png and plot.html")
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
library: highcharts
2+
specification_id: box-horizontal
3+
created: '2025-12-30T09:34:18Z'
4+
updated: '2025-12-30T09:44:33Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20593352509
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: unknown
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/box-horizontal/highcharts/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/box-horizontal/highcharts/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/box-horizontal/highcharts/plot.html
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent realistic data scenario using API response times by service type
17+
- Proper use of Highcharts inverted chart for horizontal orientation
18+
- Good color scheme with Python blue boxes and yellow median lines for contrast
19+
- Well-sized text elements readable at full resolution
20+
- Correct whisker calculation using 1.5*IQR methodology
21+
- Clean code structure following KISS principles
22+
weaknesses:
23+
- Data does not include explicit outlier points which would better demonstrate box
24+
plot capabilities
25+
- Vertical spacing between box plots could be tighter to reduce whitespace

0 commit comments

Comments
 (0)