Weighted graphs using NetworkX

I wanted to draw a network of nodes and use the thickness of the edges between the nodes to denote some information. Since I had used NetworkX a long time ago for drawing network graphs, I decided to use it again. This was going to be a one off visualization. So I did not want to spend too much time studying NetworkX.

I started by searching Google Images and then looked on StackOverflow for drawing weighted edges using NetworkX. Surprisingly neither had useful results. The NetworkX documentation on weighted graphs was a little too simplistic. It also annoyed me that their example/image will not immediately catch the eye of someone performing an image search like I did.

So I am writing this post and adding a couple of images in the hope that it helps people looking for a quick solution to drawing weighted graphs with NetworkX.

NOTE: The approach outlined here works well for a small set of nodes. I have not tried it on a large network.

The data

I like chess. So let us pretend I will be plotting how often Karpov, Kasparov, Kramnik and Anand played each other in classical chess. The data (as of Aug 2017) looks like this:

1. Karpov – Kasparov: 170 classical games
2. Karpov – Kramnik: 15 classical games
3. Karpov – Anand: 45 classical games
4. Kasparov – Kramnik: 49 classical games
5. Kasparov – Anand: 51 classical games
6. Kramnik – Anand: 91 classical games

Drawing weighted edges with NetworkX

I won’t go over the process of adding nodes, edges and labels to a graph. I assume you know that. If you are new to NetworkX, just read through the well-commented code in the next section.

Instead, I will focus on how to draw edges of different thickness. The process of drawing edges of different thickness between nodes looks like this:
a) Iterate through the graph nodes to gather all the weights
b) Get unique weights
c) Loop through the unique weights and plot any edges that match the weight
d) Normalize the weights (I did num_nodes/sum(all_weights)) so that no edge is too thick
e) Make changes to the weighting (I used a scalar multiplier) so the graph looks good

a) Iterate through the graph nodes to gather all the weights

 for (node1,node2,data) in G.edges(data=True): all_weights.append(data['weight']) #we'll use this when determining edge thickness

b) Get unique weights

 unique_weights = list(set(all_weights))

c) Loop through the unique weights and plot any edges that match the weight

 #4 c. Plot the edges - one by one! for weight in unique_weights: #4 d. Form a filtered list with just the weight you want to draw weighted_edges = [(node1,node2) for (node1,node2,edge_attr) in G.edges(data=True) if edge_attr['weight']==weight] width = weight nx.draw_networkx_edges(G,pos,edgelist=weighted_edges,width=width)

d) Normalize the weights
I did num_nodes/sum(all_weights) so that no edge is too thick

 #4 e. I think multiplying by [num_nodes/sum(all_weights)] makes the graphs edges look cleaner width = weight*len(node_list)/sum(all_weights)

But the resulting graph had very thin edges. So I decided to multiply all thickness by a factor of 5.

e) Make changes to the weighting
I used a scalar multiplier of 5 so the graph looks good

 #4 e. I think multiplying by [num_nodes/sum(all_weights)] makes the graphs edges look cleaner width = weight*len(node_list)*5.0/sum(all_weights)

Much better! I can quickly see that Karpov and Kasparov played each other many times. While Kramnik and Anand played each other quite a few times too. Given their respective ages and peaks, that makes sense.

One comment

1. Anonymous says:

Hi,
Thanks for sharing this. Just in case someone else stumbles upon your post, here is how I did it finally:

widths = [G.get_edge_data(*veza)[‘weight’] for veza in G.edges]
nx.draw_networkx_edges(G, pos=pos, width=widths, alpha=0.25, edge_cmap=plt.cm.viridis, edge_color=range(G.number_of_edges()));

Cheers!