MigoFast MigoFast - 2 months ago 7
Python Question

How to align nodes and edges in networkx

I am going through an O'Reilly data science book and it gives you the python code to more or less create this node viz ...

enter image description here

But it doesn't tell you how to make the viz as its not really relevant to the subject but I wanted to take a crack at it anyway and so far this is as close as I've come

users = [
{ "id": 0, "name": "Hero" },
{ "id": 1, "name": "Dunn" },
{ "id": 2, "name": "Sue" },
{ "id": 3, "name": "Chi" },
{ "id": 4, "name": "Thor" },
{ "id": 5, "name": "Clive" },
{ "id": 6, "name": "Hicks" },
{ "id": 7, "name": "Devin" },
{ "id": 8, "name": "Kate" },
{ "id": 9, "name": "Klein" },
{ "id": 10, "name": "Jen" }
]

friendships = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 4),
(4, 5), (5, 6), (5, 7), (6, 8), (7, 8), (8, 9)]

import networkx as nx
import matplotlib as plt
%matplotlib inline
G=nx.Graph()
G.add_nodes_from([user["id"] for user in users])
G.add_edges_from(friendships)
pos = nx.spring_layout(G)
nx.draw_networkx(G, pos, node_size=1000)


enter image description here

This is brand new to me both python and networkx - I can't seem to figure out from their documentation what actual graph I should be using - I tried just about every one of them and none get me there - is it possible in networkx to align nodes this way and what is the correct graph to use?

Is networkx the right tool for this job is there a better python lib for this task?

UPDATE

@Aric answer was perfect but I made a couple changes to make the nodes match the data rather than the static type array. I don't think this is the 'best' way to do the calculation someone with more python experience would know better. I played with the minimum sizes and positions for a bit and STILL I could not get it pixel perfect but still I'm pretty happy with the end result

import networkx as nx
import matplotlib.pyplot as plt
G=nx.Graph()
G.add_nodes_from([user["id"] for user in users])
G.add_edges_from(friendships)
pos = {0: [0,0],
1: [4,-0.35],
2: [4,0.35],
3: [8,0],
4: [12,0],
5: [16,0],
6: [20,0.35],
7: [20,-0.35],
8: [24,0],
9: [28,0],
10: [32,0]}

nodes = [user["id"] for user in users]
def calcSize(node):
minSize = 450
friends = number_of_friends(node)
if friends <= 0:
return minSize
return minSize * friends

node_size = [(calcSize(user)) for user in users]
nx.draw_networkx(G, pos, nodelist=nodes, node_size=node_size, node_color='#c4daef')
plt.ylim(-1,1)
plt.axis('off')

Answer

You can so something similar with NetworkX. You'll need use a different layout method than "spring_layout" or set the node positions explicitly like this:

import networkx as nx
import matplotlib.pyplot as plt
G=nx.Graph()
G.add_nodes_from([user["id"] for user in users])
G.add_edges_from(friendships)
pos = {0: [0,0],
       1: [1,-0.25],
       2: [1,0.25],
       3: [2,0],
       4: [3,0],
       5: [4,0],
       6: [5,0.25],
       7: [5,-0.25],
       8: [6,0],
       9: [7,0],
       10: [8,0]}

nodes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
node_size = [500, 1000, 1000, 1000,  500, 1000, 500, 500 , 1000, 300, 300]
nx.draw_networkx(G, pos, nodelist=nodes, node_size=node_size, node_color='#c4daef')
plt.ylim(-1,1)
plt.axis('off')

enter image description here

Comments