Skip to content

Commit 59e3010

Browse files
feat(highcharts): implement line-basic (#5541)
## Implementation: `line-basic` - python/highcharts Implements the **python/highcharts** version of `line-basic`. **File:** `plots/line-basic/implementations/python/highcharts.py` **Parent Issue:** #653 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25117426786)* --------- 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 c59c8d4 commit 59e3010

2 files changed

Lines changed: 243 additions & 203 deletions

File tree

Lines changed: 86 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,117 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
line-basic: Basic Line Plot
3-
Library: highcharts unknown | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: highcharts unknown | Python 3.13.13
4+
Quality: 79/100 | Updated: 2026-04-29
55
"""
66

7+
import json
8+
import os
79
import tempfile
810
import time
911
import urllib.request
1012
from pathlib import Path
1113

1214
import numpy as np
13-
from highcharts_core.chart import Chart
14-
from highcharts_core.options import HighchartsOptions
15-
from highcharts_core.options.series.area import LineSeries
1615
from selenium import webdriver
1716
from selenium.webdriver.chrome.options import Options
1817

1918

20-
# Data - Monthly temperature readings showing seasonal pattern
19+
# Theme tokens
20+
THEME = os.getenv("ANYPLOT_THEME", "light")
21+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
22+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
23+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
24+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
25+
GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
26+
BRAND = "#009E73"
27+
28+
# Data - Monthly temperature readings with realistic irregular variation
2129
np.random.seed(42)
2230
month_labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
23-
# Realistic temperature pattern: cold winter, warm summer
24-
temperatures = [5, 7, 12, 16, 21, 25, 28, 27, 22, 15, 9, 6]
25-
# Add slight natural variation
26-
temperatures = [t + np.random.randn() * 0.5 for t in temperatures]
27-
28-
# Create chart
29-
chart = Chart(container="container")
30-
chart.options = HighchartsOptions()
31-
32-
# Chart settings for 4800x2700 canvas
33-
chart.options.chart = {
34-
"type": "line",
35-
"width": 4800,
36-
"height": 2700,
37-
"backgroundColor": "#ffffff",
38-
"marginBottom": 300,
39-
"marginLeft": 200,
40-
"spacingTop": 80,
41-
}
42-
43-
# Title
44-
chart.options.title = {
45-
"text": "line-basic · highcharts · pyplots.ai",
46-
"style": {"fontSize": "72px", "fontWeight": "bold"},
47-
}
48-
49-
# X-axis
50-
chart.options.x_axis = {
51-
"categories": month_labels,
52-
"title": {"text": "Month", "style": {"fontSize": "48px"}, "margin": 30},
53-
"labels": {"style": {"fontSize": "36px"}, "y": 40},
54-
"gridLineWidth": 1,
55-
"gridLineColor": "#e0e0e0",
56-
"lineWidth": 2,
57-
"tickWidth": 2,
58-
}
59-
60-
# Y-axis
61-
chart.options.y_axis = {
62-
"title": {"text": "Temperature (°C)", "style": {"fontSize": "48px"}, "margin": 30},
63-
"labels": {"style": {"fontSize": "36px"}, "x": -10},
64-
"gridLineWidth": 1,
65-
"gridLineColor": "#e0e0e0",
66-
"gridLineDashStyle": "Dash",
31+
base_temps = [5, 7, 12, 16, 21, 25, 28, 27, 22, 15, 9, 6]
32+
temperatures = [round(t + np.random.randn() * 1.5, 1) for t in base_temps]
33+
34+
# Chart configuration
35+
chart_config = {
36+
"chart": {
37+
"type": "line",
38+
"width": 4800,
39+
"height": 2700,
40+
"backgroundColor": PAGE_BG,
41+
"marginBottom": 300,
42+
"marginLeft": 250,
43+
"marginRight": 80,
44+
"spacingTop": 80,
45+
},
46+
"title": {
47+
"text": "line-basic · highcharts · anyplot.ai",
48+
"style": {"fontSize": "72px", "fontWeight": "bold", "color": INK},
49+
},
50+
"xAxis": {
51+
"categories": month_labels,
52+
"title": {"text": "Month", "style": {"fontSize": "48px", "color": INK}, "margin": 30},
53+
"labels": {"style": {"fontSize": "36px", "color": INK_SOFT}, "y": 40},
54+
"gridLineWidth": 1,
55+
"gridLineColor": GRID,
56+
"lineColor": INK_SOFT,
57+
"tickColor": INK_SOFT,
58+
"lineWidth": 2,
59+
"tickWidth": 2,
60+
},
61+
"yAxis": {
62+
"title": {"text": "Temperature (°C)", "style": {"fontSize": "48px", "color": INK}, "margin": 30},
63+
"labels": {"style": {"fontSize": "36px", "color": INK_SOFT}, "x": -10},
64+
"gridLineWidth": 1,
65+
"gridLineColor": GRID,
66+
"gridLineDashStyle": "Dash",
67+
"lineColor": INK_SOFT,
68+
"tickColor": INK_SOFT,
69+
},
70+
"legend": {"enabled": False},
71+
"plotOptions": {"line": {"lineWidth": 8, "marker": {"enabled": True, "radius": 12, "symbol": "circle"}}},
72+
"series": [{"type": "line", "name": "Temperature", "data": temperatures, "color": BRAND}],
73+
"credits": {"enabled": False},
6774
}
6875

69-
# Legend
70-
chart.options.legend = {"enabled": True, "itemStyle": {"fontSize": "36px"}}
71-
72-
# Plot options for line styling
73-
chart.options.plot_options = {"line": {"lineWidth": 8, "marker": {"enabled": True, "radius": 12, "symbol": "circle"}}}
74-
75-
# Add series
76-
series = LineSeries()
77-
series.data = temperatures
78-
series.name = "Temperature"
79-
series.color = "#306998"
80-
81-
chart.add_series(series)
82-
83-
# Download Highcharts JS for inline embedding
84-
highcharts_url = "https://code.highcharts.com/highcharts.js"
85-
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
86-
highcharts_js = response.read().decode("utf-8")
87-
88-
# Generate HTML with inline scripts
89-
html_str = chart.to_js_literal()
76+
# Download Highcharts JS for inline embedding (fallback CDN on 403)
77+
_hc_urls = [
78+
"https://code.highcharts.com/highcharts.js",
79+
"https://cdnjs.cloudflare.com/ajax/libs/highcharts/11.3.0/highcharts.js",
80+
"https://cdn.jsdelivr.net/npm/highcharts@11/highcharts.js",
81+
]
82+
highcharts_js = None
83+
for _url in _hc_urls:
84+
try:
85+
_req = urllib.request.Request(_url, headers={"User-Agent": "Mozilla/5.0"})
86+
with urllib.request.urlopen(_req, timeout=30) as response:
87+
highcharts_js = response.read().decode("utf-8")
88+
break
89+
except Exception:
90+
continue
91+
if highcharts_js is None:
92+
raise RuntimeError("Could not download highcharts.js from any CDN")
93+
94+
# Build HTML with inline Highcharts JS
9095
html_content = f"""<!DOCTYPE html>
9196
<html>
9297
<head>
9398
<meta charset="utf-8">
9499
<script>{highcharts_js}</script>
95100
</head>
96-
<body style="margin:0;">
97-
<div id="container" style="width: 4800px; height: 2700px;"></div>
98-
<script>{html_str}</script>
101+
<body style="margin:0; background:{PAGE_BG};">
102+
<div id="container" style="width:4800px; height:2700px;"></div>
103+
<script>Highcharts.chart('container', {json.dumps(chart_config)});</script>
99104
</body>
100105
</html>"""
101106

102-
# Write temp HTML and take screenshot
103-
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
107+
# Save HTML artifact
108+
with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f:
104109
f.write(html_content)
105-
temp_path = f.name
106110

107-
# Also save HTML for interactive viewing
108-
with open("plot.html", "w", encoding="utf-8") as f:
111+
# Write temp HTML and take screenshot for PNG
112+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
109113
f.write(html_content)
114+
temp_path = f.name
110115

111116
chrome_options = Options()
112117
chrome_options.add_argument("--headless")
@@ -118,7 +123,7 @@
118123
driver = webdriver.Chrome(options=chrome_options)
119124
driver.get(f"file://{temp_path}")
120125
time.sleep(5)
121-
driver.save_screenshot("plot.png")
126+
driver.save_screenshot(f"plot-{THEME}.png")
122127
driver.quit()
123128

124129
Path(temp_path).unlink()

0 commit comments

Comments
 (0)