Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw different color for nodes in networkx based on their node value

I have a large graph of nodes and directed edges. Furthermore, I have an additional list of values assigned to each node.

I now want to change the color of each node according to their node value. So e.g., drawing nodes with a very high value red and those with a low value blue (similar to a heatmap). Is this somehow easily possible to achieve? If not with networkx, I am also open for other libraries in Python.

like image 301
fsociety Avatar asked Nov 22 '12 17:11

fsociety


People also ask

What is Nbunch in NetworkX?

nbunch. An nbunch is a single node, container of nodes or None (representing all nodes). It can be a list, set, graph, etc.. To filter an nbunch so that only nodes actually in G appear, use G.

What is a DiGraph in NetworkX?

A DiGraph stores nodes and edges with optional data, or attributes. DiGraphs hold directed edges. Self loops are allowed but multiple (parallel) edges are not. Nodes can be arbitrary (hashable) Python objects with optional key/value attributes.

Which data type can be used as the content of a node in NetworkX?

In NetworkX, nodes can be any hashable object e.g., a text string, an image, an XML object, another Graph, a customized node object, etc. Python's None object is not allowed to be used as a node.


2 Answers

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt

G = nx.Graph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

val_map = {'A': 1.0,
           'D': 0.5714285714285714,
           'H': 0.0}

values = [val_map.get(node, 0.25) for node in G.nodes()]

nx.draw(G, cmap=plt.get_cmap('viridis'), node_color=values, with_labels=True, font_color='white')
plt.show()

yields enter image description here


The numbers in values are associated with the nodes in G.nodes(). That is to say, the first number in values is associated with the first node in G.nodes(), and similarly for the second, and so on.

like image 97
unutbu Avatar answered Oct 23 '22 05:10

unutbu


For the general case, in which we have a list of values indicating some attribute of a node, and we want to assign a colour to the given node which gives a sense of scale of that attribute (reds to blues for instance), here's one approach:

import matplotlib as mpl
from matplotlib import pyplot as plt
from pylab import rcParams
import networkx as nx

G = nx.Graph()
G.add_edges_from([('A', 'D'), ('Z', 'D'), ('F', 'J'), ('A', 'E'), ('E', 'J'),('Z', 'K'), ('B', 'A'), ('B', 'D'), ('A', 'J'), ('Z', 'F'),('Z', 'D'), ('A', 'B'), ('J', 'D'), ('J', 'E'), ('Z', 'J'),('K', 'J'), ('B', 'F'), ('B', 'J'), ('A', 'Z'), ('Z', 'E'),('C', 'Z'), ('C', 'A')])

Say that we have the following dictionary mapping a each node to a given value:

color_lookup = {k:v for v, k in enumerate(sorted(set(G.nodes())))}
# {'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'J': 6, 'K': 7, 'Z': 8}

What we could do is to use mpl.colors.Normalize to normalize the values in color_lookup to the range [0,1] based on the minimum and maximum values that the nodes take, and then matplotlib.cm.ScalarMappable to map the normalized values to colours in a colourmap, here I'll be using mpl.cm.coolwarm:

low, *_, high = sorted(color_lookup.values())
norm = mpl.colors.Normalize(vmin=low, vmax=high, clip=True)
mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.coolwarm)

rcParams['figure.figsize'] = 12, 7
nx.draw(G, 
        nodelist=color_lookup,
        node_size=1000,
        node_color=[mapper.to_rgba(i) 
                    for i in color_lookup.values()], 
        with_labels=True)
plt.show()

enter image description here

For another colour map we'd just have to change the cmap parameter in mpl.cm.ScalarMappable:

mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.summer)
nx.draw(G, 
        nodelist=color_lookup,
        node_size=1000,
        node_color=[mapper.to_rgba(i) 
                    for i in color_lookup.values()], 
        with_labels=True)
plt.show()

Where we'd get:

enter image description here

Similarly, we could set the colour of a node based on the degree of a node by defining a dictionary mapping all nodes to their corresponding degree, and taking the same steps as above:

d = dict(G.degree)
# {'A': 6, 'D': 4, 'Z': 7, 'F': 3, 'J': 7, 'E': 3, 'K': 2, 'B': 4, 'C': 2}
low, *_, high = sorted(d.values())
norm = mpl.colors.Normalize(vmin=low, vmax=high, clip=True)
mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.coolwarm)

nx.draw(G, 
        nodelist=d,
        node_size=1000,
        node_color=[mapper.to_rgba(i) 
                    for i in d.values()], 
        with_labels=True,
        font_color='white')
plt.show()

enter image description here

like image 10
yatu Avatar answered Oct 23 '22 05:10

yatu