I'm trying to make a graph in networkx. I'm having trouble assigning different node sizes to the nodes.
Here is my code I've been playing with:
import sys
from collections import defaultdict
import networkx as nx
import matplotlib.pyplot as plt
inp = sys.argv[1]
cluster = sys.argv[1] + ".cluster"
counts = sys.argv[1] + ".counts"
with open(cluster, "r") as f1:
edges = [line.strip().split('\t') for line in f1]
with open(counts, "r") as f2:
countsdic = defaultdict(list)
for line in f2:
k,v = line.strip().split()
countsdic[k].append(v)
tmp = []
for el in sum(edges, []):
tmp.append(el)
nodes = []
for t in tmp:
if t not in nodes:
nodes.append(t)
node_sizes = {}
for n in nodes:
node_sizes[n] = ' '.join(countsdic[n])
print node_sizes
nodes2 = []
sizes = []
for k in node_sizes.keys():
nodes2.append(k)
for v in node_sizes.values():
sizes.append(v)
print nodes2
print len(nodes2)
print sizes
print len(sizes)
g = nx.Graph()
g.add_nodes_from(nodes)
g.add_edges_from(edges)
nx.draw_random(g, node_list = nodes2, node_size = sizes)
# I've also tried assigning node_list and node_size with node_sizes.keys() and node_sizes.values()
plt.savefig(inp + "." + gtype + ".png")
plt.show()
If I do not attempt to change the node sizes, I get a pretty decent graph. The dictionary values are between 1 and 10, with a few high values like 156 which I need to be the largest, so I would need to do something like: node_sizes = [n*100 for n in sizes] for the smaller values to at least appear on the graph and the larger values to appear relevant, but that didn't work either.
The error I get is:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in __call__
return self.func(*args)
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 276, in resize
self.show()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 348, in draw
FigureCanvasAgg.draw(self)
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_agg.py", line 451, in draw
self.figure.draw(self.renderer)
File "/usr/lib/pymodules/python2.7/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/figure.py", line 1034, in draw
func(*args)
File "/usr/lib/pymodules/python2.7/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/axes.py", line 2086, in draw
a.draw(renderer)
File "/usr/lib/pymodules/python2.7/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/collections.py", line 717, in draw
for x in self._sizes]
TypeError: Not implemented for this type
After a couple hours of google searching, I am unable to resolve the issue. Here is a generated without changing the node sizes:
All comments and help are appreciated.
2014/07/08 12:29PM: Updated to reflect comments from @user3358205
The problem is that the drawing functions in NetworkX require node_sizes
to be input as a list
of int
s, while you are passing a list
of strings. You can read the parameters to the drawing functions here.
Because I don't have the input files to your program, I can't reproduce your output. However, here's an example where you vary the size of the nodes by passing a list
of node_sizes
. Note that in the output, I am labeling each node by their size.
import sys, networkx as nx, matplotlib.pyplot as plt
# Create a list of 10 nodes numbered [0, 9]
nodes = range(10)
node_sizes = []
labels = {}
for n in nodes:
node_sizes.append( 100 * n )
labels[n] = 100 * n
# Node sizes: [0, 100, 200, 300, 400, 500, 600, 700, 800, 900]
# Connect each node to its successor
edges = [ (i, i+1) for i in range(len(nodes)-1) ]
# Create the graph and draw it with the node labels
g = nx.Graph()
g.add_nodes_from(nodes)
g.add_edges_from(edges)
nx.draw_random(g, node_size = node_sizes, labels=labels, with_labels=True)
plt.show()
With mdml's answer I was able to answer solve the problem. As it turns out I was passing a list to networkx for node sizes, although it did not appreciate the list. I was appending strings to the list, not integers. Changing v to and int() solves this problem, then I multiplied by 100, since some of the values were small, to make the node sizes relevant:
with open(cluster, "r") as f1:
edges = [line.strip().split('\t') for line in f1]
with open(counts, "r") as f2:
countsdic = defaultdict(list)
for line in f2:
k,v = line.strip().split()
countsdic[k].append(v)
tmp = []
for el in sum(edges, []):
tmp.append(el)
nodes = []
for t in tmp:
if t not in nodes:
nodes.append(t)
node_sizes = {}
for n in nodes:
node_sizes[n] = ' '.join(countsdic[n])
sizes = []
for v in node_sizes.values():
x = int(v) * 100
sizes.append(x)
g = nx.Graph()
g.add_nodes_from(nodes)
g.add_edges_from(edges)
nx.draw_random(g, node_size = sizes)
plt.savefig(inp + "." + gtype + ".png")
plt.show()
The graph output I was looking for:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With