pythondataframegraphnetworkxgraph-coloring

Networkx not coloring edges correctly by attribute


I am trying to depict a transport network in networkx and I have been doing good till now, but the problem is the following: I have loaded an edgelist from a txt file, which is in the following form:

61  1
54  79
66  134
68  57

etc. Also, in order to plot network nodes in the correct position, I have loaded and added to the Graph a txt with nodes coordinates which is in the following form:

1   478947.434  4204495.502
2   478909.145  4204244.629
3   479065.936  4204709.003
4   478880.827  4204297.676
5   478993.409  4204167.957

After that, I run the following script and my network is correctly depicted, position-wise.

import networkx as nx
import numpy as py
import copy
import matplotlib.pyplot as plt
import xlwings as xw
from xlwings import Book, Range

pos={}
with open(r'C:\Users\alexl\Documents\new_python\nodes_coordinates.txt') as f:
    for line in f:
        node, x, y = line.split()
        pos[node] = float(x), float(y)

print(pos)
network0 = nx.read_edgelist(r'C:\Users\alexl\Documents\new_python\init_edgelist.txt', create_using = nx.OrderedDiGraph)

nx.draw(network0, pos = pos, with_labels = True, edge_color = G, edge_cmap = plt.cm.Reds, connectionstyle = 'arc3,rad=0.1')
         

plt.show()

Now, what I want is to correctly assign "weights" to every edge, and color it by this attribute. For every edge there are 3 possible outcomes, 0, 1 and 2, so I want 3 different colours, for example, red for 0, green for 1 and blue for 2. What I have is a Python dictionary like this:

{0: 1.0, 1: 1.0, 2: 0.0, 3: 1.0, 4: 1.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 1.0,...

etc.The first value (1.0) corresponds to the first edge of edgelist above, the second (1.0) to the second, etc. But I see networkx does not understand this and does not colorize correctly my network. I converted dictionary to list and did the following:

var1 = G.values()
list1 = list(var1)
col = []
for n in range(len(list1)):
    if list1[n] == 0:
        col.append('b')
    elif list1[n] == 1:
        #col.append('r')
    else:
        #col.append('g') 
nx.draw(network0, pos = pos, with_labels = True, edge_color = col, edge_cmap = plt.cm.Reds, connectionstyle = 'arc3,rad=0.1')

I checked the result but the correspondence is not the correct one. I think that, if there are 32 '0's in the list, it colors 32 edges with the color I assigned to it, but not the correct ones. (But every time I run it the same 32 edges are colored this way, so it's probably not random.) I wonder what's incorrect. I tried it also as a dictionary (not converting to list), but then colors are more than 3 actually, I don;t know why. Should I try to add these values (0, 1, 1, 2 etc) to the edgelist.txt in order the assignment to be done correctly?


Solution

  • The order of the edges passed to the drawing functions are important.
    You need to make sure that your edge_color list(col) is in the same order as network0.edges, which it isn't.

    This is happening because network0.edges is not in the same order as your init_edgelist.txt file, as you were probably assuming.

    To check this try printing network0.edges and compare.

    Solution

    Instead I would suggest adding edge weights with the pretended color to the edge while creating network0, like so:

    G = {0: 1.0, 1: 1.0, 2: 0.0, 3: 1.0, 4: 1.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 1.0}
    list1 = list(G.values())
    col = []
    for n in range(len(list1)):
        if list1[n] == 0:
            col.append('b')
        elif list1[n] == 1:
            col.append('r')
        else:
            col.append('g') 
    
    
    network0 = nx.OrderedDiGraph()
    i = 0
    with open(r'init_edgelist.txt') as f:
        for line in f:
            n1, n2 = line.split()
            network0.add_edge(n1, n2, color = col[i])
            i += 1
    

    Then you just need to extract the colors and draw:

    colors = [network0[u][v]['color'] for u,v in network0.edges()]
    
    nx.draw(network0, pos = pos, with_labels = True, edge_color = colors, edge_cmap = plt.cm.Reds, connectionstyle='arc3,rad=0.1')
    

    full code:

    import networkx as nx
    import numpy as py
    import copy
    import matplotlib.pyplot as plt
    import xlwings as xw
    from xlwings import Book, Range
    
    pos={}
    with open(r'nodes_coordinates.txt') as f:
        for line in f:
            node, x, y = line.split()
            pos[node] = float(x), float(y)
    
    #print(pos)
    
    G = {0: 1.0, 1: 1.0, 2: 0.0, 3: 1.0, 4: 1.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 1.0}
    list1 = list(G.values())
    col=[]
    for n in range(len(list1)):
        if list1[n] == 0:
            col.append('b')
        elif list1[n] == 1:
            col.append('r')
        else:
            col.append('g') 
    
    network0 = nx.OrderedDiGraph()
    
    i = 0
    with open(r'init_edgelist.txt') as f:
        for line in f:
            n1, n2 = line.split()
            network0.add_edge(n1,n2, color=col[i])
            i += 1
    
    #print(network0.edges())
    
    colors = [network0[u][v]['color'] for u,v in network0.edges()]
    
    nx.draw(network0,pos=pos,with_labels=True,edge_color=colors,edge_cmap=plt.cm.Reds, connectionstyle='arc3,rad=0.1')