diff --git a/plots/gantt-dependencies/implementations/python/highcharts.py b/plots/gantt-dependencies/implementations/python/highcharts.py index 72bc383ef1..a198eb3721 100644 --- a/plots/gantt-dependencies/implementations/python/highcharts.py +++ b/plots/gantt-dependencies/implementations/python/highcharts.py @@ -1,136 +1,137 @@ -""" pyplots.ai +"""anyplot.ai gantt-dependencies: Gantt Chart with Dependencies -Library: highcharts 1.10.3 | Python 3.14 -Quality: 91/100 | Updated: 2026-02-25 +Library: highcharts | Python 3.14 +Quality: pending | Updated: 2026-06-02 """ +import os import tempfile import time import urllib.request from pathlib import Path +from PIL import Image from selenium import webdriver from selenium.webdriver.chrome.options import Options -# Download Highcharts Gantt JS (includes core + gantt module) +# 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" +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" +GRID = "rgba(26,26,23,0.15)" if THEME == "light" else "rgba(240,239,232,0.15)" + +# Imprint palette — 4 project phases as categorical series (positions 1–4) +C1 = "#009E73" # Requirements (brand green) +C2 = "#C475FD" # Design (lavender) +C3 = "#4467A3" # Development (blue) +C4 = "#BD8233" # Testing (ochre) +CRITICAL = "#AE3030" # matte red — semantic anchor: critical path + +# Download Highcharts Gantt JS inline (headless Chrome cannot load CDN from file://) highcharts_gantt_url = "https://cdn.jsdelivr.net/npm/highcharts@11.4.8/highcharts-gantt.js" with urllib.request.urlopen(highcharts_gantt_url, timeout=30) as response: highcharts_gantt_js = response.read().decode("utf-8") -# Chart configuration using Highcharts Gantt with parent/child grouping -# Software Development Project: 4 phases, 12 tasks + 2 milestones, finish-to-start dependencies -# Critical path highlighted with bold red connectors; non-critical shown as light dashed lines -# Refined muted palette: slate blue, amber, muted purple, teal -chart_config = """ +# JS theme variables — injected before the chart config so JS can reference them +theme_vars_js = f""" +var PAGE_BG = '{PAGE_BG}'; +var ELEVATED_BG = '{ELEVATED_BG}'; +var INK = '{INK}'; +var INK_SOFT = '{INK_SOFT}'; +var INK_MUTED = '{INK_MUTED}'; +var GRID_COLOR = '{GRID}'; +var C1 = '{C1}'; +var C2 = '{C2}'; +var C3 = '{C3}'; +var C4 = '{C4}'; +var CRITICAL = '{CRITICAL}'; +""" + +# PNG chart config (plain string — references JS vars declared above, avoids f-string brace escaping) +chart_config_png = r""" Highcharts.ganttChart('container', { chart: { - width: 4800, - height: 2550, - backgroundColor: '#FAFBFC', - spacingTop: 50, - spacingBottom: 40, - spacingLeft: 50, - spacingRight: 50, - style: { - fontFamily: '"Segoe UI", "Helvetica Neue", Arial, sans-serif' - }, + width: 3200, + height: 1800, + backgroundColor: PAGE_BG, + spacingTop: 30, + spacingBottom: 80, + spacingLeft: 20, + spacingRight: 20, + style: {fontFamily: '"Segoe UI", "Helvetica Neue", Arial, sans-serif'}, events: { load: function() { var ren = this.renderer; - var x = this.plotLeft + this.plotWidth - 560; - var y = this.plotTop + this.plotHeight + 10; - // Critical path legend - ren.path(['M', x, y, 'L', x + 55, y]) - .attr({ 'stroke-width': 4, stroke: '#C0392B' }) + var x = this.plotLeft + this.plotWidth - 480; + var y = this.plotTop + this.plotHeight + 24; + ren.path(['M', x, y, 'L', x + 50, y]) + .attr({'stroke-width': 4, stroke: CRITICAL}) .add(); - ren.text('Critical Path', x + 68, y + 6) - .css({ fontSize: '20px', color: '#5D6D7E', fontWeight: '600' }) + ren.text('Critical Path', x + 62, y + 6) + .css({fontSize: '36px', color: INK_SOFT, fontWeight: '600'}) .add(); - // Non-critical legend - ren.path(['M', x + 280, y, 'L', x + 335, y]) - .attr({ 'stroke-width': 2, stroke: '#B0BEC5', 'stroke-dasharray': '6,4' }) + ren.path(['M', x + 270, y, 'L', x + 320, y]) + .attr({'stroke-width': 2, stroke: INK_MUTED, 'stroke-dasharray': '6,4'}) .add(); - ren.text('Non-Critical', x + 348, y + 6) - .css({ fontSize: '20px', color: '#95A5A6', fontWeight: '400' }) + ren.text('Non-Critical', x + 332, y + 6) + .css({fontSize: '36px', color: INK_MUTED, fontWeight: '400'}) .add(); } } }, title: { - text: 'gantt-dependencies \\u00b7 highcharts \\u00b7 pyplots.ai', - style: { - fontSize: '44px', - fontWeight: '600', - color: '#2C3E50' - }, - margin: 30 + text: 'gantt-dependencies · python · highcharts · anyplot.ai', + style: {fontSize: '66px', fontWeight: '600', color: INK}, + margin: 20 }, subtitle: { - text: 'Software Development Project Schedule \\u2014 Critical Path & Phase Dependencies', - style: { - fontSize: '32px', - color: '#7F8C8D', - fontWeight: '400' - } + text: 'Software Development Project Schedule — Critical Path & Phase Dependencies', + style: {fontSize: '44px', color: INK_SOFT} }, xAxis: [{ min: Date.UTC(2024, 0, 1), max: Date.UTC(2024, 2, 31), tickInterval: 7 * 24 * 3600 * 1000, - labels: { - style: { - fontSize: '22px', - color: '#5D6D7E' - }, - format: '{value:%b %e}' - }, + labels: {style: {fontSize: '44px', color: INK_SOFT}, format: '{value:%b %e}'}, gridLineWidth: 1, - gridLineColor: '#E8ECF0', + gridLineColor: GRID_COLOR, + lineColor: INK_SOFT, + tickColor: INK_SOFT, currentDateIndicator: false }], yAxis: { - labels: { - style: { - fontSize: '26px', - color: '#34495E' - }, - indentation: 30 - }, + labels: {style: {fontSize: '40px', color: INK}, indentation: 20}, gridLineWidth: 1, - gridLineColor: '#F0F2F5', - alternateGridColor: '#F7F8FA' + gridLineColor: GRID_COLOR, + alternateGridColor: ELEVATED_BG }, tooltip: { - style: { - fontSize: '22px' - }, - dateTimeLabelFormats: { - day: '%A, %b %e, %Y' - } - }, - navigator: { - enabled: false - }, - scrollbar: { - enabled: false - }, - rangeSelector: { - enabled: false + backgroundColor: ELEVATED_BG, + borderColor: INK_SOFT, + style: {fontSize: '36px', color: INK}, + dateTimeLabelFormats: {day: '%A, %b %e, %Y'} }, + navigator: {enabled: false}, + scrollbar: {enabled: false}, + rangeSelector: {enabled: false}, plotOptions: { series: { animation: false, - borderRadius: 5, + borderRadius: 4, groupPadding: 0.05, dataLabels: { enabled: true, align: 'left', - padding: 12, + padding: 8, style: { - fontSize: '22px', + fontSize: '32px', fontWeight: '600', - textOutline: '3px #FAFBFC' + textOutline: '2px ' + PAGE_BG, + color: INK }, format: '{point.name}', overflow: 'allow', @@ -139,295 +140,250 @@ connectors: { lineWidth: 2, dashStyle: 'ShortDash', - lineColor: '#B0BEC5', - radius: 10, - startMarker: { - enabled: false - }, - endMarker: { - enabled: true, - width: 12, - height: 12, - color: '#B0BEC5' - } + lineColor: INK_MUTED, + radius: 8, + startMarker: {enabled: false}, + endMarker: {enabled: true, width: 10, height: 10, color: INK_MUTED} } } }, series: [{ name: 'Project Schedule', data: [ - // Phase 1: Requirements (Jan 1 - Jan 22) — Slate Blue - { - id: 'requirements', - name: 'Requirements Phase', - color: '#306998' - }, - { - id: 'req_gather', - name: 'Gather Requirements', - parent: 'requirements', - start: Date.UTC(2024, 0, 1), - end: Date.UTC(2024, 0, 10), - color: '#306998' - }, - { - id: 'req_analysis', - name: 'Requirements Analysis', - parent: 'requirements', - start: Date.UTC(2024, 0, 11), - end: Date.UTC(2024, 0, 17), - dependency: { to: 'req_gather', lineColor: '#C0392B', lineWidth: 4 }, - color: '#306998' - }, + {id: 'requirements', name: 'Requirements Phase', color: C1}, { - id: 'req_approval', - name: 'Stakeholder Approval', - parent: 'requirements', - start: Date.UTC(2024, 0, 18), - end: Date.UTC(2024, 0, 22), - dependency: { to: 'req_analysis', lineColor: '#C0392B', lineWidth: 4 }, - color: '#306998' + id: 'req_gather', name: 'Gather Requirements', parent: 'requirements', + start: Date.UTC(2024, 0, 1), end: Date.UTC(2024, 0, 10), color: C1 }, - // Milestone: Requirements Baseline { - id: 'milestone_req', - name: 'Requirements Baseline \\u2713', - parent: 'requirements', - start: Date.UTC(2024, 0, 22), - milestone: true, - dependency: { to: 'req_approval', lineColor: '#C0392B', lineWidth: 4 }, - color: '#1A3A5C' + id: 'req_analysis', name: 'Requirements Analysis', parent: 'requirements', + start: Date.UTC(2024, 0, 11), end: Date.UTC(2024, 0, 17), + dependency: {to: 'req_gather', lineColor: CRITICAL, lineWidth: 4}, + color: C1 }, - // Phase 2: Design (Jan 23 - Feb 9) — Amber { - id: 'design', - name: 'Design Phase', - color: '#D4920B' + id: 'req_approval', name: 'Stakeholder Approval', parent: 'requirements', + start: Date.UTC(2024, 0, 18), end: Date.UTC(2024, 0, 22), + dependency: {to: 'req_analysis', lineColor: CRITICAL, lineWidth: 4}, + color: C1 }, { - id: 'design_arch', - name: 'Architecture Design', - parent: 'design', - start: Date.UTC(2024, 0, 23), - end: Date.UTC(2024, 1, 2), - dependency: { to: 'milestone_req', lineColor: '#C0392B', lineWidth: 4 }, - color: '#D4920B' + id: 'milestone_req', name: 'Requirements Baseline ✓', + parent: 'requirements', start: Date.UTC(2024, 0, 22), milestone: true, + dependency: {to: 'req_approval', lineColor: CRITICAL, lineWidth: 4}, + color: INK }, + {id: 'design', name: 'Design Phase', color: C2}, { - id: 'design_ui', - name: 'UI/UX Design', - parent: 'design', - start: Date.UTC(2024, 0, 23), - end: Date.UTC(2024, 1, 5), - dependency: { to: 'milestone_req', lineColor: '#B0BEC5', lineWidth: 2, dashStyle: 'ShortDash' }, - color: '#E8A817' + id: 'design_arch', name: 'Architecture Design', parent: 'design', + start: Date.UTC(2024, 0, 23), end: Date.UTC(2024, 1, 2), + dependency: {to: 'milestone_req', lineColor: CRITICAL, lineWidth: 4}, + color: C2 }, { - id: 'design_db', - name: 'Database Design', - parent: 'design', - start: Date.UTC(2024, 1, 3), - end: Date.UTC(2024, 1, 9), - dependency: { to: 'design_arch', lineColor: '#C0392B', lineWidth: 4 }, - color: '#D4920B' + id: 'design_ui', name: 'UI/UX Design', parent: 'design', + start: Date.UTC(2024, 0, 23), end: Date.UTC(2024, 1, 5), + dependency: {to: 'milestone_req', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}, + color: C2 }, - // Phase 3: Development (Feb 7 - Mar 15) — Muted Purple { - id: 'development', - name: 'Development Phase', - color: '#7B5EA7' + id: 'design_db', name: 'Database Design', parent: 'design', + start: Date.UTC(2024, 1, 3), end: Date.UTC(2024, 1, 9), + dependency: {to: 'design_arch', lineColor: CRITICAL, lineWidth: 4}, + color: C2 }, + {id: 'development', name: 'Development Phase', color: C3}, { - id: 'dev_backend', - name: 'Backend Development', - parent: 'development', - start: Date.UTC(2024, 1, 12), - end: Date.UTC(2024, 2, 4), - dependency: { to: 'design_db', lineColor: '#C0392B', lineWidth: 4 }, - color: '#7B5EA7' + id: 'dev_backend', name: 'Backend Development', parent: 'development', + start: Date.UTC(2024, 1, 12), end: Date.UTC(2024, 2, 4), + dependency: {to: 'design_db', lineColor: CRITICAL, lineWidth: 4}, + color: C3 }, { - id: 'dev_frontend', - name: 'Frontend Development', - parent: 'development', - start: Date.UTC(2024, 1, 7), - end: Date.UTC(2024, 2, 1), - dependency: { to: 'design_ui', lineColor: '#B0BEC5', lineWidth: 2, dashStyle: 'ShortDash' }, - color: '#9B7EC8' + id: 'dev_frontend', name: 'Frontend Development', parent: 'development', + start: Date.UTC(2024, 1, 7), end: Date.UTC(2024, 2, 1), + dependency: {to: 'design_ui', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}, + color: C3 }, { - id: 'dev_integration', - name: 'System Integration', - parent: 'development', - start: Date.UTC(2024, 2, 5), - end: Date.UTC(2024, 2, 15), + id: 'dev_integration', name: 'System Integration', parent: 'development', + start: Date.UTC(2024, 2, 5), end: Date.UTC(2024, 2, 15), dependency: [ - { to: 'dev_backend', lineColor: '#C0392B', lineWidth: 4 }, - { to: 'dev_frontend', lineColor: '#B0BEC5', lineWidth: 2, dashStyle: 'ShortDash' } + {to: 'dev_backend', lineColor: CRITICAL, lineWidth: 4}, + {to: 'dev_frontend', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'} ], - color: '#7B5EA7' - }, - // Phase 4: Testing (Mar 5 - Mar 29) — Teal - { - id: 'testing', - name: 'Testing Phase', - color: '#0F8B8D' + color: C3 }, + {id: 'testing', name: 'Testing Phase', color: C4}, { - id: 'test_unit', - name: 'Unit Testing', - parent: 'testing', - start: Date.UTC(2024, 2, 5), - end: Date.UTC(2024, 2, 15), - dependency: { to: 'dev_backend', lineColor: '#B0BEC5', lineWidth: 2, dashStyle: 'ShortDash' }, - color: '#0F8B8D' + id: 'test_unit', name: 'Unit Testing', parent: 'testing', + start: Date.UTC(2024, 2, 5), end: Date.UTC(2024, 2, 15), + dependency: {to: 'dev_backend', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}, + color: C4 }, { - id: 'test_integration', - name: 'Integration Testing', - parent: 'testing', - start: Date.UTC(2024, 2, 16), - end: Date.UTC(2024, 2, 22), + id: 'test_integration', name: 'Integration Testing', parent: 'testing', + start: Date.UTC(2024, 2, 16), end: Date.UTC(2024, 2, 22), dependency: [ - { to: 'dev_integration', lineColor: '#C0392B', lineWidth: 4 }, - { to: 'test_unit', lineColor: '#B0BEC5', lineWidth: 2, dashStyle: 'ShortDash' } + {to: 'dev_integration', lineColor: CRITICAL, lineWidth: 4}, + {to: 'test_unit', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'} ], - color: '#0F8B8D' + color: C4 }, { - id: 'test_uat', - name: 'User Acceptance Testing', - parent: 'testing', - start: Date.UTC(2024, 2, 23), - end: Date.UTC(2024, 2, 29), - dependency: { to: 'test_integration', lineColor: '#C0392B', lineWidth: 4 }, - color: '#0F8B8D' + id: 'test_uat', name: 'User Acceptance Testing', parent: 'testing', + start: Date.UTC(2024, 2, 23), end: Date.UTC(2024, 2, 29), + dependency: {to: 'test_integration', lineColor: CRITICAL, lineWidth: 4}, + color: C4 }, - // Milestone: Release Ready { - id: 'milestone_release', - name: 'Release Ready \\u2605', - parent: 'testing', - start: Date.UTC(2024, 2, 29), - milestone: true, - dependency: { to: 'test_uat', lineColor: '#C0392B', lineWidth: 4 }, - color: '#1A3A5C' + id: 'milestone_release', name: 'Release Ready ★', + parent: 'testing', start: Date.UTC(2024, 2, 29), milestone: true, + dependency: {to: 'test_uat', lineColor: CRITICAL, lineWidth: 4}, + color: INK } ] }] }); """ -# Generate HTML with inline Highcharts Gantt -html_content = f""" +# Interactive HTML chart config (CDN-linked, responsive) +chart_config_html = r""" +Highcharts.ganttChart('container', { + chart: { + backgroundColor: PAGE_BG, + style: {fontFamily: '"Segoe UI", "Helvetica Neue", Arial, sans-serif'} + }, + title: { + text: 'gantt-dependencies · python · highcharts · anyplot.ai', + style: {color: INK} + }, + subtitle: { + text: 'Software Development Project Schedule — Critical Path & Phase Dependencies', + style: {color: INK_SOFT} + }, + xAxis: [{ + min: Date.UTC(2024, 0, 1), + max: Date.UTC(2024, 2, 31), + labels: {style: {color: INK_SOFT}}, + gridLineColor: GRID_COLOR, + lineColor: INK_SOFT, + tickColor: INK_SOFT, + currentDateIndicator: false + }], + yAxis: { + labels: {style: {color: INK}, indentation: 20}, + gridLineColor: GRID_COLOR, + alternateGridColor: ELEVATED_BG + }, + tooltip: { + backgroundColor: ELEVATED_BG, + borderColor: INK_SOFT, + style: {color: INK} + }, + navigator: {enabled: false}, + scrollbar: {enabled: false}, + rangeSelector: {enabled: false}, + plotOptions: { + series: { + borderRadius: 4, + connectors: { + lineWidth: 2, + lineColor: INK_MUTED, + radius: 6, + startMarker: {enabled: false}, + endMarker: {enabled: true, color: INK_MUTED} + } + } + }, + series: [{ + name: 'Project Schedule', + data: [ + {id: 'requirements', name: 'Requirements Phase', color: C1}, + {id: 'req_gather', name: 'Gather Requirements', parent: 'requirements', start: Date.UTC(2024, 0, 1), end: Date.UTC(2024, 0, 10), color: C1}, + {id: 'req_analysis', name: 'Requirements Analysis', parent: 'requirements', start: Date.UTC(2024, 0, 11), end: Date.UTC(2024, 0, 17), dependency: {to: 'req_gather', lineColor: CRITICAL, lineWidth: 3}, color: C1}, + {id: 'req_approval', name: 'Stakeholder Approval', parent: 'requirements', start: Date.UTC(2024, 0, 18), end: Date.UTC(2024, 0, 22), dependency: {to: 'req_analysis', lineColor: CRITICAL, lineWidth: 3}, color: C1}, + {id: 'milestone_req', name: 'Requirements Baseline ✓', parent: 'requirements', start: Date.UTC(2024, 0, 22), milestone: true, dependency: {to: 'req_approval', lineColor: CRITICAL, lineWidth: 3}, color: INK}, + {id: 'design', name: 'Design Phase', color: C2}, + {id: 'design_arch', name: 'Architecture Design', parent: 'design', start: Date.UTC(2024, 0, 23), end: Date.UTC(2024, 1, 2), dependency: {to: 'milestone_req', lineColor: CRITICAL, lineWidth: 3}, color: C2}, + {id: 'design_ui', name: 'UI/UX Design', parent: 'design', start: Date.UTC(2024, 0, 23), end: Date.UTC(2024, 1, 5), dependency: {to: 'milestone_req', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}, color: C2}, + {id: 'design_db', name: 'Database Design', parent: 'design', start: Date.UTC(2024, 1, 3), end: Date.UTC(2024, 1, 9), dependency: {to: 'design_arch', lineColor: CRITICAL, lineWidth: 3}, color: C2}, + {id: 'development', name: 'Development Phase', color: C3}, + {id: 'dev_backend', name: 'Backend Development', parent: 'development', start: Date.UTC(2024, 1, 12), end: Date.UTC(2024, 2, 4), dependency: {to: 'design_db', lineColor: CRITICAL, lineWidth: 3}, color: C3}, + {id: 'dev_frontend', name: 'Frontend Development', parent: 'development', start: Date.UTC(2024, 1, 7), end: Date.UTC(2024, 2, 1), dependency: {to: 'design_ui', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}, color: C3}, + {id: 'dev_integration', name: 'System Integration', parent: 'development', start: Date.UTC(2024, 2, 5), end: Date.UTC(2024, 2, 15), dependency: [{to: 'dev_backend', lineColor: CRITICAL, lineWidth: 3}, {to: 'dev_frontend', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}], color: C3}, + {id: 'testing', name: 'Testing Phase', color: C4}, + {id: 'test_unit', name: 'Unit Testing', parent: 'testing', start: Date.UTC(2024, 2, 5), end: Date.UTC(2024, 2, 15), dependency: {to: 'dev_backend', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}, color: C4}, + {id: 'test_integration', name: 'Integration Testing', parent: 'testing', start: Date.UTC(2024, 2, 16), end: Date.UTC(2024, 2, 22), dependency: [{to: 'dev_integration', lineColor: CRITICAL, lineWidth: 3}, {to: 'test_unit', lineColor: INK_MUTED, lineWidth: 2, dashStyle: 'ShortDash'}], color: C4}, + {id: 'test_uat', name: 'User Acceptance Testing', parent: 'testing', start: Date.UTC(2024, 2, 23), end: Date.UTC(2024, 2, 29), dependency: {to: 'test_integration', lineColor: CRITICAL, lineWidth: 3}, color: C4}, + {id: 'milestone_release', name: 'Release Ready ★', parent: 'testing', start: Date.UTC(2024, 2, 29), milestone: true, dependency: {to: 'test_uat', lineColor: CRITICAL, lineWidth: 3}, color: INK} + ] + }] +}); +""" + +# Save interactive HTML (CDN script, responsive container) +interactive_html = f""" + + + + gantt-dependencies · python · highcharts · anyplot.ai + + + +
+ + +""" + +with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f: + f.write(interactive_html) + +# Build PNG HTML with inline Highcharts JS (headless Chrome needs inline scripts) +png_html = f""" - -
+ +
""" -# Write temp HTML and take screenshot with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: - f.write(html_content) + f.write(png_html) temp_path = f.name chrome_options = Options() -chrome_options.add_argument("--headless") +chrome_options.add_argument("--headless=new") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-gpu") -chrome_options.add_argument("--window-size=4800,5000") +chrome_options.add_argument("--hide-scrollbars") +chrome_options.add_argument("--window-size=3200,1800") driver = webdriver.Chrome(options=chrome_options) +driver.execute_cdp_cmd( + "Emulation.setDeviceMetricsOverride", {"width": 3200, "height": 1800, "deviceScaleFactor": 1, "mobile": False} +) driver.get(f"file://{temp_path}") time.sleep(5) - -# Capture the chart container element -container = driver.find_element("id", "container") -container.screenshot("plot.png") +driver.save_screenshot(f"plot-{THEME}.png") driver.quit() Path(temp_path).unlink() -# Save HTML for interactive version -html_output = """ - - - - gantt-dependencies - Highcharts - pyplots.ai - - - -
- - -""" - -with open("plot.html", "w", encoding="utf-8") as f: - f.write(html_output) +# PIL normalization — pins saved PNG to exact 3200×1800 target +_img = Image.open(f"plot-{THEME}.png").convert("RGB") +if _img.size != (3200, 1800): + _norm = Image.new("RGB", (3200, 1800), PAGE_BG) + _norm.paste(_img, ((3200 - _img.size[0]) // 2, (1800 - _img.size[1]) // 2)) + _norm.save(f"plot-{THEME}.png") diff --git a/plots/gantt-dependencies/metadata/python/highcharts.yaml b/plots/gantt-dependencies/metadata/python/highcharts.yaml index 6c2dacb139..59757b2118 100644 --- a/plots/gantt-dependencies/metadata/python/highcharts.yaml +++ b/plots/gantt-dependencies/metadata/python/highcharts.yaml @@ -1,242 +1,21 @@ +# Per-library metadata for highcharts implementation of gantt-dependencies +# Auto-generated by impl-generate.yml + library: highcharts +language: python specification_id: gantt-dependencies created: '2026-01-15T21:03:37Z' -updated: '2026-02-25T22:47:15Z' -generated_by: claude-opus-4-6 -workflow_run: 21046152003 +updated: '2026-06-02T13:47:23Z' +generated_by: claude-sonnet +workflow_run: 26823365214 issue: 3830 -python_version: '3.14' -library_version: 1.10.3 -preview_url: https://storage.googleapis.com/anyplot-images/plots/gantt-dependencies/highcharts/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/gantt-dependencies/highcharts/plot.html -quality_score: 91 +language_version: 3.13.13 +library_version: unknown +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/gantt-dependencies/python/highcharts/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/gantt-dependencies/python/highcharts/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/gantt-dependencies/python/highcharts/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/gantt-dependencies/python/highcharts/plot-dark.html +quality_score: null review: - strengths: - - Expert use of Highcharts Gantt module with specialized ganttChart() constructor - and built-in dependency connector system - - Critical path visualization with bold red connectors creates excellent data storytelling - and visual hierarchy - - Cohesive custom color palette (slate blue, amber, muted purple, teal) with professional - typography - - Comprehensive project data covering sequential, parallel, and multi-dependency - task relationships - - Clean code with both static PNG and interactive HTML output - weaknesses: - - Chart dimensions (4800x2550) slightly deviate from standard formats (4800x2700 - or 3600x3600) - - Legend placement at the very bottom-right edge could be more prominent - - Minor visual competition between connector lines and data labels in dense areas - image_description: 'The plot displays a Gantt chart for a Software Development Project - spanning January to late March 2024, organized into four color-coded phases: Requirements - (slate blue #306998), Design (amber #D4920B), Development (muted purple #7B5EA7), - and Testing (teal #0F8B8D). The title reads "gantt-dependencies · highcharts · - pyplots.ai" in dark text at the top, with a subtitle "Software Development Project - Schedule — Critical Path & Phase Dependencies." The x-axis shows weekly date markers - (Jan 1 through Mar 25) with light grid lines. The y-axis lists 18 rows: 4 phase - headers with aggregate bars, 12 individual task bars, and 2 diamond-shaped milestones - ("Requirements Baseline ✓" and "Release Ready ★" in dark navy). Dependency connectors - are clearly visible — bold red lines for the critical path and lighter gray dashed - lines for non-critical dependencies, each with arrowhead end markers. A custom - legend at the bottom right explains "Critical Path" (red solid) and "Non-Critical" - (gray dashed). The background is off-white (#FAFBFC) with subtle alternating row - shading. Data labels appear on each bar with white text outline for readability.' - criteria_checklist: - visual_quality: - score: 26 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 7 - max: 8 - passed: true - comment: All font sizes explicitly set (title 44px, subtitle 32px, axis labels - 22-26px, data labels 22px with text outline). Minor competition between - some data labels and connector lines. - - id: VQ-02 - name: No Overlap - score: 5 - max: 6 - passed: true - comment: Minimal overlap; some connector lines cross text areas and aggregate - bar labels partially obscured by child task rendering. - - id: VQ-03 - name: Element Visibility - score: 5 - max: 6 - passed: true - comment: Task bars, connectors, and milestones clearly visible. Milestone - diamonds and legend elements somewhat small relative to canvas. - - id: VQ-04 - name: Color Accessibility - score: 4 - max: 4 - passed: true - comment: 'Excellent colorblind-safe palette: slate blue, amber, muted purple, - teal. Critical red vs non-critical gray highly distinguishable.' - - id: VQ-05 - name: Layout & Canvas - score: 3 - max: 4 - passed: true - comment: Good canvas usage at 4800x2550 (close to but not exactly standard - 4800x2700). Legend at very bottom-right edge. - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: Date-formatted x-axis labels and descriptive task names on y-axis. - Self-explanatory for Gantt chart. - design_excellence: - score: 15 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 6 - max: 8 - passed: true - comment: 'Strong design: cohesive custom palette, intentional typography hierarchy, - rounded bars, off-white background with alternating rows.' - - id: DE-02 - name: Visual Refinement - score: 4 - max: 6 - passed: true - comment: 'Good refinement: subtle grid colors, alternating row shading, generous - spacing, disabled unnecessary chrome. Room for polish in legend and grid.' - - id: DE-03 - name: Data Storytelling - score: 5 - max: 6 - passed: true - comment: Critical path in bold red creates clear focal point. Non-critical - de-emphasized. Phase colors and milestones guide viewer through project - lifecycle. - spec_compliance: - score: 15 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct Gantt chart with dependencies using specialized ganttChart() - constructor. - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: 'All spec requirements present: dependency arrows, visual styles, - group headers, indentation, legend, correct scheduling, hierarchy.' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: X-axis maps to timeline (Jan-Mar 2024), y-axis maps to hierarchical - task structure. - - id: SC-04 - name: Title & Legend - score: 3 - max: 3 - passed: true - comment: Title follows exact format. Custom legend explains critical path - vs non-critical styles. - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: 'Comprehensive: 4 phases, 12 tasks, 2 milestones. Sequential, parallel, - and multi-dependency relationships shown.' - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Software development lifecycle is a real-world, neutral scenario - with authentic task names. - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: 3-month project timeline with realistic task durations of 5 days - to 3 weeks. - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: 'Linear flow: imports, download JS, chart config, HTML, screenshot, - cleanup, save HTML.' - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: 'Fully deterministic: all dates and task data are hardcoded constants.' - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: 'All imports used: tempfile, time, urllib.request, Path, selenium.' - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Clean, well-commented code with structured chart config. No fake - functionality. - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Saves as plot.png via container.screenshot(). Also generates plot.html. - Uses current Highcharts 11.4.8. - library_mastery: - score: 10 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 5 - max: 5 - passed: true - comment: 'Expert Highcharts Gantt API usage: ganttChart(), parent-child hierarchy, - dependency objects, milestones, connectors config, renderer API.' - - id: LM-02 - name: Distinctive Features - score: 5 - max: 5 - passed: true - comment: 'Leverages Highcharts-unique Gantt module: built-in dependency connectors - with routing, parent-child grouping, milestone support, renderer API for - custom legend.' - verdict: APPROVED -impl_tags: - dependencies: - - selenium - techniques: - - html-export - - custom-legend - patterns: - - data-generation - dataprep: [] - styling: - - grid-styling - - edge-highlighting + strengths: [] + weaknesses: []