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