Skip to content

Commit ed44e30

Browse files
feat(highcharts): implement network-force-directed (#5440)
## Implementation: `network-force-directed` - python/highcharts Implements the **python/highcharts** version of `network-force-directed`. **File:** `plots/network-force-directed/implementations/python/highcharts.py` **Parent Issue:** #990 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/24953021958)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent d84bcba commit ed44e30

2 files changed

Lines changed: 211 additions & 162 deletions

File tree

plots/network-force-directed/implementations/python/highcharts.py

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
network-force-directed: Force-Directed Graph
3-
Library: highcharts unknown | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-23
3+
Library: highcharts unknown | Python 3.14.4
4+
Quality: 83/100 | Updated: 2026-04-26
55
"""
66

7+
import os
78
import random
89
import tempfile
910
import time
@@ -14,6 +15,15 @@
1415
from selenium.webdriver.chrome.options import Options
1516

1617

18+
# Theme tokens
19+
THEME = os.getenv("ANYPLOT_THEME", "light")
20+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
21+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
22+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
23+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
24+
GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
25+
LABEL_OUTLINE = PAGE_BG
26+
1727
# Data - Social network with communities
1828
random.seed(42)
1929

@@ -25,13 +35,8 @@
2535
"Design": ["Amy", "Ben", "Chloe", "Dan", "Emma", "Finn", "Gina", "Hugo"],
2636
}
2737

28-
# Community colors (colorblind-safe)
29-
community_colors = {
30-
"Tech": "#306998", # Python Blue
31-
"Marketing": "#FFD43B", # Python Yellow
32-
"Finance": "#9467BD", # Purple
33-
"Design": "#17BECF", # Cyan
34-
}
38+
# Community colors — Okabe-Ito positions 1-4
39+
community_colors = {"Tech": "#009E73", "Marketing": "#D55E00", "Finance": "#0072B2", "Design": "#CC79A7"}
3540

3641
# Build nodes with community info
3742
nodes = []
@@ -70,21 +75,14 @@
7075
edges.append({"from": person1, "to": person2})
7176
added_edges.add(edge)
7277

73-
# Prepare series data
74-
series_data = []
75-
for edge in edges:
76-
series_data.append([edge["from"], edge["to"]])
77-
78-
# Create node configurations with larger markers
78+
# Create node configurations
7979
node_configs = []
8080
for n in nodes:
81-
node_configs.append(
82-
{"id": n["id"], "color": n["color"], "marker": {"radius": 45}, "dataLabels": {"style": {"fontSize": "28px"}}}
83-
)
81+
node_configs.append({"id": n["id"], "color": n["color"], "marker": {"radius": 32}})
8482

8583
# Download Highcharts JS and networkgraph module
86-
highcharts_url = "https://code.highcharts.com/highcharts.js"
87-
networkgraph_url = "https://code.highcharts.com/modules/networkgraph.js"
84+
highcharts_url = "https://cdnjs.cloudflare.com/ajax/libs/highcharts/11.4.8/highcharts.js"
85+
networkgraph_url = "https://cdnjs.cloudflare.com/ajax/libs/highcharts/11.4.8/modules/networkgraph.js"
8886

8987
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
9088
highcharts_js = response.read().decode("utf-8")
@@ -95,7 +93,7 @@
9593
# Build chart configuration as raw JavaScript for better control
9694
nodes_js = "[\n"
9795
for n in node_configs:
98-
nodes_js += f' {{id: "{n["id"]}", color: "{n["color"]}", marker: {{radius: 45}}}},\n'
96+
nodes_js += f' {{id: "{n["id"]}", color: "{n["color"]}", marker: {{radius: 32}}}},\n'
9997
nodes_js += "]"
10098

10199
data_js = "[\n"
@@ -109,38 +107,48 @@
109107
type: 'networkgraph',
110108
width: 4800,
111109
height: 2700,
112-
backgroundColor: '#ffffff'
110+
backgroundColor: '{PAGE_BG}',
111+
style: {{color: '{INK}'}}
113112
}},
114113
title: {{
115-
text: 'network-force-directed · highcharts · pyplots.ai',
116-
style: {{fontSize: '56px', fontWeight: 'bold'}}
114+
text: 'network-force-directed · highcharts · anyplot.ai',
115+
style: {{fontSize: '56px', fontWeight: 'bold', color: '{INK}'}}
117116
}},
118117
subtitle: {{
119-
text: 'Social Network with 4 Communities (Tech: Blue, Marketing: Yellow, Finance: Purple, Design: Cyan)',
120-
style: {{fontSize: '32px', color: '#666666'}}
118+
useHTML: true,
119+
text: '<span style="font-size:32px;color:{INK_SOFT};">Communication ties across four departments — dense within, sparse between</span><br/>'
120+
+ '<span style="font-size:30px;">'
121+
+ '<span style="color:#009E73;">&#9679;</span> <span style="color:{INK};">Tech</span> &nbsp;&nbsp;&nbsp;'
122+
+ '<span style="color:#D55E00;">&#9679;</span> <span style="color:{INK};">Marketing</span> &nbsp;&nbsp;&nbsp;'
123+
+ '<span style="color:#0072B2;">&#9679;</span> <span style="color:{INK};">Finance</span> &nbsp;&nbsp;&nbsp;'
124+
+ '<span style="color:#CC79A7;">&#9679;</span> <span style="color:{INK};">Design</span>'
125+
+ '</span>',
126+
style: {{fontSize: '32px', color: '{INK_SOFT}'}}
121127
}},
128+
legend: {{enabled: false}},
122129
plotOptions: {{
123130
networkgraph: {{
124131
layoutAlgorithm: {{
125132
enableSimulation: true,
126133
friction: -0.9,
127-
linkLength: 250,
128-
gravitationalConstant: 0.02,
134+
linkLength: 650,
135+
gravitationalConstant: 0.06,
129136
integration: 'verlet',
130-
maxIterations: 1000
137+
maxIterations: 1500
131138
}},
132139
dataLabels: {{
133140
enabled: true,
134141
linkFormat: '',
135142
style: {{
136143
fontSize: '26px',
137144
fontWeight: 'bold',
138-
textOutline: '3px white'
145+
color: '{INK}',
146+
textOutline: '3px {LABEL_OUTLINE}'
139147
}}
140148
}},
141149
link: {{
142150
width: 4,
143-
color: '#999999'
151+
color: '{GRID}'
144152
}}
145153
}}
146154
}},
@@ -161,14 +169,14 @@
161169
<script>{highcharts_js}</script>
162170
<script>{networkgraph_js}</script>
163171
</head>
164-
<body style="margin:0; padding:0;">
172+
<body style="margin:0; padding:0; background:{PAGE_BG};">
165173
<div id="container" style="width: 4800px; height: 2700px;"></div>
166174
<script>{chart_js}</script>
167175
</body>
168176
</html>"""
169177

170178
# Save HTML file
171-
with open("plot.html", "w", encoding="utf-8") as f:
179+
with open(f"plot-{THEME}.html", "w", encoding="utf-8") as f:
172180
f.write(html_content)
173181

174182
# Take screenshot with Selenium
@@ -186,7 +194,7 @@
186194
driver = webdriver.Chrome(options=chrome_options)
187195
driver.get(f"file://{temp_path}")
188196
time.sleep(12) # Wait longer for force simulation to stabilize
189-
driver.save_screenshot("plot.png")
197+
driver.save_screenshot(f"plot-{THEME}.png")
190198
driver.quit()
191199

192200
Path(temp_path).unlink()

0 commit comments

Comments
 (0)