TypeError due to float() argument when I create a network with nodes colored using a colormap

Viewed 97

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.

1 Answers

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:

coloured graph

Related