简体   繁体   中英

Assigning networkx edge attributes/weights to a dict

I run this program:

import networkx as nx
from pylab import *
g=nx.Graph()

g.add_edge('a','b', weight=3)

g.add_edge('a','c', weight=2)

g.add_edge('b','c', weight=7)

w=nx.get_edge_attributes(g, 'weight')

w[('b','a')]=3

w[('c','a')]=2

w[('c','b')]=7

and I do not understand why the w dict contains only 5 instead of 6 items:

{('b', 'a'): 3, ('c', 'a'): 2, ('a', 'b'): 3, ('c', 'b'): 7, ('a', 'c'): 2}

the ('b','c') entry is gone...

What am I doing wrong here?

Your graph is not directed. This is the underlying cause of the problem.

When you run the first part of your code:

import networkx as nx
from pylab import *
g=nx.Graph()

g.add_edge('a','b', weight=3)

g.add_edge('a','c', weight=2)

g.add_edge('b','c', weight=7)

w=nx.get_edge_attributes(g, 'weight')

You make w into a dict, each of whose keys is one of the edges. But the order of nodes within an edge doesn't matter. So let's look at w :

w
> {('a', 'b'): 3, ('a', 'c'): 2, ('c', 'b'): 7}

Notice --- you defined the edge weight for ('b', 'c') . But in w it is stored with the key ('c','b') .

So later, when you define w[('c','b')] you overwrite this. This didn't happen for the other edges because networkx by random chance happened to return them in the order you expected.

I think you're trying to define w so that you've got the weight the same regardless of the order of the edges you check.

It's probably better to use the builtin networkx command to get the weight and not use w at all:

g.get_edge_data('a','b')['weight']

But if you really want your w , one way to do that would be to do a loop through the keys of w as

for edge in w:
    w[([edge[1],edge[0])] = w[edge]

or you can define a function

def f(edge,w):
    if edge in w:
        return w[edge]
    else:
        return w[(edge[1],edge[0])

A bit more explanation of what's going on:

You cannot assume that networkx will give you back the edges of an undirected graph with the same ordering as it was given them. It's an undirected graph, so anything that assumes some implicit direction to the edges is going to run into trouble.

Fundamentally this is because networkx stores the nodes in a dictionary structure. Because of this you cannot assume that it returns the nodes in any order. So in particular in your case when networkx looks to find its edges, it goes through the nodes in some order. In this case it gets to 'c' before it gets to 'b' . So it gets the edge with c first. When it reaches b , it knows it's already got that edge, so it leaves it out.

I've found out (after some trying and looking into the code of get_edge_attribute). In this method itself the edges are retrieved here:

if G.is_multigraph():
        edges = G.edges(keys=True, data=True)
    else:
        edges = G.edges(data=True)
    return dict( (x[:-1], x[-1][name]) for x in edges if name in x[-1] )

In your case the graph is not a multigraph. So it builds the dictionary based on the list G.edges() returns. So I made a little test with the following code:

g.add_edge('a','b', weight=3)

print "edges after adding 'ab':  " + str(g.edges(data=True))

g.add_edge('a','c', weight=2)

print "edges after adding 'ac':  " + str(g.edges(data=True))

g.add_edge('b','c', weight=7)

print "edges after adding 'bc':  " + str(g.edges(data=True))

Output:

edges after adding 'ab':  [('a', 'b', {'weight': 3})]
edges after adding 'ac':  [('a', 'c', {'weight': 2}), ('a', 'b', {'weight': 3})]
edges after adding 'bc':  [('a', 'c', {'weight': 2}), ('a', 'b', {'weight': 3}), ('c', 'b', {'weight': 7})]

Look at the last line in the output: We added the edge 'bc' NOT 'cb', but in the edges list, there is no 'bc' edge, instead there is a 'cb' edge. And that's why you don't see the edge 'bc' because it is not there.

I don't know the exact reason, why it does that.

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