Statistics
| Branch: | Revision:

iof-tools / networkxMiCe / networkx-master / networkx / readwrite / edgelist.py @ 5cef0f13

History | View | Annotate | Download (13.8 KB)

1
"""
2
**********
3
Edge Lists
4
**********
5
Read and write NetworkX graphs as edge lists.
6

7
The multi-line adjacency list format is useful for graphs with nodes
8
that can be meaningfully represented as strings.  With the edgelist
9
format simple edge data can be stored but node or graph data is not.
10
There is no way of representing isolated nodes unless the node has a
11
self-loop edge.
12

13
Format
14
------
15
You can read or write three formats of edge lists with these functions.
16

17
Node pairs with no data::
18

19
 1 2
20

21
Python dictionary as data::
22

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

25
Arbitrary data::
26

27
 1 2 7 green
28
"""
29
__author__ = """Aric Hagberg (hagberg@lanl.gov)\nDan Schult (dschult@colgate.edu)"""
30
#    Copyright (C) 2004-2019 by
31
#    Aric Hagberg <hagberg@lanl.gov>
32
#    Dan Schult <dschult@colgate.edu>
33
#    Pieter Swart <swart@lanl.gov>
34
#    All rights reserved.
35
#    BSD license.
36

    
37
__all__ = ['generate_edgelist',
38
           'write_edgelist',
39
           'parse_edgelist',
40
           'read_edgelist',
41
           'read_weighted_edgelist',
42
           'write_weighted_edgelist']
43

    
44
from networkx.utils import open_file, make_str
45
import networkx as nx
46

    
47

    
48
def generate_edgelist(G, delimiter=' ', data=True):
49
    """Generate a single line of the graph G in edge list format.
50

51
    Parameters
52
    ----------
53
    G : NetworkX graph
54

55
    delimiter : string, optional
56
       Separator for node labels
57

58
    data : bool or list of keys
59
       If False generate no edge data.  If True use a dictionary
60
       representation of edge data.  If a list of keys use a list of data
61
       values corresponding to the keys.
62

63
    Returns
64
    -------
65
    lines : string
66
        Lines of data in adjlist format.
67

68
    Examples
69
    --------
70
    >>> G = nx.lollipop_graph(4, 3)
71
    >>> G[1][2]['weight'] = 3
72
    >>> G[3][4]['capacity'] = 12
73
    >>> for line in nx.generate_edgelist(G, data=False):
74
    ...     print(line)
75
    0 1
76
    0 2
77
    0 3
78
    1 2
79
    1 3
80
    2 3
81
    3 4
82
    4 5
83
    5 6
84

85
    >>> for line in nx.generate_edgelist(G):
86
    ...     print(line)
87
    0 1 {}
88
    0 2 {}
89
    0 3 {}
90
    1 2 {'weight': 3}
91
    1 3 {}
92
    2 3 {}
93
    3 4 {'capacity': 12}
94
    4 5 {}
95
    5 6 {}
96

97
    >>> for line in nx.generate_edgelist(G,data=['weight']):
98
    ...     print(line)
99
    0 1
100
    0 2
101
    0 3
102
    1 2 3
103
    1 3
104
    2 3
105
    3 4
106
    4 5
107
    5 6
108

109
    See Also
110
    --------
111
    write_adjlist, read_adjlist
112
    """
113
    if data is True:
114
        for u, v, d in G.edges(data=True):
115
            e = u, v, dict(d)
116
            yield delimiter.join(map(make_str, e))
117
    elif data is False:
118
        for u, v in G.edges(data=False):
119
            e = u, v
120
            yield delimiter.join(map(make_str, e))
121
    else:
122
        for u, v, d in G.edges(data=True):
123
            e = [u, v]
124
            try:
125
                e.extend(d[k] for k in data)
126
            except KeyError:
127
                pass  # missing data for this edge, should warn?
128
            yield delimiter.join(map(make_str, e))
