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?
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'})]