Skip to content

Commit d368a92

Browse files
feat(highcharts): implement bar-diverging (#6033)
## Implementation: `bar-diverging` - python/highcharts Implements the **python/highcharts** version of `bar-diverging`. **File:** `plots/bar-diverging/implementations/python/highcharts.py` **Parent Issue:** #2009 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25546752765)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 1c160c3 commit d368a92

2 files changed

Lines changed: 206 additions & 150 deletions

File tree

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
bar-diverging: Diverging Bar Chart
3-
Library: highcharts unknown | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-25
3+
Library: highcharts unknown | Python 3.13.13
4+
Quality: 90/100 | Updated: 2026-05-08
55
"""
66

7+
import os
78
import tempfile
89
import time
910
import urllib.request
@@ -14,9 +15,20 @@
1415
from highcharts_core.options.series.bar import BarSeries
1516
from selenium import webdriver
1617
from selenium.webdriver.chrome.options import Options
17-
from selenium.webdriver.common.by import By
1818

1919

20+
# Theme-adaptive chrome tokens
21+
THEME = os.getenv("ANYPLOT_THEME", "light")
22+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
23+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
24+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
25+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
26+
GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
27+
28+
# Okabe-Ito palette
29+
POSITIVE = "#009E73" # bluish green (brand, position 1)
30+
NEGATIVE = "#D55E00" # vermillion (position 2)
31+
2032
# Data - Customer satisfaction survey results by department
2133
categories = [
2234
"Customer Service",
@@ -35,7 +47,7 @@
3547
values = [45, 32, 28, 15, 8, -5, -12, -18, -25, -38]
3648

3749
# Separate positive and negative for different colors
38-
positive_data = [{"y": v, "color": "#306998"} if v >= 0 else {"y": v, "color": "#FFD43B"} for v in values]
50+
positive_data = [{"y": v, "color": POSITIVE} if v >= 0 else {"y": v, "color": NEGATIVE} for v in values]
3951

4052
# Create chart
4153
chart = Chart(container="container")
@@ -46,35 +58,33 @@
4658
"type": "bar",
4759
"width": 4800,
4860
"height": 2700,
49-
"backgroundColor": "#ffffff",
61+
"backgroundColor": PAGE_BG,
5062
"marginLeft": 280,
5163
"marginRight": 100,
5264
}
5365

5466
# Title
55-
chart.options.title = {
56-
"text": "bar-diverging · highcharts · pyplots.ai",
57-
"style": {"fontSize": "48px", "fontWeight": "bold"},
58-
}
59-
60-
chart.options.subtitle = {"text": "Department Net Satisfaction Scores", "style": {"fontSize": "32px"}}
67+
chart.options.title = {"text": "bar-diverging · highcharts · anyplot.ai", "style": {"fontSize": "28px", "color": INK}}
6168

6269
# X-axis (categories)
6370
chart.options.x_axis = {
6471
"categories": categories,
6572
"title": {"text": None},
66-
"labels": {"style": {"fontSize": "28px"}},
67-
"lineWidth": 0,
68-
"tickWidth": 0,
73+
"labels": {"style": {"fontSize": "18px", "color": INK_SOFT}},
74+
"lineColor": INK_SOFT,
75+
"tickColor": INK_SOFT,
76+
"gridLineColor": GRID,
6977
}
7078

7179
# Y-axis (values) - note: in horizontal bar, y_axis shows values
7280
chart.options.y_axis = {
73-
"title": {"text": "Net Satisfaction Score", "style": {"fontSize": "28px"}, "margin": 20},
74-
"labels": {"style": {"fontSize": "24px"}},
81+
"title": {"text": "Net Satisfaction Score", "style": {"fontSize": "22px", "color": INK}},
82+
"labels": {"style": {"fontSize": "18px", "color": INK_SOFT}},
83+
"lineColor": INK_SOFT,
84+
"tickColor": INK_SOFT,
85+
"gridLineColor": GRID,
7586
"gridLineWidth": 1,
76-
"gridLineColor": "#e0e0e0",
77-
"plotLines": [{"value": 0, "width": 3, "color": "#333333", "zIndex": 5}],
87+
"plotLines": [{"value": 0, "width": 2, "color": INK_SOFT, "zIndex": 5, "dashStyle": "Solid"}],
7888
"min": -50,
7989
"max": 60,
8090
}
@@ -89,19 +99,30 @@
8999
series = BarSeries()
90100
series.name = "Net Satisfaction"
91101
series.data = positive_data
92-
series.data_labels = {"enabled": True, "style": {"fontSize": "22px", "fontWeight": "bold"}, "format": "{y}"}
102+
series.data_labels = {"enabled": True, "style": {"fontSize": "18px", "color": INK}, "format": "{y}"}
93103
series.border_width = 0
94-
series.point_width = 60
104+
series.point_width = 80
95105

96106
chart.add_series(series)
97107

98108
# Plot options
99109
chart.options.plot_options = {"bar": {"groupPadding": 0.1, "pointPadding": 0.05}}
100110

101-
# Download Highcharts JS
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")
111+
112+
# Download Highcharts JS (with fallback CDN)
113+
def fetch_js(urls):
114+
for url in urls:
115+
try:
116+
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
117+
with urllib.request.urlopen(req, timeout=30) as resp:
118+
return resp.read().decode("utf-8")
119+
except Exception:
120+
continue
121+
raise RuntimeError(f"Failed to download JS from: {urls}")
122+
123+
124+
hc_urls = ["https://code.highcharts.com/highcharts.js", "https://cdn.jsdelivr.net/npm/highcharts@11/highcharts.js"]
125+
highcharts_js = fetch_js(hc_urls)
105126

106127
# Generate HTML with inline scripts
107128
html_str = chart.to_js_literal()
@@ -111,14 +132,14 @@
111132
<meta charset="utf-8">
112133
<script>{highcharts_js}</script>
113134
</head>
114-
<body style="margin:0; padding:0; background:#ffffff;">
135+
<body style="margin:0; padding:0; background:{PAGE_BG};">
115136
<div id="container" style="width: 4800px; height: 2700px;"></div>
116137
<script>{html_str}</script>
117138
</body>
118139
</html>"""
119140

120141
# Save HTML
121-
with open("plot.html", "w", encoding="utf-8") as f:
142+
with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f:
122143
f.write(html_content)
123144

124145
# Screenshot with Selenium
@@ -131,16 +152,14 @@
131152
chrome_options.add_argument("--no-sandbox")
132153
chrome_options.add_argument("--disable-dev-shm-usage")
133154
chrome_options.add_argument("--disable-gpu")
134-
chrome_options.add_argument("--window-size=4800,2800")
155+
chrome_options.add_argument("--window-size=4800,2700")
135156
chrome_options.add_argument("--force-device-scale-factor=1")
136157

137158
driver = webdriver.Chrome(options=chrome_options)
138159
driver.get(f"file://{temp_path}")
139160
time.sleep(5)
140161

141-
# Get the container element and screenshot it at exact dimensions
142-
container = driver.find_element(By.ID, "container")
143-
container.screenshot("plot.png")
162+
driver.save_screenshot(f"plot-{THEME}.png")
144163
driver.quit()
145164

146165
Path(temp_path).unlink()

0 commit comments

Comments
 (0)