129

    
130

    
131
@open_file(1, mode='wb')
132
def write_edgelist(G, path, comments="#", delimiter=' ', data=True,
133
                   encoding='utf-8'):
134
    """Write graph as a list of edges.
135

136
    Parameters
137
    ----------
138
    G : graph
139
       A NetworkX graph
140
    path : file or string
141
       File or filename to write. If a file is provided, it must be
142
       opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed.
143
    comments : string, optional
144
       The character used to indicate the start of a comment
145
    delimiter : string, optional
146
       The string used to separate values.  The default is whitespace.
147
    data : bool or list, optional
148
       If False write no edge data.
149
       If True write a string representation of the edge data dictionary..
150
       If a list (or other iterable) is provided, write the  keys specified
151
       in the list.
152
    encoding: string, optional
153
       Specify which encoding to use when writing file.
154

155
    Examples
156
    --------
157
    >>> G=nx.path_graph(4)
158
    >>> nx.write_edgelist(G, "test.edgelist")
159
    >>> G=nx.path_graph(4)
160
    >>> fh=open("test.edgelist",'wb')
161
    >>> nx.write_edgelist(G, fh)
162
    >>> nx.write_edgelist(G, "test.edgelist.gz")
163
    >>> nx.write_edgelist(G, "test.edgelist.gz", data=False)
164

165
    >>> G=nx.Graph()
166
    >>> G.add_edge(1,2,weight=7,color='red')
167
    >>> nx.write_edgelist(G,'test.edgelist',data=False)
168
    >>> nx.write_edgelist(G,'test.edgelist',data=['color'])
169
    >>> nx.write_edgelist(G,'test.edgelist',data=['color','weight'])
170

171
    See Also
172
    --------
173
    read_edgelist
174
    write_weighted_edgelist
175
    """
176

    
177
    for line in generate_edgelist(G, delimiter, data):
178
        line += '\n'
179
        path.write(line.encode(encoding))
180

    
181

    
182
def parse_edgelist(lines, comments='#', delimiter=None,
183
                   create_using=None, nodetype=None, data=True):
184
    """Parse lines of an edge list representation of a graph.
185

186
    Parameters
187
    ----------
188
    lines : list or iterator of strings
189
        Input data in edgelist format
190
    comments : string, optional
191
       Marker for comment lines
192
    delimiter : string, optional
193
       Separator for node labels
194
    create_using : NetworkX graph constructor, optional (default=nx.Graph)
195
       Graph type to create. If graph instance, then cleared before populated.
196
    nodetype : Python type, optional
197
       Convert nodes to this type.
198
    data : bool or list of (label,type) tuples
199
       If False generate no edge data or if True use a dictionary
200
       representation of edge data or a list tuples specifying dictionary
201
       key names and types for edge data.
202

203
    Returns
204
    -------
205
    G: NetworkX Graph
206
        The graph corresponding to lines
207

208
    Examples
209
    --------
210
    Edgelist with no data:
211

212
    >>> lines = ["1 2",
213
    ...          "2 3",
214
    ...          "3 4"]
215
    >>> G = nx.parse_edgelist(lines, nodetype = int)
216
    >>> list(G)
217
    [1, 2, 3, 4]
218
    >>> list(G.edges())
219
    [(1, 2), (2, 3), (3, 4)]
220

221
    Edgelist with data in Python dictionary representation:
222

223
    >>> lines = ["1 2 {'weight':3}",
224
    ...          "2 3 {'weight':27}",
225
    ...          "3 4 {'weight':3.0}"]
226
    >>> G = nx.parse_edgelist(lines, nodetype = int)
227
    >>> list(G)
228
    [1, 2, 3, 4]
229
    >>> list(G.edges(data=True))
230
    [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})]
231

232
    Edgelist with data in a list:
233

234
    >>> lines = ["1 2 3",
235
    ...          "2 3 27",
236
    ...          "3 4 3.0"]
237
    >>> G = nx.parse_edgelist(lines, nodetype = int, data=(('weight',float),))
238
    >>> list(G)
239
    [1, 2, 3, 4]
240
    >>> list(G.edges(data=True))
241
    [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})]
242

243
    See Also
244
    --------
245
    read_weighted_edgelist
246
    """
