|
""" |
|
********** |
|
Edge Lists |
|
********** |
|
Read and write NetworkX graphs as edge lists. |
|
|
|
The multi-line adjacency list format is useful for graphs with nodes |
|
that can be meaningfully represented as strings. With the edgelist |
|
format simple edge data can be stored but node or graph data is not. |
|
There is no way of representing isolated nodes unless the node has a |
|
self-loop edge. |
|
|
|
Format |
|
------ |
|
You can read or write three formats of edge lists with these functions. |
|
|
|
Node pairs with no data:: |
|
|
|
1 2 |
|
|
|
Python dictionary as data:: |
|
|
|
1 2 {'weight':7, 'color':'green'} |
|
|
|
Arbitrary data:: |
|
|
|
1 2 7 green |
|
""" |
|
|
|
__all__ = [ |
|
"generate_edgelist", |
|
"write_edgelist", |
|
"parse_edgelist", |
|
"read_edgelist", |
|
"read_weighted_edgelist", |
|
"write_weighted_edgelist", |
|
] |
|
|
|
import networkx as nx |
|
from networkx.utils import open_file |
|
|
|
|
|
def generate_edgelist(G, delimiter=" ", data=True): |
|
"""Generate a single line of the graph G in edge list format. |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
|
|
delimiter : string, optional |
|
Separator for node labels |
|
|
|
data : bool or list of keys |
|
If False generate no edge data. If True use a dictionary |
|
representation of edge data. If a list of keys use a list of data |
|
values corresponding to the keys. |
|
|
|
Returns |
|
------- |
|
lines : string |
|
Lines of data in adjlist format. |
|
|
|
Examples |
|
-------- |
|
>>> G = nx.lollipop_graph(4, 3) |
|
>>> G[1][2]["weight"] = 3 |
|
>>> G[3][4]["capacity"] = 12 |
|
>>> for line in nx.generate_edgelist(G, data=False): |
|
... print(line) |
|
0 1 |
|
0 2 |
|
0 3 |
|
1 2 |
|
1 3 |
|
2 3 |
|
3 4 |
|
4 5 |
|
5 6 |
|
|
|
>>> for line in nx.generate_edgelist(G): |
|
... print(line) |
|
0 1 {} |
|
0 2 {} |
|
0 3 {} |
|
1 2 {'weight': 3} |
|
1 3 {} |
|
2 3 {} |
|
3 4 {'capacity': 12} |
|
4 5 {} |
|
5 6 {} |
|
|
|
>>> for line in nx.generate_edgelist(G, data=["weight"]): |
|
... print(line) |
|
0 1 |
|
0 2 |
|
0 3 |
|
1 2 3 |
|
1 3 |
|
2 3 |
|
3 4 |
|
4 5 |
|
5 6 |
|
|
|
See Also |
|
-------- |
|
write_adjlist, read_adjlist |
|
""" |
|
if data is True: |
|
for u, v, d in G.edges(data=True): |
|
e = u, v, dict(d) |
|
yield delimiter.join(map(str, e)) |
|
elif data is False: |
|
for u, v in G.edges(data=False): |
|
e = u, v |
|
yield delimiter.join(map(str, e)) |
|
else: |
|
for u, v, d in G.edges(data=True): |
|
e = [u, v] |
|
try: |
|
e.extend(d[k] for k in data) |
|
except KeyError: |
|
pass |
|
yield delimiter.join(map(str, e)) |
|
|
|
|
|
@open_file(1, mode="wb") |
|
def write_edgelist(G, path, comments="#", delimiter=" ", data=True, encoding="utf-8"): |
|
"""Write graph as a list of edges. |
|
|
|
Parameters |
|
---------- |
|
G : graph |
|
A NetworkX graph |
|
path : file or string |
|
File or filename to write. If a file is provided, it must be |
|
opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed. |
|
comments : string, optional |
|
The character used to indicate the start of a comment |
|
delimiter : string, optional |
|
The string used to separate values. The default is whitespace. |
|
data : bool or list, optional |
|
If False write no edge data. |
|
If True write a string representation of the edge data dictionary.. |
|
If a list (or other iterable) is provided, write the keys specified |
|
in the list. |
|
encoding: string, optional |
|
Specify which encoding to use when writing file. |
|
|
|
Examples |
|
-------- |
|
>>> G = nx.path_graph(4) |
|
>>> nx.write_edgelist(G, "test.edgelist") |
|
>>> G = nx.path_graph(4) |
|
>>> fh = open("test.edgelist", "wb") |
|
>>> nx.write_edgelist(G, fh) |
|
>>> nx.write_edgelist(G, "test.edgelist.gz") |
|
>>> nx.write_edgelist(G, "test.edgelist.gz", data=False) |
|
|
|
>>> G = nx.Graph() |
|
>>> G.add_edge(1, 2, weight=7, color="red") |
|
>>> nx.write_edgelist(G, "test.edgelist", data=False) |
|
>>> nx.write_edgelist(G, "test.edgelist", data=["color"]) |
|
>>> nx.write_edgelist(G, "test.edgelist", data=["color", "weight"]) |
|
|
|
See Also |
|
-------- |
|
read_edgelist |
|
write_weighted_edgelist |
|
""" |
|
|
|
for line in generate_edgelist(G, delimiter, data): |
|
line += "\n" |
|
path.write(line.encode(encoding)) |
|
|
|
|
|
@nx._dispatchable(graphs=None, returns_graph=True) |
|
def parse_edgelist( |
|
lines, comments="#", delimiter=None, create_using=None, nodetype=None, data=True |
|
): |
|
"""Parse lines of an edge list representation of a graph. |
|
|
|
Parameters |
|
---------- |
|
lines : list or iterator of strings |
|
Input data in edgelist format |
|
comments : string, optional |
|
Marker for comment lines. Default is `'#'`. To specify that no character |
|
should be treated as a comment, use ``comments=None``. |
|
delimiter : string, optional |
|
Separator for node labels. Default is `None`, meaning any whitespace. |
|
create_using : NetworkX graph constructor, optional (default=nx.Graph) |
|
Graph type to create. If graph instance, then cleared before populated. |
|
nodetype : Python type, optional |
|
Convert nodes to this type. Default is `None`, meaning no conversion is |
|
performed. |
|
data : bool or list of (label,type) tuples |
|
If `False` generate no edge data or if `True` use a dictionary |
|
representation of edge data or a list tuples specifying dictionary |
|
key names and types for edge data. |
|
|
|
Returns |
|
------- |
|
G: NetworkX Graph |
|
The graph corresponding to lines |
|
|
|
Examples |
|
-------- |
|
Edgelist with no data: |
|
|
|
>>> lines = ["1 2", "2 3", "3 4"] |
|
>>> G = nx.parse_edgelist(lines, nodetype=int) |
|
>>> list(G) |
|
[1, 2, 3, 4] |
|
>>> list(G.edges()) |
|
[(1, 2), (2, 3), (3, 4)] |
|
|
|
Edgelist with data in Python dictionary representation: |
|
|
|
>>> lines = ["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"] |
|
>>> G = nx.parse_edgelist(lines, nodetype=int) |
|
>>> list(G) |
|
[1, 2, 3, 4] |
|
>>> list(G.edges(data=True)) |
|
[(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] |
|
|
|
Edgelist with data in a list: |
|
|
|
>>> lines = ["1 2 3", "2 3 27", "3 4 3.0"] |
|
>>> G = nx.parse_edgelist(lines, nodetype=int, data=(("weight", float),)) |
|
>>> list(G) |
|
[1, 2, 3, 4] |
|
>>> list(G.edges(data=True)) |
|
[(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] |
|
|
|
See Also |
|
-------- |
|
read_weighted_edgelist |
|
""" |
|
from ast import literal_eval |
|
|
|
G = nx.empty_graph(0, create_using) |
|
for line in lines: |
|
if comments is not None: |
|
p = line.find(comments) |
|
if p >= 0: |
|
line = line[:p] |
|
if not line: |
|
continue |
|
|
|
s = line.strip().split(delimiter) |
|
if len(s) < 2: |
|
continue |
|
u = s.pop(0) |
|
v = s.pop(0) |
|
d = s |
|
if nodetype is not None: |
|
try: |
|
u = nodetype(u) |
|
v = nodetype(v) |
|
except Exception as err: |
|
raise TypeError( |
|
f"Failed to convert nodes {u},{v} to type {nodetype}." |
|
) from err |
|
|
|
if len(d) == 0 or data is False: |
|
|
|
edgedata = {} |
|
elif data is True: |
|
|
|
try: |
|
if delimiter == ",": |
|
edgedata_str = ",".join(d) |
|
else: |
|
edgedata_str = " ".join(d) |
|
edgedata = dict(literal_eval(edgedata_str.strip())) |
|
except Exception as err: |
|
raise TypeError( |
|
f"Failed to convert edge data ({d}) to dictionary." |
|
) from err |
|
else: |
|
|
|
if len(d) != len(data): |
|
raise IndexError( |
|
f"Edge data {d} and data_keys {data} are not the same length" |
|
) |
|
edgedata = {} |
|
for (edge_key, edge_type), edge_value in zip(data, d): |
|
try: |
|
edge_value = edge_type(edge_value) |
|
except Exception as err: |
|
raise TypeError( |
|
f"Failed to convert {edge_key} data {edge_value} " |
|
f"to type {edge_type}." |
|
) from err |
|
edgedata.update({edge_key: edge_value}) |
|
G.add_edge(u, v, **edgedata) |
|
return G |
|
|
|
|
|
@open_file(0, mode="rb") |
|
@nx._dispatchable(graphs=None, returns_graph=True) |
|
def read_edgelist( |
|
path, |
|
comments="#", |
|
delimiter=None, |
|
create_using=None, |
|
nodetype=None, |
|
data=True, |
|
edgetype=None, |
|
encoding="utf-8", |
|
): |
|
"""Read a graph from a list of edges. |
|
|
|
Parameters |
|
---------- |
|
path : file or string |
|
File or filename to read. If a file is provided, it must be |
|
opened in 'rb' mode. |
|
Filenames ending in .gz or .bz2 will be uncompressed. |
|
comments : string, optional |
|
The character used to indicate the start of a comment. To specify that |
|
no character should be treated as a comment, use ``comments=None``. |
|
delimiter : string, optional |
|
The string used to separate values. The default is whitespace. |
|
create_using : NetworkX graph constructor, optional (default=nx.Graph) |
|
Graph type to create. If graph instance, then cleared before populated. |
|
nodetype : int, float, str, Python type, optional |
|
Convert node data from strings to specified type |
|
data : bool or list of (label,type) tuples |
|
Tuples specifying dictionary key names and types for edge data |
|
edgetype : int, float, str, Python type, optional OBSOLETE |
|
Convert edge data from strings to specified type and use as 'weight' |
|
encoding: string, optional |
|
Specify which encoding to use when reading file. |
|
|
|
Returns |
|
------- |
|
G : graph |
|
A networkx Graph or other type specified with create_using |
|
|
|
Examples |
|
-------- |
|
>>> nx.write_edgelist(nx.path_graph(4), "test.edgelist") |
|
>>> G = nx.read_edgelist("test.edgelist") |
|
|
|
>>> fh = open("test.edgelist", "rb") |
|
>>> G = nx.read_edgelist(fh) |
|
>>> fh.close() |
|
|
|
>>> G = nx.read_edgelist("test.edgelist", nodetype=int) |
|
>>> G = nx.read_edgelist("test.edgelist", create_using=nx.DiGraph) |
|
|
|
Edgelist with data in a list: |
|
|
|
>>> textline = "1 2 3" |
|
>>> fh = open("test.edgelist", "w") |
|
>>> d = fh.write(textline) |
|
>>> fh.close() |
|
>>> G = nx.read_edgelist("test.edgelist", nodetype=int, data=(("weight", float),)) |
|
>>> list(G) |
|
[1, 2] |
|
>>> list(G.edges(data=True)) |
|
[(1, 2, {'weight': 3.0})] |
|
|
|
See parse_edgelist() for more examples of formatting. |
|
|
|
See Also |
|
-------- |
|
parse_edgelist |
|
write_edgelist |
|
|
|
Notes |
|
----- |
|
Since nodes must be hashable, the function nodetype must return hashable |
|
types (e.g. int, float, str, frozenset - or tuples of those, etc.) |
|
""" |
|
lines = (line if isinstance(line, str) else line.decode(encoding) for line in path) |
|
return parse_edgelist( |
|
lines, |
|
comments=comments, |
|
delimiter=delimiter, |
|
create_using=create_using, |
|
nodetype=nodetype, |
|
data=data, |
|
) |
|
|
|
|
|
def write_weighted_edgelist(G, path, comments="#", delimiter=" ", encoding="utf-8"): |
|
"""Write graph G as a list of edges with numeric weights. |
|
|
|
Parameters |
|
---------- |
|
G : graph |
|
A NetworkX graph |
|
path : file or string |
|
File or filename to write. If a file is provided, it must be |
|
opened in 'wb' mode. |
|
Filenames ending in .gz or .bz2 will be compressed. |
|
comments : string, optional |
|
The character used to indicate the start of a comment |
|
delimiter : string, optional |
|
The string used to separate values. The default is whitespace. |
|
encoding: string, optional |
|
Specify which encoding to use when writing file. |
|
|
|
Examples |
|
-------- |
|
>>> G = nx.Graph() |
|
>>> G.add_edge(1, 2, weight=7) |
|
>>> nx.write_weighted_edgelist(G, "test.weighted.edgelist") |
|
|
|
See Also |
|
-------- |
|
read_edgelist |
|
write_edgelist |
|
read_weighted_edgelist |
|
""" |
|
write_edgelist( |
|
G, |
|
path, |
|
comments=comments, |
|
delimiter=delimiter, |
|
data=("weight",), |
|
encoding=encoding, |
|
) |
|
|
|
|
|
@nx._dispatchable(graphs=None, returns_graph=True) |
|
def read_weighted_edgelist( |
|
path, |
|
comments="#", |
|
delimiter=None, |
|
create_using=None, |
|
nodetype=None, |
|
encoding="utf-8", |
|
): |
|
"""Read a graph as list of edges with numeric weights. |
|
|
|
Parameters |
|
---------- |
|
path : file or string |
|
File or filename to read. If a file is provided, it must be |
|
opened in 'rb' mode. |
|
Filenames ending in .gz or .bz2 will be uncompressed. |
|
comments : string, optional |
|
The character used to indicate the start of a comment. |
|
delimiter : string, optional |
|
The string used to separate values. The default is whitespace. |
|
create_using : NetworkX graph constructor, optional (default=nx.Graph) |
|
Graph type to create. If graph instance, then cleared before populated. |
|
nodetype : int, float, str, Python type, optional |
|
Convert node data from strings to specified type |
|
encoding: string, optional |
|
Specify which encoding to use when reading file. |
|
|
|
Returns |
|
------- |
|
G : graph |
|
A networkx Graph or other type specified with create_using |
|
|
|
Notes |
|
----- |
|
Since nodes must be hashable, the function nodetype must return hashable |
|
types (e.g. int, float, str, frozenset - or tuples of those, etc.) |
|
|
|
Example edgelist file format. |
|
|
|
With numeric edge data:: |
|
|
|
# read with |
|
# >>> G=nx.read_weighted_edgelist(fh) |
|
# source target data |
|
a b 1 |
|
a c 3.14159 |
|
d e 42 |
|
|
|
See Also |
|
-------- |
|
write_weighted_edgelist |
|
""" |
|
return read_edgelist( |
|
path, |
|
comments=comments, |
|
delimiter=delimiter, |
|
create_using=create_using, |
|
nodetype=nodetype, |
|
data=(("weight", float),), |
|
encoding=encoding, |
|
) |
|
|