I have the following two datasets
Node Edge
A B
A D
B N
B A
B X
S C
and
Nodes Attribute
A -9
B
C -1.5
D 1.0
...
N 1.0
...
X 0.0
Y -1.5
W -1.5
Z 1.0
where Attribute type is float64. For replication, you can use the following (unique Attribute elements, i.e., uni_val): array([ 9. , 0. , 1. , 0.5, -0.5, -1. , -1.5, -2. ])
I want to create a network using a color map for coloring nodes. I did as follows:
# Create map of color
uni_val=df2.Attribute.unique()
colors = plt.cm.jet(np.linspace(0,1,len(df2.Attribute.unique())))
n=0
val=[]
col=[]
for i in uni_val:
val.append(i)
col.append(colors[n])
n=n+1
mapper=dict(zip(val,col))
colour_map = df2.set_index('Nodes')['Attribute'].map(mapper)
# Create the network
G = nx.from_pandas_edgelist(df1, source='Node', target='Edge')
# Add Attribute to each node
nx.set_node_attributes(G, colour_map, name="colour")
# Then draw with colours based on attribute values:
nx.draw(G,
node_color=nx.get_node_attributes(G, 'colour').values(),
with_labels=True)
I am getting the following error:
TypeError: float() argument must be a string or a number, not 'dict_values'
but I do not understand what is causing it and how I can fix it. It would be great if you could help me to better understand it and show me a way to fix it.
The current mapping is incorrect. A valid colour code format is needed not arrays:
From the docs networkx.drawing.nx_pylab.draw_networkx
Node color. Can be a single color or a sequence of colors with the same length as nodelist. Color can be string or rgb (or rgba) tuple of floats from 0-1. If numeric values are specified they will be mapped to colors using the cmap and vmin,vmax parameters.
The following mapping is created with the current approach:
uni_val = np.array([9., 0., 1., 0.5, -0.5, -1., -1.5, -2.])
colors = plt.cm.jet(np.linspace(0, 1, len(uni_val)))
print(colors)
n = 0
val = []
col = []
for i in uni_val:
val.append(i)
col.append(colors[n])
n = n + 1
mapper = dict(zip(val, col))
mapper
:
{-2.0: array([0.5, 0. , 0. , 1. ]),
-1.5: array([1. , 0.18954248, 0. , 1. ]),
-1.0: array([1. , 0.72694263, 0. , 1. ]),
-0.5: array([0.71790006, 1. , 0.24984187, 1. ]),
0.0: array([0. , 0.06470588, 1. , 1. ]),
0.5: array([0.24984187, 1. , 0.71790006, 1. ]),
1.0: array([0. , 0.64509804, 1. , 1. ]),
9.0: array([0. , 0. , 0.5, 1. ])}
These arrays are invalid inputs for colours.
These arrays need to be converted into some valid form. A simple fix would be to use matplotlib.colors.to_hex
uni_val = np.array([9., 0., 1., 0.5, -0.5, -1., -1.5, -2.])
colors = plt.cm.jet(np.linspace(0, 1, len(uni_val)))
mapper = dict(zip(uni_val, map(mcolor.to_hex, colors)))
Which produces:
{-2.0: '#800000',
-1.5: '#ff3000',
-1.0: '#ffb900',
-0.5: '#b7ff40',
0.0: '#0010ff',
0.5: '#40ffb7',
1.0: '#00a4ff',
9.0: '#000080'}
All together it can look like:
import networkx as nx
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt, colors as mcolor
# Sample DataFrames
df1 = pd.DataFrame({
'Node': ['A', 'A', 'B', 'B', 'B', 'S'],
'Edge': ['B', 'D', 'N', 'A', 'X', 'C']
})
df2 = pd.DataFrame({
'Nodes': ['A', 'B', 'C', 'D', 'N', 'S', 'X'],
'Attribute': [-1, 0, -1.5, 1, 1, 9, 0]
})
# Simplified construction of `colour_map`
uni_val = df2['Attribute'].unique()
colors = plt.cm.jet(np.linspace(0, 1, len(uni_val)))
# Map colours to_hex then zip with
mapper = dict(zip(uni_val, map(mcolor.to_hex, colors)))
colour_map = df2.set_index('Nodes')['Attribute'].map(mapper)
G = nx.from_pandas_edgelist(df1, source='Node', target='Edge')
# Add Attribute to each node
nx.set_node_attributes(G, colour_map, name="colour")
# Then draw with colours based on attribute values:
nx.draw(G,
node_color=nx.get_node_attributes(G, 'colour').values(),
with_labels=True)
plt.show()
Producing a graph like: