Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/readwrite/edgelist.py: 18%

78 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 07:00 +0000

1""" 

2********** 

3Edge Lists 

4********** 

5Read and write NetworkX graphs as edge lists. 

6 

7The multi-line adjacency list format is useful for graphs with nodes 

8that can be meaningfully represented as strings. With the edgelist 

9format simple edge data can be stored but node or graph data is not. 

10There is no way of representing isolated nodes unless the node has a 

11self-loop edge. 

12 

13Format 

14------ 

15You can read or write three formats of edge lists with these functions. 

16 

17Node pairs with no data:: 

18 

19 1 2 

20 

21Python dictionary as data:: 

22 

23 1 2 {'weight':7, 'color':'green'} 

24 

25Arbitrary data:: 

26 

27 1 2 7 green 

28""" 

29 

30__all__ = [ 

31 "generate_edgelist", 

32 "write_edgelist", 

33 "parse_edgelist", 

34 "read_edgelist", 

35 "read_weighted_edgelist", 

36 "write_weighted_edgelist", 

37] 

38 

39import networkx as nx 

40from networkx.utils import open_file 

41 

42 

43def generate_edgelist(G, delimiter=" ", data=True): 

44 """Generate a single line of the graph G in edge list format. 

45 

46 Parameters 

47 ---------- 

48 G : NetworkX graph 

49 

50 delimiter : string, optional 

51 Separator for node labels 

52 

53 data : bool or list of keys 

54 If False generate no edge data. If True use a dictionary 

55 representation of edge data. If a list of keys use a list of data 

56 values corresponding to the keys. 

57 

58 Returns 

59 ------- 

60 lines : string 

61 Lines of data in adjlist format. 

62 

63 Examples 

64 -------- 

65 >>> G = nx.lollipop_graph(4, 3) 

66 >>> G[1][2]["weight"] = 3 

67 >>> G[3][4]["capacity"] = 12 

68 >>> for line in nx.generate_edgelist(G, data=False): 

69 ... print(line) 

70 0 1 

71 0 2 

72 0 3 

73 1 2 

74 1 3 

75 2 3 

76 3 4 

77 4 5 

78 5 6 

79 

80 >>> for line in nx.generate_edgelist(G): 

81 ... print(line) 

82 0 1 {} 

83 0 2 {} 

84 0 3 {} 

85 1 2 {'weight': 3} 

86 1 3 {} 

87 2 3 {} 

88 3 4 {'capacity': 12} 

89 4 5 {} 

90 5 6 {} 

91 

92 >>> for line in nx.generate_edgelist(G, data=["weight"]): 

93 ... print(line) 

94 0 1 

95 0 2 

96 0 3 

97 1 2 3 

98 1 3 

99 2 3 

100 3 4 

101 4 5 

102 5 6 

103 

104 See Also 

105 -------- 

106 write_adjlist, read_adjlist 

107 """ 

108 if data is True: 

109 for u, v, d in G.edges(data=True): 

110 e = u, v, dict(d) 

111 yield delimiter.join(map(str, e)) 

112 elif data is False: 

113 for u, v in G.edges(data=False): 

114 e = u, v 

115 yield delimiter.join(map(str, e)) 

116 else: 

117 for u, v, d in G.edges(data=True): 

118 e = [u, v] 

119 try: 

120 e.extend(d[k] for k in data) 

121 except KeyError: 

122 pass # missing data for this edge, should warn? 

123 yield delimiter.join(map(str, e)) 

124 

125 

126@open_file(1, mode="wb") 

127def write_edgelist(G, path, comments="#", delimiter=" ", data=True, encoding="utf-8"): 

