Skip to content

Commit 7e32281

Browse files
feat(highcharts): implement gantt-basic (#2416)
## Implementation: `gantt-basic` - highcharts Implements the **highcharts** version of `gantt-basic`. **File:** `plots/gantt-basic/implementations/highcharts.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20543284236)* --------- 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 2d9884b commit 7e32281

2 files changed

Lines changed: 240 additions & 0 deletions

File tree

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
""" pyplots.ai
2+
gantt-basic: Basic Gantt Chart
3+
Library: highcharts unknown | Python 3.13.11
4+
Quality: 92/100 | Created: 2025-12-27
5+
"""
6+
7+
import tempfile
8+
import time
9+
import urllib.request
10+
from datetime import datetime
11+
from pathlib import Path
12+
13+
from highcharts_core.chart import Chart
14+
from highcharts_core.options import HighchartsOptions
15+
from selenium import webdriver
16+
from selenium.webdriver.chrome.options import Options
17+
18+
19+
# Data - Project tasks with start/end dates and categories
20+
tasks = [
21+
{
22+
"name": "Requirements Analysis",
23+
"start": datetime(2025, 1, 6),
24+
"end": datetime(2025, 1, 17),
25+
"category": "Planning",
26+
},
27+
{"name": "System Design", "start": datetime(2025, 1, 13), "end": datetime(2025, 1, 31), "category": "Planning"},
28+
{"name": "Database Schema", "start": datetime(2025, 1, 27), "end": datetime(2025, 2, 7), "category": "Development"},
29+
{"name": "Backend API", "start": datetime(2025, 2, 3), "end": datetime(2025, 3, 7), "category": "Development"},
30+
{"name": "Frontend UI", "start": datetime(2025, 2, 10), "end": datetime(2025, 3, 14), "category": "Development"},
31+
{"name": "Integration", "start": datetime(2025, 3, 10), "end": datetime(2025, 3, 21), "category": "Development"},
32+
{"name": "Unit Testing", "start": datetime(2025, 2, 17), "end": datetime(2025, 3, 14), "category": "Testing"},
33+
{"name": "System Testing", "start": datetime(2025, 3, 17), "end": datetime(2025, 3, 28), "category": "Testing"},
34+
{"name": "User Acceptance", "start": datetime(2025, 3, 24), "end": datetime(2025, 4, 4), "category": "Testing"},
35+
{"name": "Documentation", "start": datetime(2025, 3, 3), "end": datetime(2025, 3, 28), "category": "Deployment"},
36+
{"name": "Training", "start": datetime(2025, 3, 31), "end": datetime(2025, 4, 11), "category": "Deployment"},
37+
{"name": "Go Live", "start": datetime(2025, 4, 14), "end": datetime(2025, 4, 18), "category": "Deployment"},
38+
]
39+
40+
# Colors for categories (colorblind-safe)
41+
category_colors = {
42+
"Planning": "#306998", # Python Blue
43+
"Development": "#FFD43B", # Python Yellow
44+
"Testing": "#9467BD", # Purple
45+
"Deployment": "#17BECF", # Cyan
46+
}
47+
48+
# Create chart
49+
chart = Chart(container="container")
50+
chart.options = HighchartsOptions()
51+
52+
# Chart configuration
53+
chart.options.chart = {
54+
"type": "xrange",
55+
"width": 4800,
56+
"height": 2700,
57+
"backgroundColor": "#ffffff",
58+
"spacingBottom": 120,
59+
"marginLeft": 420,
60+
"marginTop": 150,
61+
}
62+
63+
# Set colors at chart level
64+
chart.options.colors = ["#306998", "#FFD43B", "#9467BD", "#17BECF"]
65+
66+
# Title
67+
chart.options.title = {
68+
"text": "gantt-basic · highcharts · pyplots.ai",
69+
"style": {"fontSize": "48px", "fontWeight": "bold"},
70+
"y": 60,
71+
}
72+
73+
# X-axis (time)
74+
today_ts = int(datetime(2025, 2, 15).timestamp() * 1000)
75+
chart.options.x_axis = {
76+
"type": "datetime",
77+
"dateTimeLabelFormats": {"week": "%e %b", "month": "%b '%y"},
78+
"title": {"text": "Timeline", "style": {"fontSize": "32px"}},
79+
"labels": {"style": {"fontSize": "28px"}},
80+
"gridLineWidth": 1,
81+
"gridLineColor": "#e0e0e0",
82+
"plotLines": [
83+
{
84+
"value": today_ts,
85+
"color": "#E53935",
86+
"width": 4,
87+
"zIndex": 10,
88+
"label": {
89+
"text": "Today (Feb 15)",
90+
"style": {"fontSize": "26px", "color": "#E53935", "fontWeight": "bold"},
91+
"rotation": 0,
92+
"align": "center",
93+
"y": -20,
94+
},
95+
}
96+
],
97+
}
98+
99+
# Y-axis (tasks)
100+
task_names = [t["name"] for t in tasks]
101+
chart.options.y_axis = {
102+
"type": "category",
103+
"categories": task_names,
104+
"title": {"text": "Tasks", "style": {"fontSize": "32px"}},
105+
"labels": {"style": {"fontSize": "26px"}},
106+
"gridLineWidth": 1,
107+
"gridLineColor": "#f0f0f0",
108+
"reversed": True,
109+
}
110+
111+
# Legend configuration - show categories
112+
chart.options.legend = {
113+
"enabled": True,
114+
"align": "center",
115+
"verticalAlign": "bottom",
116+
"layout": "horizontal",
117+
"itemStyle": {"fontSize": "32px"},
118+
"symbolRadius": 4,
119+
"symbolWidth": 50,
120+
"symbolHeight": 30,
121+
"floating": False,
122+
}
123+
124+
# Tooltip configuration
125+
chart.options.tooltip = {
126+
"headerFormat": '<span style="font-size: 24px; font-weight: bold;">{point.key}</span><br/>',
127+
"pointFormat": '<span style="font-size: 22px">{point.x:%b %e} - {point.x2:%b %e, %Y}</span>',
128+
}
129+
130+
# Create series for each category (for legend with color coding)
131+
# Order categories to appear properly in legend
132+
category_order = ["Planning", "Development", "Testing", "Deployment"]
133+
series_list = []
134+
135+
for category in category_order:
136+
color = category_colors[category]
137+
category_data = []
138+
for i, task in enumerate(tasks):
139+
if task["category"] == category:
140+
category_data.append(
141+
{
142+
"x": int(task["start"].timestamp() * 1000),
143+
"x2": int(task["end"].timestamp() * 1000),
144+
"y": i,
145+
"name": task["name"],
146+
"color": color,
147+
}
148+
)
149+
150+
series_list.append(
151+
{
152+
"type": "xrange",
153+
"name": category,
154+
"color": color,
155+
"pointWidth": 55,
156+
"data": category_data,
157+
"dataLabels": {"enabled": False},
158+
"borderRadius": 6,
159+
"borderWidth": 2,
160+
"borderColor": "#555555",
161+
}
162+
)
163+
164+
chart.options.series = series_list
165+
166+
# Download Highcharts JS modules
167+
highcharts_url = "https://code.highcharts.com/highcharts.js"
168+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
169+
highcharts_js = response.read().decode("utf-8")
170+
171+
xrange_url = "https://code.highcharts.com/modules/xrange.js"
172+
with urllib.request.urlopen(xrange_url, timeout=30) as response:
173+
xrange_js = response.read().decode("utf-8")
174+
175+
# Generate HTML with inline scripts
176+
html_str = chart.to_js_literal()
177+
html_content = f"""<!DOCTYPE html>
178+
<html>
179+
<head>
180+
<meta charset="utf-8">
181+
<script>{highcharts_js}</script>
182+
<script>{xrange_js}</script>
183+
</head>
184+
<body style="margin:0; padding:0; background: #ffffff;">
185+
<div id="container" style="width: 4800px; height: 2700px;"></div>
186+
<script>{html_str}</script>
187+
</body>
188+
</html>"""
189+
190+
# Save HTML
191+
with open("plot.html", "w", encoding="utf-8") as f:
192+
f.write(html_content)
193+
194+
# Screenshot with Selenium - use element screenshot for exact dimensions
195+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
196+
f.write(html_content)
197+
temp_path = f.name
198+
199+
chrome_options = Options()
200+
chrome_options.add_argument("--headless")
201+
chrome_options.add_argument("--no-sandbox")
202+
chrome_options.add_argument("--disable-dev-shm-usage")
203+
chrome_options.add_argument("--disable-gpu")
204+
chrome_options.add_argument("--window-size=5000,3000")
205+
206+
driver = webdriver.Chrome(options=chrome_options)
207+
driver.get(f"file://{temp_path}")
208+
time.sleep(5)
209+
210+
# Take screenshot of the chart container element for exact dimensions
211+
container = driver.find_element("id", "container")
212+
container.screenshot("plot.png")
213+
214+
driver.quit()
215+
Path(temp_path).unlink()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
library: highcharts
2+
specification_id: gantt-basic
3+
created: '2025-12-27T19:24:21Z'
4+
updated: '2025-12-27T19:33:37Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20543284236
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: unknown
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/gantt-basic/highcharts/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/gantt-basic/highcharts/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/gantt-basic/highcharts/plot.html
13+
quality_score: 92
14+
review:
15+
strengths:
16+
- Excellent use of Highcharts xrange series type for Gantt chart implementation
17+
- Clean colorblind-safe color palette with distinct category colors
18+
- Well-implemented Today marker with red plotLine and label
19+
- Professional project management scenario with realistic task names and durations
20+
- Good typography scaling for the 4800x2700 canvas
21+
- Proper category-based legend with series per category
22+
weaknesses:
23+
- Legend symbols are relatively small compared to the large canvas
24+
- Could add task duration in tooltip for enhanced interactivity
25+
- Left margin (420px) is slightly larger than necessary

0 commit comments

Comments
 (0)