comparison env/lib/python3.9/site-packages/networkx/readwrite/multiline_adjlist.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """
2 *************************
3 Multi-line Adjacency List
4 *************************
5 Read and write NetworkX graphs as multi-line adjacency lists.
6
7 The multi-line adjacency list format is useful for graphs with
8 nodes that can be meaningfully represented as strings. With this format
9 simple edge data can be stored but node or graph data is not.
10
11 Format
12 ------
13 The first label in a line is the source node label followed by the node degree
14 d. The next d lines are target node labels and optional edge data.
15 That pattern repeats for all nodes in the graph.
16
17 The graph with edges a-b, a-c, d-e can be represented as the following
18 adjacency list (anything following the # in a line is a comment)::
19
20 # example.multiline-adjlist
21 a 2
22 b
23 c
24 d 1
25 e
26 """
27
28 __all__ = [
29 "generate_multiline_adjlist",
30 "write_multiline_adjlist",
31 "parse_multiline_adjlist",
32 "read_multiline_adjlist",
33 ]
34
35 from networkx.utils import open_file
36 import networkx as nx
37
38
39 def generate_multiline_adjlist(G, delimiter=" "):
40 """Generate a single line of the graph G in multiline adjacency list format.
41
42 Parameters
43 ----------
44 G : NetworkX graph
45
46 delimiter : string, optional
47 Separator for node labels
48
49 Returns
50 -------
51 lines : string
52 Lines of data in multiline adjlist format.
53
54 Examples
55 --------
56 >>> G = nx.lollipop_graph(4, 3)
57 >>> for line in nx.generate_multiline_adjlist(G):
58 ... print(line)
59 0 3
60 1 {}
61 2 {}
62 3 {}
63 1 2
64 2 {}
65 3 {}
66 2 1
67 3 {}
68 3 1
69 4 {}
70 4 1
71 5 {}
72 5 1
73 6 {}
74 6 0
75
76 See Also
77 --------
78 write_multiline_adjlist, read_multiline_adjlist
79 """
80 if G.is_directed():
81 if G.is_multigraph():
82 for s, nbrs in G.adjacency():
83 nbr_edges = [
84 (u, data)
85 for u, datadict in nbrs.items()
86 for key, data in datadict.items()
87 ]
88 deg = len(nbr_edges)
89 yield str(s) + delimiter + str(deg)
90 for u, d in nbr_edges:
91 if d is None:
92 yield str(u)
93 else:
94 yield str(u) + delimiter + str(d)
95 else: # directed single edges
96 for s, nbrs in G.adjacency():
97 deg = len(nbrs)
98 yield str(s) + delimiter + str(deg)
99 for u, d in nbrs.items():
100 if d is None:
101 yield str(u)
102 else:
103 yield str(u) + delimiter + str(d)
104 else: # undirected
105 if G.is_multigraph():
106 seen = set() # helper dict used to avoid duplicate edges
107 for s, nbrs in G.adjacency():
108 nbr_edges = [
109 (u, data)
110 for u, datadict in nbrs.items()
111 if u not in seen
112 for key, data in datadict.items()
113 ]
114 deg = len(nbr_edges)
115 yield str(s) + delimiter + str(deg)
116 for u, d in nbr_edges:
117 if d is None:
118 yield str(u)
119 else:
120 yield str(u) + delimiter + str(d)
121 seen.add(s)
122 else: # undirected single edges
123 seen = set() # helper dict used to avoid duplicate edges
124 for s, nbrs in G.adjacency():
125 nbr_edges = [(u, d) for u, d in nbrs.items() if u not in seen]
126 deg = len(nbr_edges)
127 yield str(s) + delimiter + str(deg)
128 for u, d in nbr_edges:
129 if d is None:
130 yield str(u)
131 else:
132 yield str(u) + delimiter + str(d)
133 seen.add(s)
134
135
136 @open_file(1, mode="wb")
137 def write_multiline_adjlist(G, path, delimiter=" ", comments="#", encoding="utf-8"):
138 """ Write the graph G in multiline adjacency list format to path
139
140 Parameters
141 ----------
142 G : NetworkX graph
143
144 comments : string, optional
145 Marker for comment lines
146
147 delimiter : string, optional
148 Separator for node labels
149
150 encoding : string, optional
151 Text encoding.
152
153 Examples
154 --------
155 >>> G = nx.path_graph(4)
156 >>> nx.write_multiline_adjlist(G, "test.adjlist")
157
158 The path can be a file handle or a string with the name of the file. If a
159 file handle is provided, it has to be opened in 'wb' mode.
160
161 >>> fh = open("test.adjlist", "wb")
162 >>> nx.write_multiline_adjlist(G, fh)
163
164 Filenames ending in .gz or .bz2 will be compressed.
165
166 >>> nx.write_multiline_adjlist(G, "test.adjlist.gz")
167
168 See Also
169 --------
170 read_multiline_adjlist
171 """
172 import sys
173 import time
174
175 pargs = comments + " ".join(sys.argv)
176 header = (
177 f"{pargs}\n"
178 + comments
179 + f" GMT {time.asctime(time.gmtime())}\n"
180 + comments
181 + f" {G.name}\n"
182 )
183 path.write(header.encode(encoding))
184
185 for multiline in generate_multiline_adjlist(G, delimiter):
186 multiline += "\n"
187 path.write(multiline.encode(encoding))
188
189
190 def parse_multiline_adjlist(
191 lines, comments="#", delimiter=None, create_using=None, nodetype=None, edgetype=None
192 ):
193 """Parse lines of a multiline adjacency list representation of a graph.
194
195 Parameters
196 ----------
197 lines : list or iterator of strings
198 Input data in multiline adjlist format
199
200 create_using : NetworkX graph constructor, optional (default=nx.Graph)
201 Graph type to create. If graph instance, then cleared before populated.
202
203 nodetype : Python type, optional
204 Convert nodes to this type.
205
206 comments : string, optional
207 Marker for comment lines
208
209 delimiter : string, optional
210 Separator for node labels. The default is whitespace.
211
212 Returns
213 -------
214 G: NetworkX graph
215 The graph corresponding to the lines in multiline adjacency list format.
216
217 Examples
218 --------
219 >>> lines = [
220 ... "1 2",
221 ... "2 {'weight':3, 'name': 'Frodo'}",
222 ... "3 {}",
223 ... "2 1",
224 ... "5 {'weight':6, 'name': 'Saruman'}",
225 ... ]
226 >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype=int)
227 >>> list(G)
228 [1, 2, 3, 5]
229
230 """
231 from ast import literal_eval
232
233 G = nx.empty_graph(0, create_using)
234 for line in lines:
235 p = line.find(comments)
236 if p >= 0:
237 line = line[:p]
238 if not line:
239 continue
240 try:
241 (u, deg) = line.strip().split(delimiter)
242 deg = int(deg)
243 except BaseException as e:
244 raise TypeError(f"Failed to read node and degree on line ({line})") from e
245 if nodetype is not None:
246 try:
247 u = nodetype(u)
248 except BaseException as e:
249 raise TypeError(
250 f"Failed to convert node ({u}) to " f"type {nodetype}"
251 ) from e
252 G.add_node(u)
253 for i in range(deg):
254 while True:
255 try:
256 line = next(lines)
257 except StopIteration as e:
258 msg = f"Failed to find neighbor for node ({u})"
259 raise TypeError(msg) from e
260 p = line.find(comments)
261 if p >= 0:
262 line = line[:p]
263 if line:
264 break
265 vlist = line.strip().split(delimiter)
266 numb = len(vlist)
267 if numb < 1:
268 continue # isolated node
269 v = vlist.pop(0)
270 data = "".join(vlist)
271 if nodetype is not None:
272 try:
273 v = nodetype(v)
274 except BaseException as e:
275 raise TypeError(
276 f"Failed to convert node ({v}) " f"to type {nodetype}"
277 ) from e
278 if edgetype is not None:
279 try:
280 edgedata = {"weight": edgetype(data)}
281 except BaseException as e:
282 raise TypeError(
283 f"Failed to convert edge data ({data}) " f"to type {edgetype}"
284 ) from e
285 else:
286 try: # try to evaluate
287 edgedata = literal_eval(data)
288 except:
289 edgedata = {}
290 G.add_edge(u, v, **edgedata)
291
292 return G
293
294
295 @open_file(0, mode="rb")
296 def read_multiline_adjlist(
297 path,
298 comments="#",
299 delimiter=None,
300 create_using=None,
301 nodetype=None,
302 edgetype=None,
303 encoding="utf-8",
304 ):
305 """Read graph in multi-line adjacency list format from path.
306
307 Parameters
308 ----------
309 path : string or file
310 Filename or file handle to read.
311 Filenames ending in .gz or .bz2 will be uncompressed.
312
313 create_using : NetworkX graph constructor, optional (default=nx.Graph)
314 Graph type to create. If graph instance, then cleared before populated.
315
316 nodetype : Python type, optional
317 Convert nodes to this type.
318
319 edgetype : Python type, optional
320 Convert edge data to this type.
321
322 comments : string, optional
323 Marker for comment lines
324
325 delimiter : string, optional
326 Separator for node labels. The default is whitespace.
327
328 Returns
329 -------
330 G: NetworkX graph
331
332 Examples
333 --------
334 >>> G = nx.path_graph(4)
335 >>> nx.write_multiline_adjlist(G, "test.adjlist")
336 >>> G = nx.read_multiline_adjlist("test.adjlist")
337
338 The path can be a file or a string with the name of the file. If a
339 file s provided, it has to be opened in 'rb' mode.
340
341 >>> fh = open("test.adjlist", "rb")
342 >>> G = nx.read_multiline_adjlist(fh)
343
344 Filenames ending in .gz or .bz2 will be compressed.
345
346 >>> nx.write_multiline_adjlist(G, "test.adjlist.gz")
347 >>> G = nx.read_multiline_adjlist("test.adjlist.gz")
348
349 The optional nodetype is a function to convert node strings to nodetype.
350
351 For example
352
353 >>> G = nx.read_multiline_adjlist("test.adjlist", nodetype=int)
354
355 will attempt to convert all nodes to integer type.
356
357 The optional edgetype is a function to convert edge data strings to
358 edgetype.
359
360 >>> G = nx.read_multiline_adjlist("test.adjlist")
361
362 The optional create_using parameter is a NetworkX graph container.
363 The default is Graph(), an undirected graph. To read the data as
364 a directed graph use
365
366 >>> G = nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph)
367
368 Notes
369 -----
370 This format does not store graph, node, or edge data.
371
372 See Also
373 --------
374 write_multiline_adjlist
375 """
376 lines = (line.decode(encoding) for line in path)
377 return parse_multiline_adjlist(
378 lines,
379 comments=comments,
380 delimiter=delimiter,
381 create_using=create_using,
382 nodetype=nodetype,
383 edgetype=edgetype,
384 )