diff --git a/plots/network-weighted/implementations/highcharts.py b/plots/network-weighted/implementations/highcharts.py new file mode 100644 index 0000000000..46b0cd37f8 --- /dev/null +++ b/plots/network-weighted/implementations/highcharts.py @@ -0,0 +1,324 @@ +""" pyplots.ai +network-weighted: Weighted Network Graph with Edge Thickness +Library: highcharts unknown | Python 3.13.11 +Quality: 90/100 | Created: 2026-01-08 +""" + +import json +import tempfile +import time +import urllib.request +from pathlib import Path + +import numpy as np +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + + +# Data: Research collaboration network between university departments +np.random.seed(42) + +# Departments (nodes) +departments = [ + {"id": "CS", "name": "Computer Science"}, + {"id": "MATH", "name": "Mathematics"}, + {"id": "PHYS", "name": "Physics"}, + {"id": "STAT", "name": "Statistics"}, + {"id": "EE", "name": "Electrical Eng."}, + {"id": "ME", "name": "Mechanical Eng."}, + {"id": "BIO", "name": "Biology"}, + {"id": "CHEM", "name": "Chemistry"}, + {"id": "ECON", "name": "Economics"}, + {"id": "PSYCH", "name": "Psychology"}, + {"id": "MED", "name": "Medicine"}, + {"id": "ENV", "name": "Environmental Sci."}, +] + +# Collaboration edges with weights (number of joint publications) +edges = [ + ("CS", "MATH", 45), + ("CS", "STAT", 38), + ("CS", "EE", 52), + ("CS", "PHYS", 22), + ("MATH", "STAT", 41), + ("MATH", "PHYS", 35), + ("MATH", "ECON", 18), + ("PHYS", "EE", 28), + ("PHYS", "CHEM", 25), + ("STAT", "ECON", 32), + ("STAT", "PSYCH", 24), + ("STAT", "BIO", 19), + ("EE", "ME", 33), + ("BIO", "CHEM", 47), + ("BIO", "MED", 55), + ("CHEM", "ENV", 29), + ("MED", "PSYCH", 21), + ("MED", "BIO", 55), + ("ENV", "BIO", 26), + ("ECON", "PSYCH", 15), +] + +# Calculate weighted degree for node sizing +weighted_degree = {d["id"]: 0 for d in departments} +for src, tgt, w in edges: + weighted_degree[src] += w + weighted_degree[tgt] += w + +# Normalize for marker size (bigger nodes = more collaborations) +max_degree = max(weighted_degree.values()) +min_degree = min(weighted_degree.values()) + +# Colors for nodes - colorblind-safe palette +colors = [ + "#306998", + "#FFD43B", + "#9467BD", + "#17BECF", + "#8C564B", + "#E377C2", + "#7F7F7F", + "#BCBD22", + "#1F77B4", + "#FF7F0E", + "#2CA02C", + "#D62728", +] + +# Create nodes for Highcharts networkgraph +nodes_data = [] +for i, dept in enumerate(departments): + deg = weighted_degree[dept["id"]] + # Scale marker size between 50 and 120 based on weighted degree + marker_size = 50 + 70 * (deg - min_degree) / (max_degree - min_degree) + nodes_data.append( + {"id": dept["id"], "name": dept["name"], "marker": {"radius": marker_size}, "color": colors[i % len(colors)]} + ) + +# Create links with width based on weight +# Scale line width between 4 and 24 based on weight +min_weight = min(w for _, _, w in edges) +max_weight = max(w for _, _, w in edges) + +links_data = [] +for src, tgt, weight in edges: + width = 4 + 20 * (weight - min_weight) / (max_weight - min_weight) + links_data.append({"from": src, "to": tgt, "width": round(width, 1)}) + +# Convert links and nodes to JSON for embedding +links_json = json.dumps(links_data) +nodes_json = json.dumps(nodes_data) + +# Download Highcharts JS and networkgraph module +highcharts_url = "https://code.highcharts.com/highcharts.js" +networkgraph_url = "https://code.highcharts.com/modules/networkgraph.js" + +with urllib.request.urlopen(highcharts_url, timeout=30) as response: + highcharts_js = response.read().decode("utf-8") + +with urllib.request.urlopen(networkgraph_url, timeout=30) as response: + networkgraph_js = response.read().decode("utf-8") + +# Generate HTML with inline scripts, weight legend, and custom link width rendering +html_content = f""" + + + + + + + + +
+
+

Edge Weight (Publications)