247
    from ast import literal_eval
248
    G = nx.empty_graph(0, create_using)
249
    for line in lines:
250
        p = line.find(comments)
251
        if p >= 0:
252
            line = line[:p]
253
        if not len(line):
254
            continue
255
        # split line, should have 2 or more
256
        s = line.strip().split(delimiter)
257
        if len(s) < 2:
258
            continue
259
        u = s.pop(0)
260
        v = s.pop(0)
261
        d = s
262
        if nodetype is not None:
263
            try:
264
                u = nodetype(u)
265
                v = nodetype(v)
266
            except:
267
                raise TypeError("Failed to convert nodes %s,%s to type %s."
268
                                % (u, v, nodetype))
269

    
270
        if len(d) == 0 or data is False:
271
            # no data or data type specified
272
            edgedata = {}
273
        elif data is True:
274
            # no edge types specified
275
            try:  # try to evaluate as dictionary
276
                edgedata = dict(literal_eval(' '.join(d)))
277
            except:
278
                raise TypeError(
279
                    "Failed to convert edge data (%s) to dictionary." % (d))
280
        else:
281
            # convert edge data to dictionary with specified keys and type
282
            if len(d) != len(data):
283
                raise IndexError(
284
                    "Edge data %s and data_keys %s are not the same length" %
285
                    (d, data))
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:
291
                    raise TypeError(
292
                        "Failed to convert %s data %s to type %s."
293
                        % (edge_key, edge_value, edge_type))
294
                edgedata.update({edge_key: edge_value})
295
        G.add_edge(u, v, **edgedata)
296
    return G
297

    
298

    
299
@open_file(0, mode='rb')
300
def read_edgelist(path, comments="#", delimiter=None, create_using=None,
301
                  nodetype=None, data=True, edgetype=None, encoding='utf-8'):
302
    """Read a graph from a list of edges.
303

304
    Parameters
305
    ----------
306
    path : file or string
307
       File or filename to read. If a file is provided, it must be
308
       opened in 'rb' mode.
309
       Filenames ending in .gz or .bz2 will be uncompressed.
310
    comments : string, optional
311
       The character used to indicate the start of a comment.
312
    delimiter : string, optional
313
       The string used to separate values.  The default is whitespace.
314
    create_using : NetworkX graph constructor, optional (default=nx.Graph)
315
       Graph type to create. If graph instance, then cleared before populated.
316
    nodetype : int, float, str, Python type, optional
317
       Convert node data from strings to specified type
318
    data : bool or list of (label,type) tuples
319
       Tuples specifying dictionary key names and types for edge data
320
    edgetype : int, float, str, Python type, optional OBSOLETE
321
       Convert edge data from strings to specified type and use as 'weight'
322
    encoding: string, optional
323
       Specify which encoding to use when reading file.
324

325
    Returns
326
    -------
327
    G : graph
328
       A networkx Graph or other type specified with create_using
329

330
    Examples
331
    --------
332
    >>> nx.write_edgelist(nx.path_graph(4), "test.edgelist")
333
    >>> G=nx.read_edgelist("test.edgelist")
334

335
    >>> fh=open("test.edgelist", 'rb')
336
    >>> G=nx.read_edgelist(fh)
337
    >>> fh.close()
338

339
    >>> G=nx.read_edgelist("test.edgelist", nodetype=int)
340
    >>> G=nx.read_edgelist("test.edgelist",create_using=nx.DiGraph)
341

342
    Edgelist with data in a list:
343

344
    >>> textline = '1 2 3'
345
    >>> fh = open('test.edgelist','w')
346
    >>> d = fh.write(textline)
347
    >>> fh.close()
348
    >>> G = nx.read_edgelist('test.edgelist', nodetype=int, data=(('weight',float),))
349
    >>> list(G)
350
    [1, 2]
351
    >>> list(G.edges(data=True))
352
    [(1, 2, {'weight': 3.0})]
353

354
    See parse_edgelist() for more examples of formatting.
355

356
    See Also
357
    --------
358
    parse_edgelist
359
    write_edgelist
360

361
    Notes
362
    -----
363
    Since nodes must be hashable, the function nodetype must return hashable
364
    types (e.g. int, float, str, frozenset - or tuples of those, etc.)
365
    """
