1 """
2 Read graphs in GML format.
3 See http://www.infosun.fim.uni-passau.de/Graphlet/GML/gml-tr.html
4 for format specification.
5
6 Example graphs in GML format:
7 http://www-personal.umich.edu/~mejn/netdata/
8
9 """
10 __author__ = """Aric Hagberg (hagberg@lanl.gov)"""
11
12
13
14
15
16
17
18 import sys
19 import time
20 import networkx
21 from networkx.exception import NetworkXException, NetworkXError
22 from networkx.utils import _get_fh, is_string_like
23
24
26 """Read graph in GML format from path.
27 Returns an XGraph or XDiGraph.
28
29 This doesn't implement the complete GML specification for
30 nested attributes for graphs, edges, and nodes.
31
32 """
33 fh=_get_fh(path,mode='r')
34 G=parse_gml(fh)
35 return G
36
37
39 """Parse GML format from string or iterable.
40 Returns an XGraph or XDiGraph.
41
42 This doesn't implement the complete GML specification for
43 nested attributes for graphs, edges, and nodes.
44 """
45 try:
46 from pyparsing import ParseException
47 except ImportError:
48 raise ImportError, \
49 "Import Error: not able to import pyparsing: http://pyparsing.wikispaces.com/"
50
51 try:
52 data = "".join(lines)
53 gml = pyparse_gml()
54 tokens =gml.parseString(data)
55 except ParseException, err:
56 print err.line
57 print " "*(err.column-1) + "^"
58 print err
59
60 graph_attr=tokens.asDict()
61
62 directed=graph_attr.get('directed',0)
63 if directed==1:
64 G=networkx.XDiGraph()
65 else:
66 G=networkx.XGraph()
67 G.node_attr={}
68 G.graph_attr=graph_attr
69
70
71 label={}
72 for item in tokens:
73 if item[0]=='node':
74 d=item.asDict()
75 id=d['id']
76 if 'label'in d:
77 label[id]=d['label']
78 del d['label']
79 else:
80 label[id]=id
81 del d['id']
82 G.add_node(label[id])
83 if len(d)==0:
84 d=None
85 G.node_attr[label[id]]=d
86
87
88 for item in tokens:
89 if item[0]=='edge':
90 d=item.asDict()
91 source=d['source']
92 target=d['target']
93 del d['source']
94 del d['target']
95 if len(d)==0:
96 d=None
97 G.add_edge(label[source],label[target],d)
98 return G
99
100 graph = None
102 """pyparser tokenizer for GML graph format
103
104 This doesn't implement the complete GML specification for
105 nested attributes for graphs, edges, and nodes.
106
107 """
108 global graph
109
110 try:
111 from pyparsing import \
112 Literal, CaselessLiteral,Word,\
113 ZeroOrMore, Group, Dict, Optional, Combine,\
114 ParseException, restOfLine, White, alphanums, nums,\
115 OneOrMore,quotedString,removeQuotes,dblQuotedString
116 except ImportError:
117 raise ImportError, \
118 "Import Error: not able to import pyparsing: http://pyparsing.wikispaces.com/"
119
120 if not graph:
121 graphkey = Literal("graph").suppress()
122 lbrack = Literal("[").suppress()
123 rbrack = Literal("]").suppress()
124 pound = ("#")
125 comment = pound + Optional( restOfLine )
126 white = White(" \t\n")
127 point = Literal(".")
128 e = CaselessLiteral("E")
129 integer = Word(nums).setParseAction(lambda s,l,t:[ int(t[0])])
130 real = Combine( Word("+-"+nums, nums )+
131 Optional(point+Optional(Word(nums)))+
132 Optional(e+Word("+-"+nums, nums))).setParseAction(
133 lambda s,l,t:[ float(t[0]) ])
134 key=Word(alphanums)
135 value=integer^real^Word(alphanums)^quotedString.setParseAction(removeQuotes)
136 keyvalue = Dict(Group(key+OneOrMore(white).suppress()\
137 +value+OneOrMore(white).suppress()))
138 node = Group(Literal("node") + lbrack + OneOrMore(keyvalue) + rbrack)
139 edge = Group(Literal("edge") + lbrack + OneOrMore(keyvalue) + rbrack)
140 graph = graphkey + lbrack + OneOrMore(edge|node|keyvalue) + rbrack
141 graph.ignore(comment)
142
143 return graph
144
146 """
147 Write the graph G in GML format to the file or file handle path.
148
149 >>> write_gml(G,"file.gml")
150
151 path can be a filehandle or a string with the name of the file.
152
153 >>> fh=open("file.gml")
154 >>> write_multiline_adjlist(G,fh)
155
156 Filenames ending in .gz or .bz2 will be compressed.
157
158 >>> write_multiline_adjlist(G,"file.gml.gz")
159
160
161 The output file will use the default text encoding on your system.
162 It is possible to write files in other encodings by opening
163 the file with the codecs module. See doc/examples/unicode.py
164 for hints.
165
166 >>> import codecs
167 >>> fh=codecs.open("file.edgelist",encoding='iso8859-1')# use iso8859-1
168 >>> write_edgelist(G,fh)
169
170 GML specifications indicate that the file should only use
171 7bit ASCII text encoding.iso8859-1 (latin-1).
172
173 Only a single level of attributes for graphs, nodes, and edges,
174 is supported.
175
176 """
177 fh=_get_fh(path,mode='w')
178
179
180
181
182
183
184
185 if hasattr(G,'graph_attr'):
186 graph_attr=G.graph_attr
187 else:
188 graph_attr={}
189 if hasattr(G,'node_attr'):
190 node_attr=G.node_attr
191 else:
192 node_attr={}
193
194 indent=2*' '
195 count=iter(range(G.number_of_nodes()))
196 node_id={}
197
198 fh.write("graph [\n")
199
200 for k,v in graph_attr.items():
201 if is_string_like(v):
202 v='"'+v+'"'
203 fh.write(indent+"%s %s\n"%(k,v))
204
205 for n in G:
206 fh.write(indent+"node [\n")
207
208 if n in node_attr:
209 nid=node_attr[n].get('id',count.next())
210 else:
211 nid=count.next()
212 node_id[n]=nid
213 fh.write(2*indent+"id %s\n"%nid)
214 fh.write(2*indent+"label \"%s\"\n"%n)
215 if n in node_attr:
216 for k,v in node_attr[n].items():
217 if is_string_like(v): v='"'+v+'"'
218 if k=='id': continue
219 fh.write(2*indent+"%s %s\n"%(k,v))
220 fh.write(indent+"]\n")
221
222 for e in G.edges_iter():
223 if len(e)==3:
224 u,v,d=e
225
226 edgedata={}
227 if d is None:
228 pass
229 elif hasattr(d,'iteritems'):
230 edgedata=dict(d.iteritems())
231 elif hasattr(d,'__iter__'):
232 edgedata['data']=d.__repr__()
233 else:
234 edgedata['data']=d
235 else:
236 u,v=e
237 edgedata={}
238 fh.write(indent+"edge [\n")
239 fh.write(2*indent+"source %s\n"%node_id[u])
240 fh.write(2*indent+"target %s\n"%node_id[v])
241 for k,v in edgedata.items():
242 if k=='source': continue
243 if k=='target': continue
244 if is_string_like(v): v='"'+v+'"'
245 fh.write(2*indent+"%s %s\n"%(k,v))
246 fh.write(indent+"]\n")
247 fh.write("]\n")
248
249
251 import doctest
252 suite = doctest.DocFileSuite('tests/readwrite/gml.txt',
253 package='networkx')
254 return suite
255
256 if __name__ == "__main__":
257 import os
258 import sys
259 import unittest
260 if sys.version_info[:2] < (2, 4):
261 print "Python version 2.4 or later required for tests (%d.%d detected)." % sys.version_info[:2]
262 sys.exit(-1)
263
264 nxbase=sys.path[0]+os.sep+os.pardir
265 sys.path.insert(0,nxbase)
266 unittest.TextTestRunner().run(_test_suite())
267