Skip to content

Commit 3a36c64

Browse files
feat(highcharts): implement bar-feature-importance (#2325)
## Implementation: `bar-feature-importance` - highcharts Implements the **highcharts** version of `bar-feature-importance`. **File:** `plots/bar-feature-importance/implementations/highcharts.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20526656090)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 9cb0002 commit 3a36c64

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
""" pyplots.ai
2+
bar-feature-importance: Feature Importance Bar Chart
3+
Library: highcharts unknown | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-26
5+
"""
6+
7+
import json
8+
import tempfile
9+
import time
10+
import urllib.request
11+
from pathlib import Path
12+
13+
from selenium import webdriver
14+
from selenium.webdriver.chrome.options import Options
15+
from selenium.webdriver.common.by import By
16+
from selenium.webdriver.support import expected_conditions as EC
17+
from selenium.webdriver.support.ui import WebDriverWait
18+
19+
20+
# Data - Feature importances from a Random Forest classifier (house price prediction)
21+
features = [
22+
"Square Footage",
23+
"Number of Bedrooms",
24+
"Location Score",
25+
"Year Built",
26+
"Lot Size",
27+
"Number of Bathrooms",
28+
"Garage Capacity",
29+
"School District Rating",
30+
"Distance to City Center",
31+
"Property Tax Rate",
32+
"HOA Fees",
33+
"Neighborhood Crime Rate",
34+
"Nearby Amenities Count",
35+
"Public Transit Access",
36+
"Energy Efficiency Score",
37+
]
38+
39+
# Importance scores (from ensemble averaging)
40+
importance = [0.215, 0.142, 0.128, 0.089, 0.078, 0.068, 0.062, 0.055, 0.048, 0.041, 0.028, 0.019, 0.014, 0.009, 0.004]
41+
42+
# Sort by importance (already sorted, but make explicit)
43+
sorted_data = sorted(zip(features, importance, strict=True), key=lambda x: x[1], reverse=True)
44+
features_sorted = [x[0] for x in sorted_data]
45+
importance_sorted = [x[1] for x in sorted_data]
46+
47+
# Reverse for horizontal bar chart (highest importance at top in Highcharts bar)
48+
features_sorted = features_sorted[::-1]
49+
importance_sorted = importance_sorted[::-1]
50+
51+
# Create gradient colors based on importance (light to dark blue)
52+
max_imp = max(importance_sorted)
53+
min_imp = min(importance_sorted)
54+
55+
56+
def importance_to_color(imp):
57+
"""Map importance to color from light (#a8d5f2) to dark (#306998)."""
58+
ratio = (imp - min_imp) / (max_imp - min_imp) if max_imp != min_imp else 0.5
59+
r = int(168 + (48 - 168) * ratio)
60+
g = int(213 + (105 - 213) * ratio)
61+
b = int(242 + (152 - 242) * ratio)
62+
return f"#{r:02x}{g:02x}{b:02x}"
63+
64+
65+
# Build data with colors
66+
bar_data = []
67+
for imp in importance_sorted:
68+
bar_data.append({"y": imp, "color": importance_to_color(imp)})
69+
70+
# Download Highcharts JS
71+
highcharts_url = "https://code.highcharts.com/highcharts.js"
72+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
73+
highcharts_js = response.read().decode("utf-8")
74+
75+
# Build chart options as a dictionary
76+
chart_options = {
77+
"chart": {
78+
"type": "bar",
79+
"width": 4800,
80+
"height": 2700,
81+
"backgroundColor": "#ffffff",
82+
"marginLeft": 380,
83+
"marginRight": 180,
84+
"marginTop": 150,
85+
"marginBottom": 120,
86+
"animation": False,
87+
},
88+
"title": {
89+
"text": "bar-feature-importance \u00b7 highcharts \u00b7 pyplots.ai",
90+
"style": {"fontSize": "48px", "fontWeight": "bold"},
91+
},
92+
"subtitle": {
93+
"text": "House Price Prediction - Random Forest Feature Importances",
94+
"style": {"fontSize": "32px", "color": "#666666"},
95+
},
96+
"xAxis": {
97+
"categories": features_sorted,
98+
"title": {"text": None},
99+
"labels": {"style": {"fontSize": "26px"}},
100+
"lineWidth": 0,
101+
"tickWidth": 0,
102+
},
103+
"yAxis": {
104+
"title": {"text": "Importance Score", "style": {"fontSize": "32px"}},
105+
"labels": {"style": {"fontSize": "24px"}},
106+
"min": 0,
107+
"max": 0.25,
108+
"gridLineWidth": 1,
109+
"gridLineColor": "#e0e0e0",
110+
},
111+
"legend": {"enabled": False},
112+
"tooltip": {"enabled": False},
113+
"plotOptions": {
114+
"bar": {
115+
"dataLabels": {
116+
"enabled": True,
117+
"format": "{point.y:.3f}",
118+
"style": {"fontSize": "22px", "fontWeight": "normal", "textOutline": "none"},
119+
"align": "left",
120+
"x": 10,
121+
},
122+
"pointPadding": 0.1,
123+
"groupPadding": 0.05,
124+
"borderWidth": 0,
125+
"animation": False,
126+
}
127+
},
128+
"credits": {"enabled": False},
129+
"series": [{"name": "Feature Importance", "data": bar_data, "animation": False}],
130+
}
131+
132+
# Convert to JSON for embedding
133+
chart_json = json.dumps(chart_options)
134+
135+
# Generate HTML with inline scripts
136+
html_content = f"""<!DOCTYPE html>
137+
<html>
138+
<head>
139+
<meta charset="utf-8">
140+
<script>{highcharts_js}</script>
141+
</head>
142+
<body style="margin:0; padding:0; background-color: #ffffff;">
143+
<div id="container" style="width: 4800px; height: 2700px;"></div>
144+
<script>
145+
Highcharts.chart('container', {chart_json});
146+
</script>
147+
</body>
148+
</html>"""
149+
150+
# Save HTML for interactive version
151+
with open("plot.html", "w", encoding="utf-8") as f:
152+
f.write(html_content)
153+
154+
# Take screenshot with Selenium
155+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
156+
f.write(html_content)
157+
temp_path = f.name
158+
159+
chrome_options = Options()
160+
chrome_options.add_argument("--headless=new")
161+
chrome_options.add_argument("--no-sandbox")
162+
chrome_options.add_argument("--disable-dev-shm-usage")
163+
chrome_options.add_argument("--disable-gpu")
164+
chrome_options.add_argument("--window-size=5000,3000")
165+
chrome_options.add_argument("--force-device-scale-factor=1")
166+
167+
driver = webdriver.Chrome(options=chrome_options)
168+
driver.set_window_size(5000, 3000)
169+
driver.get(f"file://{temp_path}")
170+
171+
# Wait for Highcharts chart to render
172+
try:
173+
WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".highcharts-root")))
174+
time.sleep(3)
175+
except Exception:
176+
time.sleep(10)
177+
178+
# Get the container element and screenshot it
179+
container = driver.find_element(By.ID, "container")
180+
container.screenshot("plot.png")
181+
driver.quit()
182+
183+
Path(temp_path).unlink()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library: highcharts
2+
specification_id: bar-feature-importance
3+
created: '2025-12-26T17:45:30Z'
4+
updated: '2025-12-26T17:53:37Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20526656090
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: unknown
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/bar-feature-importance/highcharts/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bar-feature-importance/highcharts/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/bar-feature-importance/highcharts/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent implementation of the feature importance bar chart with proper sorting
17+
(highest at top)
18+
- Clear gradient color mapping that visually emphasizes feature importance levels
19+
- Data labels positioned cleanly at the end of each bar for precise value reading
20+
- Realistic house price prediction scenario with meaningful feature names
21+
- Proper title format following pyplots.ai conventions
22+
- Clean, professional appearance suitable for publication
23+
weaknesses:
24+
- X-axis tick labels are overly dense (increments of 0.005 create visual clutter)
25+
- Contains a helper function importance_to_color() which deviates slightly from
26+
KISS structure
27+
- Does not use the highcharts-core Python library as recommended in library rules
28+
- Error bars not included despite spec mentioning them as valuable for ensemble
29+
methods

0 commit comments

Comments
 (0)