Question

I've pulled up some code I used to play with in 1.6.1 of networkx. On 1.8.1 it doesn't work when writing to gml or graphml.

The problem boils down to being unable to write edge attributes inside the data dict like so:

BasicGraph = nx.read_graphml("KeggCompleteEng.graphml")

for e,v in BasicGraph.edges_iter():
    BasicGraph[e][v]['test'] = 'test'

nx.write_graphml(BasicGraph, "edgeTester.graphml")

Causes the error:

AttributeError: 'str' object has no attribute 'items'

When I use: for e,v,data in BasicGraph.edges_iter(data=True): the data prints out like so:

{'root_index': -3233, 'label': u'unspecified'}
test

AKA the new attribute is outside the dictionary.

The documentation says I should be able to do it like above. However, I imagine I've made a silly mistake and would appreciate being put back on the right path!

EDIT:

So I ran the program with a graph generated inside the program: BasicGraph = nx.complete_graph(100) and it ran fine.

I then ran it with an example graphml file from the primer: BasicGraph = nx.read_graphml("graphmltest.graphml") and that too worked. (I even imported into and out of Cytoscape to check that wasn't the issue)

So obviously it's the file I'm using. Here's a link to it, can anyone see what's wrong with it?

Was it helpful?

Solution

The issue is that your graph is has parallel edges so NetworkX is loading it as a MultiGraph object:

In [1]: import networkx as nx

In [2]: G = nx.read_graphml('KeggCompleteEng.graphml')

In [3]: type(G)
Out[3]: networkx.classes.multigraph.MultiGraph

In [4]: G.number_of_edges()
Out[4]: 7123

In [5]: H = nx.Graph(G) # convert to graph, remove parallel edges

In [6]: H.number_of_edges()
Out[6]: 6160

Because of that the internal structure of the graph object storage for an edge is G[node][node][key][attribute]=value (note the extra key dictionary level for multigraphs).

You are explicitly modifying the structure by

for e,v in BasicGraph.edges_iter():
    BasicGraph[e][v]['test'] = 'test'

which breaks it.

It is allowed to modify the data structure that way but it is safer to use the NetworkX API

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

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

In [9]: G.add_edge(1,2,key='two')

In [10]: G.edges(keys=True)
Out[10]: [(1, 2, 'two'), (1, 2, 'one')]

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

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

In [13]: G.edges(keys=True,data=True)
Out[13]: [(1, 2, 'two', {'color': 'blue'}), (1, 2, 'one', {'color': 'red'})]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top