Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/readwrite/multiline_adjlist.py: 10%
111 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
1"""
2*************************
3Multi-line Adjacency List
4*************************
5Read and write NetworkX graphs as multi-line adjacency lists.
7The multi-line adjacency list format is useful for graphs with
8nodes that can be meaningfully represented as strings. With this format
9simple edge data can be stored but node or graph data is not.
11Format
12------
13The first label in a line is the source node label followed by the node degree
14d. The next d lines are target node labels and optional edge data.
15That pattern repeats for all nodes in the graph.
17The graph with edges a-b, a-c, d-e can be represented as the following
18adjacency list (anything following the # in a line is a comment)::
20 # example.multiline-adjlist
21 a 2
22 b
23 c
24 d 1
25 e
26"""
28__all__ = [
29 "generate_multiline_adjlist",
30 "write_multiline_adjlist",
31 "parse_multiline_adjlist",
32 "read_multiline_adjlist",
33]
35import networkx as nx
36from networkx.utils import open_file
39def generate_multiline_adjlist(G, delimiter=" "):
40 """Generate a single line of the graph G in multiline adjacency list format.
42 Parameters
43 ----------
44 G : NetworkX graph
46 delimiter : string, optional
47 Separator for node labels
49 Returns
50 -------
51 lines : string
52 Lines of data in multiline adjlist format.
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
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)
136@open_file(1, mode="wb")
137def write_multiline_adjlist(G, path, delimiter=" ", comments="#", encoding="utf-8"):
138 """Write the graph G in multiline adjacency list format to path
140 Parameters
141 ----------
142 G : NetworkX graph
144 path : string or file
145 Filename or file handle to write to.
146 Filenames ending in .gz or .bz2 will be compressed.
148 comments : string, optional
149 Marker for comment lines
151 delimiter : string, optional
152 Separator for node labels
154 encoding : string, optional
155 Text encoding.
157 Examples
158 --------
159 >>> G = nx.path_graph(4)
160 >>> nx.write_multiline_adjlist(G, "test.adjlist")
162 The path can be a file handle or a string with the name of the file. If a
163 file handle is provided, it has to be opened in 'wb' mode.
165 >>> fh = open("test.adjlist", "wb")
166 >>> nx.write_multiline_adjlist(G, fh)
168 Filenames ending in .gz or .bz2 will be compressed.
170 >>> nx.write_multiline_adjlist(G, "test.adjlist.gz")
172 See Also
173 --------
174 read_multiline_adjlist
175 """
176 import sys
177 import time
179 pargs = comments + " ".join(sys.argv)
180 header = (
181 f"{pargs}\n"
182 + comments
183 + f" GMT {time.asctime(time.gmtime())}\n"
184 + comments
185 + f" {G.name}\n"
186 )
187 path.write(header.encode(encoding))
189 for multiline in generate_multiline_adjlist(G, delimiter):
190 multiline += "\n"
191 path.write(multiline.encode(encoding))
194@nx._dispatch(graphs=None)
195def parse_multiline_adjlist(
196 lines, comments="#", delimiter=None, create_using=None, nodetype=None, edgetype=None
197):
198 """Parse lines of a multiline adjacency list representation of a graph.
200 Parameters
201 ----------
202 lines : list or iterator of strings
203 Input data in multiline adjlist format
205 create_using : NetworkX graph constructor, optional (default=nx.Graph)
206 Graph type to create. If graph instance, then cleared before populated.
208 nodetype : Python type, optional
209 Convert nodes to this type.
211 edgetype : Python type, optional
212 Convert edges to this type.
214 comments : string, optional
215 Marker for comment lines
217 delimiter : string, optional
218 Separator for node labels. The default is whitespace.
220 Returns
221 -------
222 G: NetworkX graph
223 The graph corresponding to the lines in multiline adjacency list format.
225 Examples
226 --------
227 >>> lines = [
228 ... "1 2",
229 ... "2 {'weight':3, 'name': 'Frodo'}",
230 ... "3 {}",
231 ... "2 1",
232 ... "5 {'weight':6, 'name': 'Saruman'}",
233 ... ]
234 >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype=int)
235 >>> list(G)
236 [1, 2, 3, 5]
238 """
239 from ast import literal_eval
241 G = nx.empty_graph(0, create_using)
242 for line in lines:
243 p = line.find(comments)
244 if p >= 0:
245 line = line[:p]
246 if not line:
247 continue
248 try:
249 (u, deg) = line.strip().split(delimiter)
250 deg = int(deg)
251 except BaseException as err:
252 raise TypeError(f"Failed to read node and degree on line ({line})") from err
253 if nodetype is not None:
254 try:
255 u = nodetype(u)
256 except BaseException as err:
257 raise TypeError(
258 f"Failed to convert node ({u}) to " f"type {nodetype}"
259 ) from err
260 G.add_node(u)
261 for i in range(deg):
262 while True:
263 try:
264 line = next(lines)
265 except StopIteration as err:
266 msg = f"Failed to find neighbor for node ({u})"
267 raise TypeError(msg) from err
268 p = line.find(comments)
269 if p >= 0:
270 line = line[:p]
271 if line:
272 break
273 vlist = line.strip().split(delimiter)
274 numb = len(vlist)
275 if numb < 1:
276 continue # isolated node
277 v = vlist.pop(0)
278 data = "".join(vlist)
279 if nodetype is not None:
280 try:
281 v = nodetype(v)
282 except BaseException as err:
283 raise TypeError(
284 f"Failed to convert node ({v}) " f"to type {nodetype}"
285 ) from err
286 if edgetype is not None:
287 try:
288 edgedata = {"weight": edgetype(data)}
289 except BaseException as err:
290 raise TypeError(
291 f"Failed to convert edge data ({data}) " f"to type {edgetype}"
292 ) from err
293 else:
294 try: # try to evaluate
295 edgedata = literal_eval(data)
296 except:
297 edgedata = {}
298 G.add_edge(u, v, **edgedata)
300 return G
303@open_file(0, mode="rb")
304@nx._dispatch(graphs=None)
305def read_multiline_adjlist(
306 path,
307 comments="#",
308 delimiter=None,
309 create_using=None,
310 nodetype=None,
311 edgetype=None,
312 encoding="utf-8",
313):
314 """Read graph in multi-line adjacency list format from path.
316 Parameters
317 ----------
318 path : string or file
319 Filename or file handle to read.
320 Filenames ending in .gz or .bz2 will be uncompressed.
322 create_using : NetworkX graph constructor, optional (default=nx.Graph)
323 Graph type to create. If graph instance, then cleared before populated.
325 nodetype : Python type, optional
326 Convert nodes to this type.
328 edgetype : Python type, optional
329 Convert edge data to this type.
331 comments : string, optional
332 Marker for comment lines
334 delimiter : string, optional
335 Separator for node labels. The default is whitespace.
337 Returns
338 -------
339 G: NetworkX graph
341 Examples
342 --------
343 >>> G = nx.path_graph(4)
344 >>> nx.write_multiline_adjlist(G, "test.adjlist")
345 >>> G = nx.read_multiline_adjlist("test.adjlist")
347 The path can be a file or a string with the name of the file. If a
348 file s provided, it has to be opened in 'rb' mode.
350 >>> fh = open("test.adjlist", "rb")
351 >>> G = nx.read_multiline_adjlist(fh)
353 Filenames ending in .gz or .bz2 will be compressed.
355 >>> nx.write_multiline_adjlist(G, "test.adjlist.gz")
356 >>> G = nx.read_multiline_adjlist("test.adjlist.gz")
358 The optional nodetype is a function to convert node strings to nodetype.
360 For example
362 >>> G = nx.read_multiline_adjlist("test.adjlist", nodetype=int)
364 will attempt to convert all nodes to integer type.
366 The optional edgetype is a function to convert edge data strings to
367 edgetype.
369 >>> G = nx.read_multiline_adjlist("test.adjlist")
371 The optional create_using parameter is a NetworkX graph container.
372 The default is Graph(), an undirected graph. To read the data as
373 a directed graph use
375 >>> G = nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph)
377 Notes
378 -----
379 This format does not store graph, node, or edge data.
381 See Also
382 --------
383 write_multiline_adjlist
384 """
385 lines = (line.decode(encoding) for line in path)
386 return parse_multiline_adjlist(
387 lines,
388 comments=comments,
389 delimiter=delimiter,
390 create_using=create_using,
391 nodetype=nodetype,
392 edgetype=edgetype,
393 )