+
+
+ {min_weight} publications +
+
+
+ ~{(min_weight + max_weight) // 2} publications +
+
+
+ {max_weight} publications +
+
+ + +""" + +# Write temp HTML and take screenshot +with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: + f.write(html_content) + temp_path = f.name + +# Also save as plot.html for interactive viewing +with open("plot.html", "w", encoding="utf-8") as f: + f.write(html_content) + +chrome_options = Options() +chrome_options.add_argument("--headless") +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=4900,2800") + +driver = webdriver.Chrome(options=chrome_options) +driver.get(f"file://{temp_path}") +time.sleep(10) # Wait for network simulation to settle +driver.save_screenshot("plot.png") +driver.quit() + +Path(temp_path).unlink() # Clean up temp file diff --git a/plots/network-weighted/metadata/highcharts.yaml b/plots/network-weighted/metadata/highcharts.yaml new file mode 100644 index 0000000000..f6dd3c4617 --- /dev/null +++ b/plots/network-weighted/metadata/highcharts.yaml @@ -0,0 +1,210 @@ +library: highcharts +specification_id: network-weighted +created: '2026-01-08T16:03:42Z' +updated: '2026-01-08T16:22:21Z' +generated_by: claude-opus-4-5-20251101 +workflow_run: 20822859689 +issue: 3290 +python_version: 3.13.11 +library_version: unknown +preview_url: https://storage.googleapis.com/pyplots-images/plots/network-weighted/highcharts/plot.png +preview_thumb: https://storage.googleapis.com/pyplots-images/plots/network-weighted/highcharts/plot_thumb.png +preview_html: https://storage.googleapis.com/pyplots-images/plots/network-weighted/highcharts/plot.html +quality_score: 90 +review: + strengths: + - Excellent implementation of weighted network graph using Highcharts networkgraph + module + - Node sizing by weighted degree adds meaningful visual information + - Custom legend clearly explains the edge weight scale + - Force-directed layout with verlet integration provides good node positioning + - Colorblind-safe palette with distinct colors for each department + - Clean data structure with realistic university collaboration scenario + weaknesses: + - Legend positioned in bottom-left is far from the main visualization + - Network could utilize more of the canvas space for better visibility + - Post-render timeout approach for link widths is a workaround rather than native + solution + image_description: 'The plot displays a weighted network graph showing university + department collaboration patterns. There are 12 department nodes rendered as colored + circles: CS (blue), MATH (blue), PHYS (purple), STAT (cyan), EE (brown), ME (pink), + BIO (gray), CHEM (olive-yellow), ECON (blue), PSYCH (orange), MED (green), and + ENV (red). Node sizes vary based on weighted degree - BIO and CS appear as the + largest nodes indicating highest collaboration activity. Edges connect departments + with varying thickness representing the number of joint publications (ranging + from 15 to 55). The thickest edges connect BIO-MED (55 publications) and CS-EE + (52 publications). A legend in the bottom-left corner explains the edge weight + scale with three line thickness examples. The title ''network-weighted · highcharts + · pyplots.ai'' appears at the top with a subtitle ''University Department Collaboration + Network''. The network uses a force-directed layout centered in the canvas.' + criteria_checklist: + visual_quality: + score: 36 + max: 40 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 10 + passed: true + comment: Labels readable but could be larger for 4800x2700 canvas + - id: VQ-02 + name: No Overlap + score: 8 + max: 8 + passed: true + comment: No overlapping text or elements + - id: VQ-03 + name: Element Visibility + score: 8 + max: 8 + passed: true + comment: Nodes well-sized, edges clearly distinguishable by thickness + - id: VQ-04 + name: Color Accessibility + score: 5 + max: 5 + passed: true + comment: Colorblind-safe palette with good variety + - id: VQ-05 + name: Layout Balance + score: 3 + max: 5 + passed: true + comment: Network centered but could use more canvas space; legend far from + main visualization + - id: VQ-06 + name: Axis Labels + score: 2 + max: 2 + passed: true + comment: N/A for network graphs, subtitle provides context + - id: VQ-07 + name: Grid & Legend + score: 2 + max: 2 + passed: true + comment: Legend well-designed with clear thickness examples + spec_compliance: + score: 25 + max: 25 + items: + - id: SC-01 + name: Plot Type + score: 8 + max: 8 + passed: true + comment: Correct weighted network graph + - id: SC-02 + name: Data Mapping + score: 5 + max: 5 + passed: true + comment: Edge thickness correctly maps to weights + - id: SC-03 + name: Required Features + score: 5 + max: 5 + passed: true + comment: Weighted edges, node sizing by degree, legend present + - id: SC-04 + name: Data Range + score: 3 + max: 3 + passed: true + comment: All nodes and edges visible + - id: SC-05 + name: Legend Accuracy + score: 2 + max: 2 + passed: true + comment: Edge weight legend accurate with min/mid/max values + - id: SC-06 + name: Title Format + score: 2 + max: 2 + passed: true + comment: 'Correct format: network-weighted · highcharts · pyplots.ai' + data_quality: + score: 17 + max: 20 + items: + - id: DQ-01 + name: Feature Coverage + score: 7 + max: 8 + passed: true + comment: Shows varied edge weights and node degrees; could show more weight + variation + - id: DQ-02 + name: Realistic Context + score: 7 + max: 7 + passed: true + comment: University collaboration is neutral and realistic + - id: DQ-03 + name: Appropriate Scale + score: 3 + max: 5 + passed: true + comment: Publication counts realistic but some weights very similar + code_quality: + score: 9 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Linear structure: imports → data → plot → save' + - id: CQ-02 + name: Reproducibility + score: 3 + max: 3 + passed: true + comment: Uses np.random.seed(42) + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All imports used + - id: CQ-04 + name: No Deprecated API + score: 1 + max: 1 + passed: true + comment: Current Highcharts API + - id: CQ-05 + name: Output Correct + score: 0 + max: 1 + passed: false + comment: Saves as plot.png but also plot.html (minor) + library_features: + score: 3 + max: 5 + items: + - id: LF-01 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Uses networkgraph module, force-directed layout, custom link widths + via post-render update + verdict: APPROVED +impl_tags: + dependencies: + - selenium + techniques: + - custom-legend + - html-export + - hover-tooltips + patterns: + - data-generation + - iteration-over-groups + dataprep: + - normalization + styling: + - edge-highlighting