128 """Write graph as a list of edges. 

129 

130 Parameters 

131 ---------- 

132 G : graph 

133 A NetworkX graph 

134 path : file or string 

135 File or filename to write. If a file is provided, it must be 

136 opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed. 

137 comments : string, optional 

138 The character used to indicate the start of a comment 

139 delimiter : string, optional 

140 The string used to separate values. The default is whitespace. 

141 data : bool or list, optional 

142 If False write no edge data. 

143 If True write a string representation of the edge data dictionary.. 

144 If a list (or other iterable) is provided, write the keys specified 

145 in the list. 

146 encoding: string, optional 

147 Specify which encoding to use when writing file. 

148 

149 Examples 

150 -------- 

151 >>> G = nx.path_graph(4) 

152 >>> nx.write_edgelist(G, "test.edgelist") 

153 >>> G = nx.path_graph(4) 

154 >>> fh = open("test.edgelist", "wb") 

155 >>> nx.write_edgelist(G, fh) 

156 >>> nx.write_edgelist(G, "test.edgelist.gz") 

157 >>> nx.write_edgelist(G, "test.edgelist.gz", data=False) 

158 

159 >>> G = nx.Graph() 

160 >>> G.add_edge(1, 2, weight=7, color="red") 

161 >>> nx.write_edgelist(G, "test.edgelist", data=False) 

162 >>> nx.write_edgelist(G, "test.edgelist", data=["color"]) 

163 >>> nx.write_edgelist(G, "test.edgelist", data=["color", "weight"]) 

164 

165 See Also 

166 -------- 

167 read_edgelist 

168 write_weighted_edgelist 

169 """ 

170 

171 for line in generate_edgelist(G, delimiter, data): 

172 line += "\n" 

173 path.write(line.encode(encoding)) 

174 

175 

176@nx._dispatch(graphs=None) 

177def parse_edgelist( 

178 lines, comments="#", delimiter=None, create_using=None, nodetype=None, data=True 

179): 

180 """Parse lines of an edge list representation of a graph. 

181 

182 Parameters 

183 ---------- 

184 lines : list or iterator of strings 

185 Input data in edgelist format 

186 comments : string, optional 

187 Marker for comment lines. Default is `'#'`. To specify that no character 

188 should be treated as a comment, use ``comments=None``. 

189 delimiter : string, optional 

190 Separator for node labels. Default is `None`, meaning any whitespace. 

191 create_using : NetworkX graph constructor, optional (default=nx.Graph) 

192 Graph type to create. If graph instance, then cleared before populated. 

193 nodetype : Python type, optional 

194 Convert nodes to this type. Default is `None`, meaning no conversion is 

195 performed. 

196 data : bool or list of (label,type) tuples 

197 If `False` generate no edge data or if `True` use a dictionary 

198 representation of edge data or a list tuples specifying dictionary 

199 key names and types for edge data. 

200 

201 Returns 

202 ------- 

203 G: NetworkX Graph 

204 The graph corresponding to lines 

205 

206 Examples 

207 -------- 

208 Edgelist with no data: 

209 

210 >>> lines = ["1 2", "2 3", "3 4"] 

211 >>> G = nx.parse_edgelist(lines, nodetype=int) 

212 >>> list(G) 

213 [1, 2, 3, 4] 

214 >>> list(G.edges()) 

215 [(1, 2), (2, 3), (3, 4)] 

216 

217 Edgelist with data in Python dictionary representation: 

218 

219 >>> lines = ["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"] 

220 >>> G = nx.parse_edgelist(lines, nodetype=int) 

221 >>> list(G) 

222 [1, 2, 3, 4] 

223 >>> list(G.edges(data=True)) 

224 [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] 

225 

226 Edgelist with data in a list: 

227 

228 >>> lines = ["1 2 3", "2 3 27", "3 4 3.0"] 

229 >>> G = nx.parse_edgelist(lines, nodetype=int, data=(("weight", float),)) 

230 >>> list(G) 

231 [1, 2, 3, 4] 

232 >>> list(G.edges(data=True)) 

233 [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] 

234 

235 See Also 

236 -------- 

237 read_weighted_edgelist 

238 """ 

239 from ast import literal_eval 

240 

241 G = nx.empty_graph(0, create_using) 

242 for line in lines: 

243 if comments is not None: 

244 p = line.find(comments) 

245 if p >= 0: 

246 line = line[:p] 

247 if not line: 

248 continue 

