Spaces:
Running
Running
""" | |
************** | |
Adjacency List | |
************** | |
Read and write NetworkX graphs as adjacency lists. | |
Adjacency list format is useful for graphs without data associated | |
with nodes or edges and for nodes that can be meaningfully represented | |
as strings. | |
Format | |
------ | |
The adjacency list format consists of lines with node labels. The | |
first label in a line is the source node. Further labels in the line | |
are considered target nodes and are added to the graph along with an edge | |
between the source node and target node. | |
The graph with edges a-b, a-c, d-e can be represented as the following | |
adjacency list (anything following the # in a line is a comment):: | |
a b c # source target target | |
d e | |
""" | |
__all__ = ["generate_adjlist", "write_adjlist", "parse_adjlist", "read_adjlist"] | |
import networkx as nx | |
from networkx.utils import open_file | |
def generate_adjlist(G, delimiter=" "): | |
"""Generate a single line of the graph G in adjacency list format. | |
Parameters | |
---------- | |
G : NetworkX graph | |
delimiter : string, optional | |
Separator for node labels | |
Returns | |
------- | |
lines : string | |
Lines of data in adjlist format. | |
Examples | |
-------- | |
>>> G = nx.lollipop_graph(4, 3) | |
>>> for line in nx.generate_adjlist(G): | |
... print(line) | |
0 1 2 3 | |
1 2 3 | |
2 3 | |
3 4 | |
4 5 | |
5 6 | |
6 | |
See Also | |
-------- | |
write_adjlist, read_adjlist | |
Notes | |
----- | |
The default `delimiter=" "` will result in unexpected results if node names contain | |
whitespace characters. To avoid this problem, specify an alternate delimiter when spaces are | |
valid in node names. | |
NB: This option is not available for data that isn't user-generated. | |
""" | |
directed = G.is_directed() | |
seen = set() | |
for s, nbrs in G.adjacency(): | |
line = str(s) + delimiter | |
for t, data in nbrs.items(): | |
if not directed and t in seen: | |
continue | |
if G.is_multigraph(): | |
for d in data.values(): | |
line += str(t) + delimiter | |
else: | |
line += str(t) + delimiter | |
if not directed: | |
seen.add(s) | |
yield line[: -len(delimiter)] | |
def write_adjlist(G, path, comments="#", delimiter=" ", encoding="utf-8"): | |
"""Write graph G in single-line adjacency-list format to path. | |
Parameters | |
---------- | |
G : NetworkX graph | |
path : string or file | |
Filename or file handle for data output. | |
Filenames ending in .gz or .bz2 will be compressed. | |
comments : string, optional | |
Marker for comment lines | |
delimiter : string, optional | |
Separator for node labels | |
encoding : string, optional | |
Text encoding. | |
Examples | |
-------- | |
>>> G = nx.path_graph(4) | |
>>> nx.write_adjlist(G, "test.adjlist") | |
The path can be a filehandle or a string with the name of the file. If a | |
filehandle is provided, it has to be opened in 'wb' mode. | |
>>> fh = open("test.adjlist", "wb") | |
>>> nx.write_adjlist(G, fh) | |
Notes | |
----- | |
The default `delimiter=" "` will result in unexpected results if node names contain | |
whitespace characters. To avoid this problem, specify an alternate delimiter when spaces are | |
valid in node names. | |
NB: This option is not available for data that isn't user-generated. | |
This format does not store graph, node, or edge data. | |
See Also | |
-------- | |
read_adjlist, generate_adjlist | |
""" | |
import sys | |
import time | |
pargs = comments + " ".join(sys.argv) + "\n" | |
header = ( | |
pargs | |
+ comments | |
+ f" GMT {time.asctime(time.gmtime())}\n" | |
+ comments | |
+ f" {G.name}\n" | |
) | |
path.write(header.encode(encoding)) | |
for line in generate_adjlist(G, delimiter): | |
line += "\n" | |
path.write(line.encode(encoding)) | |
def parse_adjlist( | |
lines, comments="#", delimiter=None, create_using=None, nodetype=None | |
): | |
"""Parse lines of a graph adjacency list representation. | |
Parameters | |
---------- | |
lines : list or iterator of strings | |
Input data in adjlist format | |
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. | |
comments : string, optional | |
Marker for comment lines | |
delimiter : string, optional | |
Separator for node labels. The default is whitespace. | |
Returns | |
------- | |
G: NetworkX graph | |
The graph corresponding to the lines in adjacency list format. | |
Examples | |
-------- | |
>>> lines = ["1 2 5", "2 3 4", "3 5", "4", "5"] | |
>>> G = nx.parse_adjlist(lines, nodetype=int) | |
>>> nodes = [1, 2, 3, 4, 5] | |
>>> all(node in G for node in nodes) | |
True | |
>>> edges = [(1, 2), (1, 5), (2, 3), (2, 4), (3, 5)] | |
>>> all((u, v) in G.edges() or (v, u) in G.edges() for (u, v) in edges) | |
True | |
See Also | |
-------- | |
read_adjlist | |
""" | |
G = nx.empty_graph(0, create_using) | |
for line in lines: | |
p = line.find(comments) | |
if p >= 0: | |
line = line[:p] | |
if not len(line): | |
continue | |
vlist = line.strip().split(delimiter) | |
u = vlist.pop(0) | |
# convert types | |
if nodetype is not None: | |
try: | |
u = nodetype(u) | |
except BaseException as err: | |
raise TypeError( | |
f"Failed to convert node ({u}) to type " f"{nodetype}" | |
) from err | |
G.add_node(u) | |
if nodetype is not None: | |
try: | |
vlist = list(map(nodetype, vlist)) | |
except BaseException as err: | |
raise TypeError( | |
f"Failed to convert nodes ({','.join(vlist)}) to type {nodetype}" | |
) from err | |
G.add_edges_from([(u, v) for v in vlist]) | |
return G | |
def read_adjlist( | |
path, | |
comments="#", | |
delimiter=None, | |
create_using=None, | |
nodetype=None, | |
encoding="utf-8", | |
): | |
"""Read graph in adjacency list format from path. | |
Parameters | |
---------- | |
path : string or file | |
Filename or file handle to read. | |
Filenames ending in .gz or .bz2 will be uncompressed. | |
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. | |
comments : string, optional | |
Marker for comment lines | |
delimiter : string, optional | |
Separator for node labels. The default is whitespace. | |
Returns | |
------- | |
G: NetworkX graph | |
The graph corresponding to the lines in adjacency list format. | |
Examples | |
-------- | |
>>> G = nx.path_graph(4) | |
>>> nx.write_adjlist(G, "test.adjlist") | |
>>> G = nx.read_adjlist("test.adjlist") | |
The path can be a filehandle or a string with the name of the file. If a | |
filehandle is provided, it has to be opened in 'rb' mode. | |
>>> fh = open("test.adjlist", "rb") | |
>>> G = nx.read_adjlist(fh) | |
Filenames ending in .gz or .bz2 will be compressed. | |
>>> nx.write_adjlist(G, "test.adjlist.gz") | |
>>> G = nx.read_adjlist("test.adjlist.gz") | |
The optional nodetype is a function to convert node strings to nodetype. | |
For example | |
>>> G = nx.read_adjlist("test.adjlist", nodetype=int) | |
will attempt to convert all nodes to integer type. | |
Since nodes must be hashable, the function nodetype must return hashable | |
types (e.g. int, float, str, frozenset - or tuples of those, etc.) | |
The optional create_using parameter indicates the type of NetworkX graph | |
created. The default is `nx.Graph`, an undirected graph. | |
To read the data as a directed graph use | |
>>> G = nx.read_adjlist("test.adjlist", create_using=nx.DiGraph) | |
Notes | |
----- | |
This format does not store graph or node data. | |
See Also | |
-------- | |
write_adjlist | |
""" | |
lines = (line.decode(encoding) for line in path) | |
return parse_adjlist( | |
lines, | |
comments=comments, | |
delimiter=delimiter, | |
create_using=create_using, | |
nodetype=nodetype, | |
) | |