366
    lines = (line.decode(encoding) for line in path)
367
    return parse_edgelist(lines, comments=comments, delimiter=delimiter,
368
                          create_using=create_using, nodetype=nodetype,
369
                          data=data)
370

    
371

    
372
def write_weighted_edgelist(G, path, comments="#",
373
                            delimiter=' ', encoding='utf-8'):
374
    """Write graph G as a list of edges with numeric weights.
375

376
    Parameters
377
    ----------
378
    G : graph
379
       A NetworkX graph
380
    path : file or string
381
       File or filename to write. If a file is provided, it must be
382
       opened in 'wb' mode.
383
       Filenames ending in .gz or .bz2 will be compressed.
384
    comments : string, optional
385
       The character used to indicate the start of a comment
386
    delimiter : string, optional
387
       The string used to separate values.  The default is whitespace.
388
    encoding: string, optional
389
       Specify which encoding to use when writing file.
390

391
    Examples
392
    --------
393
    >>> G=nx.Graph()
394
    >>> G.add_edge(1,2,weight=7)
395
    >>> nx.write_weighted_edgelist(G, 'test.weighted.edgelist')
396

397
    See Also
398
    --------
399
    read_edgelist
400
    write_edgelist
401
    read_weighted_edgelist
402
    """
403
    write_edgelist(G, path, comments=comments, delimiter=delimiter,
404
                   data=('weight',), encoding=encoding)
405

    
406

    
407
def read_weighted_edgelist(path, comments="#", delimiter=None,
408
                           create_using=None, nodetype=None, encoding='utf-8'):
409
    """Read a graph as list of edges with numeric weights.
410

411
    Parameters
412
    ----------
413
    path : file or string
414
       File or filename to read. If a file is provided, it must be
415
       opened in 'rb' mode.
416
       Filenames ending in .gz or .bz2 will be uncompressed.
417
    comments : string, optional
418
       The character used to indicate the start of a comment.
419
    delimiter : string, optional
420
       The string used to separate values.  The default is whitespace.
421
    create_using : NetworkX graph constructor, optional (default=nx.Graph)
422
       Graph type to create. If graph instance, then cleared before populated.
423
    nodetype : int, float, str, Python type, optional
424
       Convert node data from strings to specified type
425
    encoding: string, optional
426
       Specify which encoding to use when reading file.
427

428
    Returns
429
    -------
430
    G : graph
431
       A networkx Graph or other type specified with create_using
432

433
    Notes
434
    -----
435
    Since nodes must be hashable, the function nodetype must return hashable
436
    types (e.g. int, float, str, frozenset - or tuples of those, etc.)
437

438
    Example edgelist file format.
439

440
    With numeric edge data::
441

442
     # read with
443
     # >>> G=nx.read_weighted_edgelist(fh)
444
     # source target data
445
     a b 1
446
     a c 3.14159
447
     d e 42
448
    
449
    See Also
450
    --------
451
    write_weighted_edgelist
452
    """
453
    return read_edgelist(path,
454
                         comments=comments,
455
                         delimiter=delimiter,
456
                         create_using=create_using,
457
                         nodetype=nodetype,
458
                         data=(('weight', float),),
459
                         encoding=encoding
460
                         )
461

    
462

    
463
# fixture for nose tests
464
def teardown_module(module):
465
    import os
466
    for fname in ['test.edgelist', 'test.edgelist.gz',
467
                  'test.weighted.edgelist']:
468
        if os.path.isfile(fname):
469
            os.unlink(fname)