3
votes

I'm drawing to draw a simple undirected graph with networkx and I'm having trouble coloring the nodes according to a specific attribute. I created a dictionary, in which case the key references a list of nodes that contain that attribute. It looks like so:

{ 
  1 : [1, 2, 3, 4],
  3 : [9, 11, 10, 8],
  2 : [7, 5, 6]
}

I would like to render the graph so that each set of nodes is colored differently. The keys are used to access a specific color. I draw the graph like so:

colors = [(random.random(), random.random(), random.random()) for i in xrange(0, 3)]
pos = nx.circular_layout(G) 
for k,v in node_list_dict.iteritems():
   nc = colors[int(k)-1]
   nx.draw_networkx_nodes(G, pos, nodelist=v, node_color=nc)
nx.draw_networkx_edges(G, pos)  
nx.draw_networkx_labels(G, pos) 

This almost works, but results in an image like:

Almost correct graph

So it appears that the first two sets render correctly, but the last one does not. Any idea as to why? I looked at the documentation but I don't see why it's failing.

Also, the colors list usually ends up like so (when I mean usually I mean the colors generated are somewhat random)

[(0.982864745272968, 0.038693538759121182, 0.03869353875912118), (0.12848750206109338,    0.9956534627440381, 0.12848750206109338), (0.050388282183359334, 0.050388282183359334, 0.9916284269963801)]
1
can you add the code to generate the graph?tacaswell

1 Answers

5
votes

You seem to have discovered an interesting broadcasting problem.

The trigger for this issue is when len(v) == len(nc), as according to the documentation:

node_color : color string, or array of floats
   Node color. Can be a single color format string (default='r'),
   or a  sequence of colors with the same length as nodelist.
   If numeric values are specified they will be mapped to
   colors using the cmap and vmin,vmax parameters.  See
   matplotlib.scatter for more details.

so when len(v) != 3 nc is interpreted as RGB triple, when len(v) == 3, the floats in nc are mapped to RGB via the default color map (which is jet).

A possible work-around for this is

for k,v in node_list_dict.iteritems():
   nc = colors[int(k)-1]
   if len(v) == 3:
       nc = nc +  (1,)
   nx.draw_networkx_nodes(G, pos, nodelist=v, node_color=nc)

which turns nc into a RGBA tuple, which won't trigger the usage of the color map. enter image description here

If you want to track this down, the main work of draw_network_nodes is done here by a call to scatter. There is a comment in the scatter function (here) that marks this as a known problem and states how the ambiguity is broken. If you feel really strongly about this, you can create an issue on github, but I don't think it will get traction, as this is an explicit design decision.