249 # split line, should have 2 or more 

250 s = line.strip().split(delimiter) 

251 if len(s) < 2: 

252 continue 

253 u = s.pop(0) 

254 v = s.pop(0) 

255 d = s 

256 if nodetype is not None: 

257 try: 

258 u = nodetype(u) 

259 v = nodetype(v) 

260 except Exception as err: 

261 raise TypeError( 

262 f"Failed to convert nodes {u},{v} to type {nodetype}." 

263 ) from err 

264 

265 if len(d) == 0 or data is False: 

266 # no data or data type specified 

267 edgedata = {} 

268 elif data is True: 

269 # no edge types specified 

270 try: # try to evaluate as dictionary 

271 if delimiter == ",": 

272 edgedata_str = ",".join(d) 

273 else: 

274 edgedata_str = " ".join(d) 

275 edgedata = dict(literal_eval(edgedata_str.strip())) 

276 except Exception as err: 

277 raise TypeError( 

278 f"Failed to convert edge data ({d}) to dictionary." 

279 ) from err 

280 else: 

281 # convert edge data to dictionary with specified keys and type 

282 if len(d) != len(data): 

283 raise IndexError( 

284 f"Edge data {d} and data_keys {data} are not the same length" 

285 ) 

286 edgedata = {} 

287 for (edge_key, edge_type), edge_value in zip(data, d): 

288 try: 

289 edge_value = edge_type(edge_value) 

290 except Exception as err: 

291 raise TypeError( 

292 f"Failed to convert {edge_key} data {edge_value} " 

293 f"to type {edge_type}." 

294 ) from err 

295 edgedata.update({edge_key: edge_value}) 

296 G.add_edge(u, v, **edgedata) 

297 return G 

298 

299 

300@open_file(0, mode="rb") 

301@nx._dispatch(graphs=None) 

302def read_edgelist( 

303 path, 

304 comments="#", 

305 delimiter=None, 

306 create_using=None, 

307 nodetype=None, 

308 data=True, 

309 edgetype=None, 

310 encoding="utf-8", 

311): 

312 """Read a graph from a list of edges. 

313 

314 Parameters 

315 ---------- 

316 path : file or string 

317 File or filename to read. If a file is provided, it must be 

318 opened in 'rb' mode. 

319 Filenames ending in .gz or .bz2 will be uncompressed. 

320 comments : string, optional 

321 The character used to indicate the start of a comment. To specify that 

322 no character should be treated as a comment, use ``comments=None``. 

323 delimiter : string, optional 

324 The string used to separate values. The default is whitespace. 

325 create_using : NetworkX graph constructor, optional (default=nx.Graph) 

326 Graph type to create. If graph instance, then cleared before populated. 

327 nodetype : int, float, str, Python type, optional 

328 Convert node data from strings to specified type 

329 data : bool or list of (label,type) tuples 

330 Tuples specifying dictionary key names and types for edge data 

331 edgetype : int, float, str, Python type, optional OBSOLETE 

332 Convert edge data from strings to specified type and use as 'weight' 

333 encoding: string, optional 

334 Specify which encoding to use when reading file. 

335 

336 Returns 

337 ------- 

338 G : graph 

339 A networkx Graph or other type specified with create_using 

340 

341 Examples 

342 -------- 

343 >>> nx.write_edgelist(nx.path_graph(4), "test.edgelist") 

344 >>> G = nx.read_edgelist("test.edgelist") 

345 

346 >>> fh = open("test.edgelist", "rb") 

347 >>> G = nx.read_edgelist(fh) 

348 >>> fh.close() 

349 

350 >>> G = nx.read_edgelist("test.edgelist", nodetype=int) 

351 >>> G = nx.read_edgelist("test.edgelist", create_using=nx.DiGraph) 

352 

353 Edgelist with data in a list: 

354 

355 >>> textline = "1 2 3" 

356 >>> fh = open("test.edgelist", "w") 

357 >>> d = fh.write(textline) 

358 >>> fh.close() 

359 >>> G = nx.read_edgelist("test.edgelist", nodetype=int, data=(("weight", float),)) 

360 >>> list(G) 

361 [1, 2] 

362 >>> list(G.edges(data=True)) 

363 [(1, 2, {'weight': 3.0})] 

364 

365 See parse_edgelist() for more examples of formatting. 

366 

367 See Also 

368 -------- 

369 parse_edgelist 

370 write_edgelist 

371 

372 Notes 

373 ----- 

374 Since nodes must be hashable, the function nodetype must return hashable 

375 types (e.g. int, float, str, frozenset - or tuples of those, etc.) 

376 """ 

