|
1 | 1 | """ anyplot.ai |
2 | 2 | sn-curve-basic: S-N Curve (Wöhler Curve) |
3 | 3 | Library: highcharts unknown | Python 3.13.13 |
4 | | -Quality: 87/100 | Updated: 2026-05-20 |
| 4 | +Quality: 89/100 | Updated: 2026-05-20 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import os |
|
15 | 15 | from highcharts_core.options import HighchartsOptions |
16 | 16 | from highcharts_core.options.series.area import LineSeries |
17 | 17 | from highcharts_core.options.series.scatter import ScatterSeries |
| 18 | +from PIL import Image |
18 | 19 | from selenium import webdriver |
19 | 20 | from selenium.webdriver.chrome.options import Options |
20 | 21 |
|
|
73 | 74 | "height": 1800, |
74 | 75 | "backgroundColor": PAGE_BG, |
75 | 76 | "style": {"fontFamily": "Arial, sans-serif", "color": INK}, |
76 | | - "marginBottom": 120, |
| 77 | + "marginBottom": 140, |
77 | 78 | "marginLeft": 150, |
78 | 79 | "marginRight": 80, |
79 | 80 | "marginTop": 100, |
| 81 | + "plotBorderWidth": 0, |
80 | 82 | } |
81 | 83 |
|
82 | 84 | chart.options.title = { |
|
92 | 94 | "color": "rgba(213,94,0,0.07)", |
93 | 95 | "label": { |
94 | 96 | "text": "Low-Cycle Fatigue", |
95 | | - "style": {"fontSize": "32px", "color": INK_SOFT}, |
| 97 | + "style": {"fontSize": "36px", "color": INK_SOFT}, |
96 | 98 | "align": "center", |
97 | 99 | "verticalAlign": "top", |
98 | 100 | "y": 30, |
|
104 | 106 | "color": "rgba(0,114,178,0.05)", |
105 | 107 | "label": { |
106 | 108 | "text": "High-Cycle Fatigue", |
107 | | - "style": {"fontSize": "32px", "color": INK_SOFT}, |
| 109 | + "style": {"fontSize": "36px", "color": INK_SOFT}, |
108 | 110 | "align": "center", |
109 | 111 | "verticalAlign": "top", |
110 | 112 | "y": 30, |
|
116 | 118 | "color": "rgba(0,158,115,0.06)", |
117 | 119 | "label": { |
118 | 120 | "text": "Infinite Life", |
119 | | - "style": {"fontSize": "32px", "color": INK_SOFT}, |
| 121 | + "style": {"fontSize": "36px", "color": INK_SOFT}, |
120 | 122 | "align": "center", |
121 | 123 | "verticalAlign": "top", |
122 | 124 | "y": 30, |
|
151 | 153 | "plotLines": [ |
152 | 154 | { |
153 | 155 | "value": ultimate_strength, |
154 | | - "color": "#E53935", |
| 156 | + "color": "#CC79A7", |
155 | 157 | "width": 4, |
156 | 158 | "dashStyle": "Dash", |
157 | 159 | "label": { |
158 | 160 | "text": f"Ultimate Strength ({ultimate_strength} MPa)", |
159 | | - "align": "right", |
160 | | - "style": {"fontSize": "34px", "color": "#E53935", "fontWeight": "bold"}, |
161 | | - "x": -10, |
| 161 | + "align": "left", |
| 162 | + "style": {"fontSize": "34px", "color": "#CC79A7", "fontWeight": "bold"}, |
| 163 | + "x": 10, |
162 | 164 | }, |
163 | 165 | "zIndex": 3, |
164 | 166 | }, |
165 | 167 | { |
166 | 168 | "value": yield_strength, |
167 | | - "color": "#FB8C00", |
| 169 | + "color": "#E69F00", |
168 | 170 | "width": 4, |
169 | 171 | "dashStyle": "Dash", |
170 | 172 | "label": { |
171 | 173 | "text": f"Yield Strength ({yield_strength} MPa)", |
172 | | - "align": "right", |
173 | | - "style": {"fontSize": "34px", "color": "#FB8C00", "fontWeight": "bold"}, |
174 | | - "x": -10, |
| 174 | + "align": "left", |
| 175 | + "style": {"fontSize": "34px", "color": "#E69F00", "fontWeight": "bold"}, |
| 176 | + "x": 10, |
175 | 177 | }, |
176 | 178 | "zIndex": 3, |
177 | 179 | }, |
178 | 180 | { |
179 | 181 | "value": endurance_limit, |
180 | | - "color": "#43A047", |
| 182 | + "color": "#56B4E9", |
181 | 183 | "width": 4, |
182 | 184 | "dashStyle": "Dash", |
183 | 185 | "label": { |
184 | 186 | "text": f"Endurance Limit ({endurance_limit} MPa)", |
185 | | - "align": "right", |
186 | | - "style": {"fontSize": "34px", "color": "#43A047", "fontWeight": "bold"}, |
187 | | - "x": -10, |
| 187 | + "align": "left", |
| 188 | + "style": {"fontSize": "34px", "color": "#56B4E9", "fontWeight": "bold"}, |
| 189 | + "x": 10, |
188 | 190 | }, |
189 | 191 | "zIndex": 3, |
190 | 192 | }, |
|
201 | 203 | "verticalAlign": "top", |
202 | 204 | "layout": "vertical", |
203 | 205 | "x": -60, |
204 | | - "y": 100, |
| 206 | + "y": 140, |
205 | 207 | } |
206 | 208 |
|
207 | 209 | chart.options.plot_options = { |
|
253 | 255 | temp_path = f.name |
254 | 256 |
|
255 | 257 | chrome_options = Options() |
256 | | -chrome_options.add_argument("--headless") |
| 258 | +chrome_options.add_argument("--headless=new") |
257 | 259 | chrome_options.add_argument("--no-sandbox") |
258 | 260 | chrome_options.add_argument("--disable-dev-shm-usage") |
259 | 261 | chrome_options.add_argument("--disable-gpu") |
| 262 | +chrome_options.add_argument("--hide-scrollbars") |
260 | 263 | chrome_options.add_argument("--window-size=3200,1800") |
261 | 264 |
|
262 | 265 | driver = webdriver.Chrome(options=chrome_options) |
| 266 | +# CDP override makes the viewport authoritative; --window-size alone is eaten by Chrome chrome |
| 267 | +driver.execute_cdp_cmd( |
| 268 | + "Emulation.setDeviceMetricsOverride", {"width": 3200, "height": 1800, "deviceScaleFactor": 1, "mobile": False} |
| 269 | +) |
263 | 270 | driver.get(f"file://{temp_path}") |
264 | 271 | time.sleep(5) |
265 | 272 | driver.save_screenshot(f"plot-{THEME}.png") |
266 | 273 | driver.quit() |
267 | 274 |
|
268 | 275 | Path(temp_path).unlink() |
| 276 | + |
| 277 | +# PIL safety net: pin to exact 3200×1800 in case of ±1-2 px rounding |
| 278 | +_img = Image.open(f"plot-{THEME}.png").convert("RGB") |
| 279 | +if _img.size != (3200, 1800): |
| 280 | + _norm = Image.new("RGB", (3200, 1800), PAGE_BG) |
| 281 | + _norm.paste(_img, ((3200 - _img.size[0]) // 2, (1800 - _img.size[1]) // 2)) |
| 282 | + _norm.save(f"plot-{THEME}.png") |
0 commit comments