Python networkx Library
Environment Setup
I ran into an issue when running pip install networkx
. I had to CD to the path where I had Python installed. To find out where Python is installed, use:
1where Python
and the output should resemble:
1C:\Users\<you>\AppData\Local\anaconda3\python.exe
2C:\Users\<you>\AppData\Local\Programs\Python\Python311\python.exe
3C:\Users\<you>\AppData\Local\Microsoft\WindowsApps\python.exe
followed by:
1cd C:\Users\<you>\AppData\Local\Programs\Python\Python311\python.exe
2pip install networkx
Python Script
1import json
2import networkx as nx
3import matplotlib.pyplot as plt
4import numpy as np
5from matplotlib.patches import Ellipse
6
7# Load the JSON data
8with open("dummy-data.json", "r") as file:
9 data = json.load(file)
10
11# Create a graph
12G = nx.DiGraph()
13
14# Add nodes and edges to the graph from the JSON data
15node_colors = {}
16group_nodes = {} # {group: [node1, node2, ...]}
17for group, details in data["groups"].items():
18 if group not in group_nodes:
19 group_nodes[group] = []
20 for edge in details["edges"]:
21 G.add_edge(edge["source"], edge["target"], color=details["color"], label=edge["label"])
22 node_colors[edge["source"]] = details["color"]
23 group_nodes[group].append(edge["source"])
24 group_nodes[group].append(edge["target"])
25
26# Compute node positions
27width, height = 2, 2
28pos = {}
29center_node = "source-node"
30pos[center_node] = (width / 2, height / 2)
31node_colors[center_node] = "#8888FF"
32
33# Positioning nodes around a circle
34shell_nodes = [node for node in G.nodes() if node != center_node]
35angle_step = 2 * np.pi / len(shell_nodes)
36for index, node in enumerate(shell_nodes):
37 angle = index * angle_step
38 pos[node] = (width/2 + 0.75*np.cos(angle), height/2 + 0.75*np.sin(angle))
39
40# Set DPI for the desired resolution
41dpi = 256
42fig, ax = plt.subplots(figsize=(24, 24), dpi=dpi)
43
44# Legend proxy artists
45from matplotlib.patches import Patch
46legend_handles = [
47 Patch(facecolor='#FF8888', edgecolor='black', label='group-01'),
48 Patch(facecolor='#88FF88', edgecolor='black', label='group-02')
49]
50
51colors = [node_colors[node] for node in G.nodes()]
52nx.draw_networkx_nodes(G, pos, node_color=colors, node_size=20000, ax=ax)
53nx.draw_networkx_labels(G, pos, ax=ax, font_size=14)
54
55for edge in G.edges(data=True):
56 nx.draw_networkx_edges(G, pos, edgelist=[(edge[0], edge[1])], ax=ax, edge_color=edge[2]["color"], width=2)
57
58edge_labels = nx.get_edge_attributes(G, 'label')
59nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=14)
60
61# Draw ellipses around groups of nodes
62for group, nodes in group_nodes.items():
63 unique_nodes = list(set(nodes))
64 coords = [pos[node] for node in unique_nodes]
65 x_coords, y_coords = zip(*coords)
66 center = np.mean(x_coords), np.mean(y_coords)
67 distances = [np.sqrt((x - center[0])**2 + (y - center[1])**2) for x, y in coords]
68 max_distance = max(distances)
69 ellipse = Ellipse(center, 2*max_distance, 2*max_distance, fill=False, edgecolor=node_colors[unique_nodes[0]], linestyle="--")
70 ax.add_patch(ellipse)
71
72# Adding the legend to the plot
73ax.legend(handles=legend_handles, loc='upper right')
74
75plt.axis("off")
76plt.tight_layout()
77plt.savefig("graph.png", format="png")
78plt.show()
JSON Schema
1{
2 "nodes": [],
3 "groups": {
4 "group-01": {
5 "color": "#FF8888",
6 "edges": [
7 {
8 "source": "group-01-node-01",
9 "target": "source-node",
10 "label": "label"
11 },
12 {
13 "source": "group-02-node-02",
14 "target": "source-node",
15 "label": "label"
16 },
17 {
18 "source": "group-03-node-03",
19 "target": "source-node",
20 "label": "label"
21 },
22 {
23 "source": "group-03-node-04",
24 "target": "source-node",
25 "label": "label"
26 },
27 {
28 "source": "group-04-node-05",
29 "target": "source-node",
30 "label": "label"
31 },
32 {
33 "source": "group-05-node-06",
34 "target": "source-node",
35 "label": "label"
36 },
37 {
38 "source": "group-06-node-07",
39 "target": "source-node",
40 "label": "label"
41 },
42 {
43 "source": "group-07-node-08",
44 "target": "source-node",
45 "label": "label"
46 }
47 ]
48 },
49 "group 02": {
50 "color": "#88FF88",
51 "edges": [
52 {
53 "source": "group-02-node-01",
54 "target": "source-node",
55 "label": "label"
56 },
57 {
58 "source": "group-02-node-02",
59 "target": "source-node",
60 "label": "label"
61 },
62 {
63 "source": "group-02-node-03",
64 "target": "source-node",
65 "label": "label"
66 },
67 {
68 "source": "group-02-node-04",
69 "target": "source-node",
70 "label": "label"
71 },
72 {
73 "source": "group-02-node-05",
74 "target": "source-node",
75 "label": "label"
76 }
77 ]
78 }
79 }
80}