|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | 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 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import json |
| 8 | +import os |
7 | 9 | import tempfile |
8 | 10 | import time |
9 | 11 | import urllib.request |
10 | 12 | from pathlib import Path |
11 | 13 |
|
12 | 14 | 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 |
16 | 15 | from selenium import webdriver |
17 | 16 | from selenium.webdriver.chrome.options import Options |
18 | 17 |
|
19 | 18 |
|
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 |
21 | 29 | np.random.seed(42) |
22 | 30 | 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}, |
67 | 74 | } |
68 | 75 |
|
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 |
90 | 95 | html_content = f"""<!DOCTYPE html> |
91 | 96 | <html> |
92 | 97 | <head> |
93 | 98 | <meta charset="utf-8"> |
94 | 99 | <script>{highcharts_js}</script> |
95 | 100 | </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> |
99 | 104 | </body> |
100 | 105 | </html>""" |
101 | 106 |
|
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: |
104 | 109 | f.write(html_content) |
105 | | - temp_path = f.name |
106 | 110 |
|
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: |
109 | 113 | f.write(html_content) |
| 114 | + temp_path = f.name |
110 | 115 |
|
111 | 116 | chrome_options = Options() |
112 | 117 | chrome_options.add_argument("--headless") |
|
118 | 123 | driver = webdriver.Chrome(options=chrome_options) |
119 | 124 | driver.get(f"file://{temp_path}") |
120 | 125 | time.sleep(5) |
121 | | -driver.save_screenshot("plot.png") |
| 126 | +driver.save_screenshot(f"plot-{THEME}.png") |
122 | 127 | driver.quit() |
123 | 128 |
|
124 | 129 | Path(temp_path).unlink() |
0 commit comments