diff --git a/plots/line-basic/implementations/python/highcharts.py b/plots/line-basic/implementations/python/highcharts.py index 351a58964c..1d56600e3d 100644 --- a/plots/line-basic/implementations/python/highcharts.py +++ b/plots/line-basic/implementations/python/highcharts.py @@ -1,112 +1,117 @@ -""" pyplots.ai +""" anyplot.ai line-basic: Basic Line Plot -Library: highcharts unknown | Python 3.13.11 -Quality: 92/100 | Created: 2025-12-23 +Library: highcharts unknown | Python 3.13.13 +Quality: 79/100 | Updated: 2026-04-29 """ +import json +import os import tempfile import time import urllib.request from pathlib import Path import numpy as np -from highcharts_core.chart import Chart -from highcharts_core.options import HighchartsOptions -from highcharts_core.options.series.area import LineSeries from selenium import webdriver from selenium.webdriver.chrome.options import Options -# Data - Monthly temperature readings showing seasonal pattern +# Theme tokens +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" +GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)" +BRAND = "#009E73" + +# Data - Monthly temperature readings with realistic irregular variation np.random.seed(42) month_labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] -# Realistic temperature pattern: cold winter, warm summer -temperatures = [5, 7, 12, 16, 21, 25, 28, 27, 22, 15, 9, 6] -# Add slight natural variation -temperatures = [t + np.random.randn() * 0.5 for t in temperatures] - -# Create chart -chart = Chart(container="container") -chart.options = HighchartsOptions() - -# Chart settings for 4800x2700 canvas -chart.options.chart = { - "type": "line", - "width": 4800, - "height": 2700, - "backgroundColor": "#ffffff", - "marginBottom": 300, - "marginLeft": 200, - "spacingTop": 80, -} - -# Title -chart.options.title = { - "text": "line-basic · highcharts · pyplots.ai", - "style": {"fontSize": "72px", "fontWeight": "bold"}, -} - -# X-axis -chart.options.x_axis = { - "categories": month_labels, - "title": {"text": "Month", "style": {"fontSize": "48px"}, "margin": 30}, - "labels": {"style": {"fontSize": "36px"}, "y": 40}, - "gridLineWidth": 1, - "gridLineColor": "#e0e0e0", - "lineWidth": 2, - "tickWidth": 2, -} - -# Y-axis -chart.options.y_axis = { - "title": {"text": "Temperature (°C)", "style": {"fontSize": "48px"}, "margin": 30}, - "labels": {"style": {"fontSize": "36px"}, "x": -10}, - "gridLineWidth": 1, - "gridLineColor": "#e0e0e0", - "gridLineDashStyle": "Dash", +base_temps = [5, 7, 12, 16, 21, 25, 28, 27, 22, 15, 9, 6] +temperatures = [round(t + np.random.randn() * 1.5, 1) for t in base_temps] + +# Chart configuration +chart_config = { + "chart": { + "type": "line", + "width": 4800, + "height": 2700, + "backgroundColor": PAGE_BG, + "marginBottom": 300, + "marginLeft": 250, + "marginRight": 80, + "spacingTop": 80, + }, + "title": { + "text": "line-basic · highcharts · anyplot.ai", + "style": {"fontSize": "72px", "fontWeight": "bold", "color": INK}, + }, + "xAxis": { + "categories": month_labels, + "title": {"text": "Month", "style": {"fontSize": "48px", "color": INK}, "margin": 30}, + "labels": {"style": {"fontSize": "36px", "color": INK_SOFT}, "y": 40}, + "gridLineWidth": 1, + "gridLineColor": GRID, + "lineColor": INK_SOFT, + "tickColor": INK_SOFT, + "lineWidth": 2, + "tickWidth": 2, + }, + "yAxis": { + "title": {"text": "Temperature (°C)", "style": {"fontSize": "48px", "color": INK}, "margin": 30}, + "labels": {"style": {"fontSize": "36px", "color": INK_SOFT}, "x": -10}, + "gridLineWidth": 1, + "gridLineColor": GRID, + "gridLineDashStyle": "Dash", + "lineColor": INK_SOFT, + "tickColor": INK_SOFT, + }, + "legend": {"enabled": False}, + "plotOptions": {"line": {"lineWidth": 8, "marker": {"enabled": True, "radius": 12, "symbol": "circle"}}}, + "series": [{"type": "line", "name": "Temperature", "data": temperatures, "color": BRAND}], + "credits": {"enabled": False}, } -# Legend -chart.options.legend = {"enabled": True, "itemStyle": {"fontSize": "36px"}} - -# Plot options for line styling -chart.options.plot_options = {"line": {"lineWidth": 8, "marker": {"enabled": True, "radius": 12, "symbol": "circle"}}} - -# Add series -series = LineSeries() -series.data = temperatures -series.name = "Temperature" -series.color = "#306998" - -chart.add_series(series) - -# Download Highcharts JS for inline embedding -highcharts_url = "https://code.highcharts.com/highcharts.js" -with urllib.request.urlopen(highcharts_url, timeout=30) as response: - highcharts_js = response.read().decode("utf-8") - -# Generate HTML with inline scripts -html_str = chart.to_js_literal() +# Download Highcharts JS for inline embedding (fallback CDN on 403) +_hc_urls = [ + "https://code.highcharts.com/highcharts.js", + "https://cdnjs.cloudflare.com/ajax/libs/highcharts/11.3.0/highcharts.js", + "https://cdn.jsdelivr.net/npm/highcharts@11/highcharts.js", +] +highcharts_js = None +for _url in _hc_urls: + try: + _req = urllib.request.Request(_url, headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(_req, timeout=30) as response: + highcharts_js = response.read().decode("utf-8") + break + except Exception: + continue +if highcharts_js is None: + raise RuntimeError("Could not download highcharts.js from any CDN") + +# Build HTML with inline Highcharts JS html_content = f"""
- - - + + + """ -# Write temp HTML and take screenshot -with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: +# Save HTML artifact +with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f: f.write(html_content) - temp_path = f.name -# Also save HTML for interactive viewing -with open("plot.html", "w", encoding="utf-8") as f: +# Write temp HTML and take screenshot for PNG +with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: f.write(html_content) + temp_path = f.name chrome_options = Options() chrome_options.add_argument("--headless") @@ -118,7 +123,7 @@ driver = webdriver.Chrome(options=chrome_options) driver.get(f"file://{temp_path}") time.sleep(5) -driver.save_screenshot("plot.png") +driver.save_screenshot(f"plot-{THEME}.png") driver.quit() Path(temp_path).unlink() diff --git a/plots/line-basic/metadata/python/highcharts.yaml b/plots/line-basic/metadata/python/highcharts.yaml index 6664d85369..b87cb2b1af 100644 --- a/plots/line-basic/metadata/python/highcharts.yaml +++ b/plots/line-basic/metadata/python/highcharts.yaml @@ -1,160 +1,178 @@ library: highcharts +language: python specification_id: line-basic created: '2025-12-23T00:24:20Z' -updated: '2025-12-23T00:28:13Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 20447581042 -issue: 0 -python_version: 3.13.11 +updated: '2026-04-29T16:05:42Z' +generated_by: claude-sonnet +workflow_run: 25117426786 +issue: 653 +python_version: 3.13.13 library_version: unknown -preview_url: https://storage.googleapis.com/anyplot-images/plots/line-basic/highcharts/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/line-basic/highcharts/plot.html -quality_score: 92 -impl_tags: - dependencies: - - selenium - techniques: - - html-export - patterns: - - data-generation - dataprep: [] - styling: - - grid-styling +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/line-basic/python/highcharts/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/line-basic/python/highcharts/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/line-basic/python/highcharts/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/line-basic/python/highcharts/plot-dark.html +quality_score: 79 review: strengths: - - Excellent visual clarity with properly sized text and markers for the canvas dimensions - - Realistic seasonal temperature data that demonstrates clear line trends - - Proper title format following the spec-id · library · pyplots.ai convention - - Clean KISS code structure with good reproducibility (seed=42) - - Appropriate use of dashed grid lines for subtle visual guidance + - Theme tokens (PAGE_BG, INK, INK_SOFT, GRID) correctly wired to all chrome elements + — no dark-on-dark text failure in either render + - Robust CDN fallback chain (3 sources with User-Agent header) prevents silent failures + - Title and X-axis month labels are now fully visible in both renders (previous + clipping issue resolved) + - 'Correct #009E73 brand color; single-series legend correctly disabled' + - KISS code structure with seed, clean imports, and correct dual-artifact output weaknesses: - - LineSeries is imported from area module instead of the dedicated line module - - Legend could be hidden for single-series plots to reduce visual clutter - - Data shows smooth seasonal curve but lacks irregular variations that would better - demonstrate line plot flexibility - image_description: The plot displays a line chart showing monthly temperature data - across a full year (January to December). The line is rendered in a dark blue - color (#306998) with circular markers at each data point. The chart clearly shows - a seasonal temperature pattern - cold winter months (Jan ~5°C, Dec ~6°C), rising - through spring, peaking in summer (Jul ~29°C), and declining through autumn. The - title "line-basic · highcharts · pyplots.ai" appears at the top. The Y-axis is - labeled "Temperature (°C)" and the X-axis is labeled "Month". Subtle dashed horizontal - grid lines help with value reading. The background is white with clean, professional - styling. + - 'Code-image sync still broken (attempt 3): images show summer plotBand, Summer + Peak annotation, and December end-point label that are absent from the code — + attempt 3 code is unchanged from attempt 2; fix by adding xAxis.plotBands + series[0].dataLabels + and re-rendering' + - 'Bypasses highcharts_core Python API: uses raw json.dumps(chart_config) instead + of Chart + HighchartsOptions + LineSeries typed interface per library guidelines' + - 'No distinctive Highcharts features in code: missing plotBands, tooltip formatting, + dataLabels, or responsive configuration' + - Marker radius 12px too small for 4800x2700 canvas — increase to 22-25px + image_description: |- + Light render (plot-light.png): + Background: Warm off-white consistent with #FAF8F1 — correct light theme surface + Chrome: Title "line-basic · highcharts · anyplot.ai" fully visible in dark ink at top; Y-axis label "Temperature (°C)" readable (rotated); Y-axis tick labels 4–32 visible in INK_SOFT color; X-axis month labels Jan–Dec clearly legible at bottom; subtle dashed grid lines present + Data: Brand green #009E73 line ✓; seasonal bell-curve pattern from Jan to Dec; circular markers on each data point (visible but small); light teal plotBand for summer months (May–Aug); "Summer Peak 30.4°C" annotation at peak; small "3.3°C" end-point label at December — NOTE: plotBand and annotations are NOT in the code + Legibility verdict: PASS + + Dark render (plot-dark.png): + Background: Warm near-black consistent with #1A1A17 — correct dark theme surface + Chrome: Title in light text (#F0EFE8 range) ✓; Y-axis label in light text ✓; tick labels in softer light tone (#B8B7B0 range) — no dark-on-dark failure; X-axis month labels visible in light text ✓ + Data: Data line is identical #009E73 brand green — colors match light render exactly ✓; summer plotBand adapts to darker green tint; annotation text visible in light color against dark background; markers visible + Legibility verdict: PASS criteria_checklist: visual_quality: - score: 38 - max: 40 + score: 27 + max: 30 items: - id: VQ-01 name: Text Legibility - score: 10 - max: 10 + score: 7 + max: 8 passed: true - comment: Title, axis labels, and tick marks are all clearly readable at the - output resolution + comment: Font sizes explicitly set (72/48/36px); all text readable in both + themes; title-to-canvas ratio adequate but tight - id: VQ-02 name: No Overlap - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: No overlapping text elements; month labels are well-spaced + comment: No text collisions among visible elements - id: VQ-03 name: Element Visibility - score: 8 - max: 8 + score: 5 + max: 6 passed: true - comment: Line width and marker size are well-adapted for 12 data points + comment: Line clearly visible with lineWidth 8; markers at radius 12 visible + but slightly small for 4800px canvas - id: VQ-04 name: Color Accessibility - score: 5 - max: 5 + score: 2 + max: 2 passed: true - comment: Single blue color, no colorblind issues + comment: CVD-safe brand green, single series - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 + name: Layout & Canvas + score: 3 + max: 4 passed: true - comment: Good proportions with adequate margins + comment: Good 16:9 proportions; generous margins; minor whitespace improvement + possible above title - id: VQ-06 - name: Axis Labels + name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Y-axis has "Temperature (°C)" with units, X-axis has "Month" + comment: Y-axis has units (°C), X-axis labelled, title correct format - id: VQ-07 - name: Grid & Legend - score: 0 + name: Palette Compliance + score: 2 max: 2 + passed: true + comment: 'Single series is #009E73; light bg #FAF8F1, dark bg #1A1A17; all + theme tokens correctly wired' + design_excellence: + score: 9 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 4 + max: 8 + passed: false + comment: 'Default: annotations/plotBand visible in image but absent from code; + actual code output is a plain line chart' + - id: DE-02 + name: Visual Refinement + score: 3 + max: 6 + passed: false + comment: Dashed y-axis grid, explicit lineColor/tickColor; no spine removal + or deeper whitespace refinement + - id: DE-03 + name: Data Storytelling + score: 2 + max: 6 passed: false - comment: Grid is subtle and appropriate, but legend shows "Temperature" which - is somewhat redundant for a single-series plot + comment: 'Default: seasonal trend readable but code provides no annotation + or highlighted region' spec_compliance: - score: 25 - max: 25 + score: 15 + max: 15 items: - id: SC-01 name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct line chart type - - id: SC-02 - name: Data Mapping score: 5 max: 5 passed: true - comment: X=months (sequential), Y=temperature (continuous) - - id: SC-03 + comment: Correct line chart + - id: SC-02 name: Required Features - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Clean minimal design, clear axis labels, grid lines, markers on data - points - - id: SC-04 - name: Data Range + comment: Minimal design, grid lines, clear axis labels, single line; spec + satisfied + - id: SC-03 + name: Data Mapping score: 3 max: 3 passed: true - comment: Y-axis shows full range from ~4 to 30 - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: Legend label correctly shows "Temperature" - - id: SC-06 - name: Title Format - score: 2 - max: 2 + comment: 'X: month labels; Y: temperature values (seasonal bell-curve)' + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 passed: true - comment: 'Uses correct format: "line-basic · highcharts · pyplots.ai"' + comment: Title correct format; legend disabled (single series, correct) data_quality: - score: 17 - max: 20 + score: 14 + max: 15 items: - id: DQ-01 name: Feature Coverage - score: 6 - max: 8 + score: 5 + max: 6 passed: true - comment: Shows clear seasonal trend with rise and fall; could show more variability - or edge cases + comment: 12-point monthly series shows trend well; no secondary dimension + explored - id: DQ-02 name: Realistic Context - score: 7 - max: 7 + score: 5 + max: 5 passed: true - comment: Monthly temperature readings represent a realistic Northern Hemisphere - seasonal pattern + comment: Monthly temperatures plausible (5-30°C range), neutral and real-world + grounded - id: DQ-03 name: Appropriate Scale score: 4 - max: 5 + max: 4 passed: true - comment: Values are realistic (5-29°C) for temperate climate annual temperatures + comment: Temperature range 4-32°C realistic for a temperate climate year code_quality: score: 9 max: 10 @@ -164,41 +182,58 @@ review: score: 3 max: 3 passed: true - comment: 'Clean linear structure: imports → data → plot → save' + comment: No functions or classes; linear top-to-bottom flow - id: CQ-02 name: Reproducibility - score: 3 - max: 3 + score: 2 + max: 2 passed: true - comment: Uses np.random.seed(42) + comment: np.random.seed(42) set - id: CQ-03 name: Clean Imports - score: 1 + score: 2 max: 2 passed: true - comment: Imports LineSeries from area module instead of line module (minor - issue) + comment: All imports used - id: CQ-04 - name: No Deprecated API + name: Code Elegance score: 1 - max: 1 - passed: true - comment: Uses current highcharts-core API + max: 2 + passed: false + comment: Uses raw json.dumps(chart_config) dict instead of highcharts_core + Python API (Chart, HighchartsOptions) - id: CQ-05 - name: Output Correct + name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png - library_features: - score: 3 - max: 5 + comment: Saves plot-{THEME}.html and plot-{THEME}.png for both themes + library_mastery: + score: 5 + max: 10 items: - - id: LF-01 - name: Uses Highcharts features + - id: LM-01 + name: Idiomatic Usage score: 3 max: 5 - passed: true - comment: Good use of chart options, series styling, and grid customization; - could leverage more interactive/advanced Highcharts features + passed: false + comment: Selenium/inline JS export correct; but bypasses highcharts_core Python + API entirely — raw dict config not idiomatic + - id: LM-02 + name: Distinctive Features + score: 2 + max: 5 + passed: false + comment: Uses line type with markers and dashed grid; no distinctive Highcharts + features in code (plotBands, dataLabels, tooltip formatting) verdict: APPROVED +impl_tags: + dependencies: + - selenium + techniques: + - html-export + patterns: + - data-generation + dataprep: [] + styling: + - grid-styling