37

What I have: a graph G imported in networkx with nodes and edges loaded by gml file.

Problem: How to add a new attribute to a selected edge E.

What I want to do: I want to add a new attribute 'type' for a particular edge E of my graph. Attention: the attribute 'type' doesn't exist for this edge E.

My code is:

  G.edge[id_source][id_target]['type']= value

But if I print all the edges of G, now I have n+1 edges; all the old edges of G, and a new edge p= (id_source, id_target, {'type'= value}). Furthermore, the old edge E (the one that I want modify) doesn't have the new attribute 'type'.

So my code have added a new edge (that I don't want).

I want to update the old one adding a new attribute that doesn't exist.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Stefano C.
  • 1,033
  • 3
  • 13
  • 17

5 Answers5

30

You may have a networkx MultiGraph instead of a graph and in that case the attribute setting for edges is a little tricker. (You can get a multigraph by loading a graph with more than one edge between nodes). You may be corrupting the data structure by assigning the attribute G.edge[id_source][id_target]['type']= value when you need G.edge[id_source][id_target][key]['type']= value.

Here are examples of how it works differently for Graphs and MultiGraphs.

For the Graph case attributes work like this:

In [1]: import networkx as nx

In [2]: G = nx.Graph()

In [3]: G.add_edge(1,2,color='red')

In [4]: G.edges(data=True)
Out[4]: [(1, 2, {'color': 'red'})]

In [5]: G.add_edge(1,2,color='blue')

In [6]: G.edges(data=True)
Out[6]: [(1, 2, {'color': 'blue'})]

In [7]: G[1][2]
Out[7]: {'color': 'blue'}

In [8]: G[1][2]['color']='green'

In [9]: G.edges(data=True)
Out[9]: [(1, 2, {'color': 'green'})]

With MultiGraphs there is an additional level of keys to keep track of the parallel edges so it works a little differently. If you don't explicitly set a key MultiGraph.add_edge() will add a new edge with an internally chosen key (sequential integers).

In [1]: import networkx as nx

In [2]: G = nx.MultiGraph()

In [3]: G.add_edge(1,2,color='red')

In [4]: G.edges(data=True)
Out[4]: [(1, 2, {'color': 'red'})]

In [5]: G.add_edge(1,2,color='blue')

In [6]: G.edges(data=True)
Out[6]: [(1, 2, {'color': 'red'}), (1, 2, {'color': 'blue'})]

In [7]: G.edges(data=True,keys=True)
Out[7]: [(1, 2, 0, {'color': 'red'}), (1, 2, 1, {'color': 'blue'})]

In [8]: G.add_edge(1,2,key=0,color='blue')

In [9]: G.edges(data=True,keys=True)
Out[9]: [(1, 2, 0, {'color': 'blue'}), (1, 2, 1, {'color': 'blue'})]

In [10]: G[1][2]
Out[10]: {0: {'color': 'blue'}, 1: {'color': 'blue'}}

In [11]: G[1][2][0]['color']='green'

In [12]: G.edges(data=True,keys=True)
Out[12]: [(1, 2, 0, {'color': 'green'}), (1, 2, 1, {'color': 'blue'})]
Aric
  • 24,511
  • 5
  • 78
  • 77
  • 1
    Thanks for answer. But in multigraph example when you add the edge you add also the attribute color. I need add a new attribute that doesn't exist when i have created the edge. For example after line 3 , how i Can add a second attribute to edge 1-2 ???? – Stefano C. Nov 01 '14 at 23:08
  • 1
    Sure just write G.add_edge(1,2,other='foo'). You might not want to use `type` since it is a reserved word in Python (though it will probably be OK to use like this). – Aric Nov 01 '14 at 23:14
  • But i tried G.add_edge(1,2, other='foo'). But it Adds a new one edge different by th first edge 1,2,color: red). i want This : (1,2, color: red, other: foo). How Can i get This result? – Stefano C. Nov 01 '14 at 23:32
  • So do you have a MultiGraph or a Graph object? The approach is different as I explained in my answer. Try type(G). – Aric Nov 01 '14 at 23:34
  • I have a multigraph. In fac ti have multiple edge between two nodes. Consider a single edge between (1,2) . Initially i add edge (1,2, color='red') . After i do some stuff and i want add a new attribute to edge (1,2). So for example i want add other='foo' to (1,2) . The result is: (1,2, color='red', other='foo' ). Ok???? – Stefano C. Nov 01 '14 at 23:38
  • You need to specify a key too for MultiGraphs (see my example). If you don't set a key at creation you will get a automatically generated integer key. See G.edges(keys=True). – Aric Nov 01 '14 at 23:49
  • I wrote `key_id = H[id_source][id_target]['key']` and then `H.add_edge(id_source,id_target,key=key_id,type='normal')` But when i compile i get this error: `key_id = H[id_source][id_target]['key'] KeyError: 'key'` I don't set the key for each edge, so it automatically set a integer (i printed it). How i can get a key attribute of a specif edge? – Stefano C. Nov 02 '14 at 08:28
3

I don't quite understand why you want add an attribute to only one edge, instead you can add an attribute to all edges, then you give the the wanted value to your specific edge.

Networkx has a method called set_edge_attributes can add an edge attributes to all edges, for example

    G = nx.path_graph(3)
    bb = nx.edge_betweenness_centrality(G, normalized=False)
    nx.set_edge_attributes(G, 'betweenness', bb)
    G[1][2]['betweenness']

Output: 2.0

  • 2
    You should answer the actual question asked, not a different question that you can easily answer by copying from the documentation. This method can actually be adapted to update just one edge (by specifying the `bb` dictionary for that specific edge), but that's not what you offered as an answer. – Aaron Bramson Oct 20 '22 at 08:31
1

The answer below by Xin-Feng Li works, just note that the arguments for values and name switched between Networkx v1.x (when the answer was originally written) and Networkx v2.x. For v2.x, the code is:

G = nx.path_graph(3)
bb = nx.edge_betweenness_centrality(G, normalized=False)
nx.set_edge_attributes(G, bb, 'betweenness')
G[1][2]['betweenness']
scorch421
  • 11
  • 2
1

Solution added from OP's question:

Thanks to Aric and some tricks I solved my problem:

def add_attribute_to_edge(H,id_node_source,id_node_target,new_attr,value_attr):

      keydict =H[id_node_source][id_node_target]
      key=len(keydict)
      for k in keydict:
          if 'type' not in H.edge[id_source][id_target][k]:
             H.add_edge(id_node_source,id_node_target,key=k, new_attr= value_attr)
TylerH
  • 20,799
  • 66
  • 75
  • 101
0

Actually, there is a better and short way to add new attributes to an existing edge in a graph:

>>> for itr in G.edges_iter(None, True, True):
        itr

(0, 1, {})
(0, 2, {'edge': (0, 2)})
(0, 3, {})
(0, 4, {})
(1, 2, {})
(1, 3, {})
(2, 3, {})
(2, 4, {})
(3, 4, {})
>>> G[0][1].update(edge=(0,1))      #This will add 'edge'=(0,1) dict item to edge(0,1)
>>> for itr in G.edges_iter(None, True, True):
        itr


(0, 1, {'edge': (0, 1)})
(0, 2, {'edge': (0, 2)})
(0, 3, {})
(0, 4, {})
(1, 2, {})
(1, 3, {})
(2, 3, {})
(2, 4, {})
(3, 4, {})
Vibhor Mishra
  • 31
  • 1
  • 6