377 lines = (line if isinstance(line, str) else line.decode(encoding) for line in path) 

378 return parse_edgelist( 

379 lines, 

380 comments=comments, 

381 delimiter=delimiter, 

382 create_using=create_using, 

383 nodetype=nodetype, 

384 data=data, 

385 ) 

386 

387 

388def write_weighted_edgelist(G, path, comments="#", delimiter=" ", encoding="utf-8"): 

389 """Write graph G as a list of edges with numeric weights. 

390 

391 Parameters 

392 ---------- 

393 G : graph 

394 A NetworkX graph 

395 path : file or string 

396 File or filename to write. If a file is provided, it must be 

397 opened in 'wb' mode. 

398 Filenames ending in .gz or .bz2 will be compressed. 

399 comments : string, optional 

400 The character used to indicate the start of a comment 

401 delimiter : string, optional 

402 The string used to separate values. The default is whitespace. 

403 encoding: string, optional 

404 Specify which encoding to use when writing file. 

405 

406 Examples 

407 -------- 

408 >>> G = nx.Graph() 

409 >>> G.add_edge(1, 2, weight=7) 

410 >>> nx.write_weighted_edgelist(G, "test.weighted.edgelist") 

411 

412 See Also 

413 -------- 

414 read_edgelist 

415 write_edgelist 

416 read_weighted_edgelist 

417 """ 

418 write_edgelist( 

419 G, 

420 path, 

421 comments=comments, 

422 delimiter=delimiter, 

423 data=("weight",), 

424 encoding=encoding, 

425 ) 

426 

427 

428@nx._dispatch(graphs=None) 

429def read_weighted_edgelist( 

430 path, 

431 comments="#", 

432 delimiter=None, 

433 create_using=None, 

434 nodetype=None, 

435 encoding="utf-8", 

436): 

437 """Read a graph as list of edges with numeric weights. 

438 

439 Parameters 

440 ---------- 

441 path : file or string 

442 File or filename to read. If a file is provided, it must be 

443 opened in 'rb' mode. 

444 Filenames ending in .gz or .bz2 will be uncompressed. 

445 comments : string, optional 

446 The character used to indicate the start of a comment. 

447 delimiter : string, optional 

448 The string used to separate values. The default is whitespace. 

449 create_using : NetworkX graph constructor, optional (default=nx.Graph) 

450 Graph type to create. If graph instance, then cleared before populated. 

451 nodetype : int, float, str, Python type, optional 

452 Convert node data from strings to specified type 

453 encoding: string, optional 

454 Specify which encoding to use when reading file. 

455 

456 Returns 

457 ------- 

458 G : graph 

459 A networkx Graph or other type specified with create_using 

460 

461 Notes 

462 ----- 

463 Since nodes must be hashable, the function nodetype must return hashable 

464 types (e.g. int, float, str, frozenset - or tuples of those, etc.) 

465 

466 Example edgelist file format. 

467 

468 With numeric edge data:: 

469 

470 # read with 

471 # >>> G=nx.read_weighted_edgelist(fh) 

472 # source target data 

473 a b 1 

474 a c 3.14159 

475 d e 42 

476 

477 See Also 

478 -------- 

479 write_weighted_edgelist 

480 """ 

481 return read_edgelist( 

482 path, 

483 comments=comments, 

484 delimiter=delimiter, 

485 create_using=create_using, 

486 nodetype=nodetype, 

487 data=(("weight", float),), 

488 encoding=encoding, 

489 )