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}

Graph Output