简体   繁体   中英

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 eg, 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.

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在此处输入图片说明


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.

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()

在此处输入图片说明

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:

在此处输入图片说明

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()

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM