diff options
author | aric <none@none> | 2010-08-20 20:21:28 +0000 |
---|---|---|
committer | aric <none@none> | 2010-08-20 20:21:28 +0000 |
commit | c7af2b9dc774d5edd64fe0edc75ac6b291a60e4c (patch) | |
tree | 9d0c2e2da66df09822a95f50a5c42ba0b0d5a9fc | |
parent | e30ab2bc62b1e00d72daba88b78e75cd04fb3358 (diff) | |
download | networkx-c7af2b9dc774d5edd64fe0edc75ac6b291a60e4c.tar.gz |
Split multiline_adglist and adjlist. Add documentation.
Don't add linefeed to end of line in generate_* functions.
--HG--
extra : convert_revision : svn%3A3ed01bd8-26fb-0310-9e4c-ca1a4053419f/networkx/trunk%401924
-rw-r--r-- | doc/source/reference/readwrite.adjlist.rst | 4 | ||||
-rw-r--r-- | doc/source/reference/readwrite.rst | 1 | ||||
-rw-r--r-- | networkx/readwrite/__init__.py | 2 | ||||
-rw-r--r-- | networkx/readwrite/adjlist.py | 534 | ||||
-rw-r--r-- | networkx/readwrite/multiline_adjlist.py | 389 |
5 files changed, 522 insertions, 408 deletions
diff --git a/doc/source/reference/readwrite.adjlist.rst b/doc/source/reference/readwrite.adjlist.rst index 3550a109..cb86a364 100644 --- a/doc/source/reference/readwrite.adjlist.rst +++ b/doc/source/reference/readwrite.adjlist.rst @@ -10,5 +10,5 @@ Adjacency List read_adjlist write_adjlist - read_multiline_adjlist - write_multiline_adjlist + parse_adjlist + generate_adjlist diff --git a/doc/source/reference/readwrite.rst b/doc/source/reference/readwrite.rst index 37794d49..cde75d54 100644 --- a/doc/source/reference/readwrite.rst +++ b/doc/source/reference/readwrite.rst @@ -8,6 +8,7 @@ Reading and writing graphs :maxdepth: 2 readwrite.adjlist + readwrite.multiline_adjlist readwrite.edgelist readwrite.gml readwrite.gpickle diff --git a/networkx/readwrite/__init__.py b/networkx/readwrite/__init__.py index b4212251..2710e5c4 100644 --- a/networkx/readwrite/__init__.py +++ b/networkx/readwrite/__init__.py @@ -2,8 +2,8 @@ A package for reading and writing graphs in various formats. """ -import sys from networkx.readwrite.adjlist import * +from networkx.readwrite.multiline_adjlist import * from networkx.readwrite.edgelist import * from networkx.readwrite.gpickle import * from networkx.readwrite.pajek import * diff --git a/networkx/readwrite/adjlist.py b/networkx/readwrite/adjlist.py index 05a9e29d..9712e725 100644 --- a/networkx/readwrite/adjlist.py +++ b/networkx/readwrite/adjlist.py @@ -1,396 +1,66 @@ # -*- coding: utf-8 -*- """ -*************** -Adjacency Lists -*************** - +************** +Adjacency List +************** Read and write NetworkX graphs as adjacency lists. -Note that NetworkX graphs can contain any hashable Python object as -node (not just integers and strings). So writing a NetworkX graph -as a text file may not always be what you want: see write_gpickle -and gread_gpickle for that case. - -This module provides the following : - -Adjacency list with single line per node: -Useful for connected or unconnected graphs without edge data. +Adjacency list format is useful for graphs without data associated +with nodes or edges and for nodes that can be meaningfully represented +as strings. ->>> G=nx.path_graph(4) ->>> path='test.adjlist' ->>> write_adjlist(G, path) ->>> G=read_adjlist(path) +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. -Adjacency list with multiple lines per node: -Useful for connected or unconnected graphs with or without edge data. - ->>> write_multiline_adjlist(G, path) ->>> G=read_multiline_adjlist(path) +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 """ __author__ = '\n'.join(['Aric Hagberg <hagberg@lanl.gov>', 'Dan Schult <dschult@colgate.edu>', 'Loïc Séguin-C. <loicseguin@gmail.com>']) -# Copyright (C) 2004-2009 by +# Copyright (C) 2004-2010 by # Aric Hagberg <hagberg@lanl.gov> # Dan Schult <dschult@colgate.edu> # Pieter Swart <swart@lanl.gov> # All rights reserved. # BSD license. -__all__ = ['generate_multiline_adjlist', - 'write_multiline_adjlist', - 'parse_multiline_adjlist', - 'read_multiline_adjlist', - 'generate_adjlist', +__all__ = ['generate_adjlist', 'write_adjlist', 'parse_adjlist', 'read_adjlist'] - from networkx.utils import is_string_like, make_str, _get_fh import networkx as nx -def generate_multiline_adjlist(G, delimiter = ' '): - """Generate a single entry of the graph G in multiline adjacency list format. - - This function is a generator. - - See read_multiline_adjlist for format details. - - Examples - -------- - - >>> G = nx.lollipop_graph(4, 3) - >>> adjlist_str = '' - >>> for line in nx.generate_multiline_adjlist(G): - ... adjlist_str += line - ... - >>> print(adjlist_str[:-1]) - 0 3 - 1 {} - 2 {} - 3 {} - 1 2 - 2 {} - 3 {} - 2 1 - 3 {} - 3 1 - 4 {} - 4 1 - 5 {} - 5 1 - 6 {} - 6 0 - - """ - - if G.is_directed(): - if G.is_multigraph(): - for s,nbrs in G.adjacency_iter(): - nbr_edges=[ (u,data) - for u,datadict in nbrs.items() - for key,data in datadict.items()] - deg=len(nbr_edges) - multiline = make_str(s)+delimiter+"%i\n"%(deg) - for u,d in nbr_edges: - if d is None: - multiline += make_str(u)+'\n' - else: - multiline += make_str(u)+delimiter+make_str(d)+"\n" - yield multiline - else: # directed single edges - for s,nbrs in G.adjacency_iter(): - deg=len(nbrs) - multiline = make_str(s)+delimiter+"%i\n"%(deg) - for u,d in nbrs.items(): - if d is None: - multiline += make_str(u)+'\n' - else: - multiline += make_str(u)+delimiter+make_str(d)+"\n" - yield multiline - else: # undirected - if G.is_multigraph(): - seen=set() # helper dict used to avoid duplicate edges - for s,nbrs in G.adjacency_iter(): - nbr_edges=[ (u,data) - for u,datadict in nbrs.items() - if u not in seen - for key,data in datadict.items()] - deg=len(nbr_edges) - multiline = make_str(s)+delimiter+"%i\n"%(deg) - for u,d in nbr_edges: - if d is None: - multiline += make_str(u)+'\n' - else: - multiline += make_str(u)+delimiter+make_str(d)+"\n" - seen.add(s) - yield multiline - else: # undirected single edges - seen=set() # helper dict used to avoid duplicate edges - for s,nbrs in G.adjacency_iter(): - nbr_edges=[ (u,d) for u,d in nbrs.items() if u not in seen] - deg=len(nbr_edges) - multiline = make_str(s)+delimiter+"%i\n"%(deg) - for u,d in nbr_edges: - if d is None: - multiline += make_str(u)+'\n' - else: - multiline += make_str(u)+delimiter+make_str(d)+"\n" - seen.add(s) - yield multiline - -def write_multiline_adjlist(G, path, delimiter=' ', comments='#', - encoding = 'utf-8'): - """ - Write the graph G in multiline adjacency list format to the file or file handle path. - - See read_multiline_adjlist for file format details. - - Examples - -------- - - >>> G=nx.path_graph(4) - >>> nx.write_multiline_adjlist(G,"test.adjlist") - - 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_multiline_adjlist(G,fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_multiline_adjlist(G,"test.adjlist.gz") - - The file will use the utf-8 encoding by default. - It is possible to write files in other encodings by providing the - encoding argument to write_multiline_adjlist. - - >>> fh=open("test.adjlist",'wb') - >>> nx.write_multiline_adjlist(G,fh,encoding='utf-8') - - The same result can be obtained with the following call. - >>> nx.write_multiline_adjlist(G, 'test-utf8.adjlist', encoding = 'utf-8') - - """ - import sys - import time - - fh=_get_fh(path,mode='wb') - pargs=comments+" ".join(sys.argv) - header = ("%s\n" % (pargs) - + comments + " GMT %s\n" % (time.asctime(time.gmtime())) - + comments + " %s\n" % (G.name)) - fh.write(header.encode(encoding)) - - for multiline in generate_multiline_adjlist(G, delimiter): - fh.write(multiline.encode(encoding)) - -def parse_multiline_adjlist(lines, comments = '#', delimiter = ' ', - create_using = None, nodetype = None, - edgetype = None): - """Parse lines of a multiline adjacency list representation of a graph. - - See read_multiline_adjlist for file format details. - - Returns - ------- - G: NetworkX Graph - The graph corresponding to lines - - Examples - -------- - >>> lines = ['1 2', - ... "2 {'weight':3, 'name': 'Frodo'}", - ... "3 {}", - ... "2 1", - ... "5 {'weigth':6, 'name': 'Saruman'}"] - >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype = int) - >>> G.nodes() - [1, 2, 3, 5] - >>> G.edges(data = True) - [(1, 2, {'name': 'Frodo', 'weight': 3}), (1, 3, {}), (2, 5, {'name': 'Saruman', 'weigth': 6})] - - - """ - if create_using is None: - G=nx.Graph() - else: - try: - G=create_using - G.clear() - except: - raise TypeError("Input graph is not a networkx graph type") - - for line in lines: - p=line.find(comments) - if p>=0: - line = line[:p] - if not line: continue - try: - (u,deg)=line.strip().split(delimiter) - deg=int(deg) - except: - raise TypeError("Failed to read node and degree on line (%s)"%line) - if nodetype is not None: - try: - u=nodetype(u) - except: - raise TypeError("Failed to convert node (%s) to type %s"\ - %(u,nodetype)) - G.add_node(u) - for i in range(deg): - while True: - try: - line = next(lines) - except StopIteration: - msg = "Failed to find neighbor for node (%s)" % (u,) - raise TypeError(msg) - p=line.find(comments) - if p>=0: - line = line[:p] - if line: break - vlist=line.strip().split(delimiter) - numb=len(vlist) - if numb<1: - continue # isolated node - v=vlist.pop(0) - data=''.join(vlist) - if nodetype is not None: - try: - v=nodetype(v) - except: - raise TypeError( - "Failed to convert node (%s) to type %s"\ - %(v,nodetype)) - if edgetype is not None: - try: - edgedata={'weight':edgetype(data)} - except: - raise TypeError( - "Failed to convert edge data (%s) to type %s"\ - %(data, edgetype)) - else: - try: - from ast import literal_eval - except: - literal_eval=eval # use potentially unsafe built-in eval - try: # try to evaluate - edgedata=literal_eval(data) - except: - edgedata={} - G.add_edge(u,v,attr_dict=edgedata) - - return G - - -def read_multiline_adjlist(path, comments="#", delimiter=' ', - create_using=None, - nodetype=None, edgetype=None, - encoding = 'utf-8'): - """Read graph in multi-line adjacency list format from path. - - Examples - -------- - - >>> G=nx.path_graph(4) - >>> nx.write_multiline_adjlist(G,"test.adjlist") - >>> G=nx.read_multiline_adjlist("test.adjlist") - - 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_multiline_adjlist(fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_multiline_adjlist(G,"test.adjlist.gz") - >>> G=nx.read_multiline_adjlist("test.adjlist.gz") - - nodetype is an optional function to convert node strings to nodetype - - For example - - >>> G=nx.read_multiline_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.) - - edgetype is a function to convert edge data strings to edgetype - - >>> G=nx.read_multiline_adjlist("test.adjlist") - - create_using is an optional networkx graph type, the default is - Graph(), a simple undirected graph - - >>> G=nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph()) - - The comments character (default='#') at the beginning of a - line indicates a comment line. - - The entries are separated by delimiter (default=' '). - If whitespace is significant in node or edge labels you should use - some other delimiter such as a tab or other symbol. - - - Example multiline adjlist file format - - No edge data:: - - # source target for Graph or DiGraph - a 2 - b - c - d 1 - e - - With edge data:: - - # source target for XGraph or XDiGraph with edge data - a 2 - b edge-ab-data - c edge-ac-data - d 1 - e edge-de-data - - Reading the file will use the utf-8 text encoding by default. - It is possible to read files with other encodings by providing the - encoding arguement to read_multiline_adjlist. - - >>> fh=open("test.adjlist",'rb') - >>> G=nx.read_multiline_adjlist(fh, encoding = 'iso-8859-1') - """ - inp=_get_fh(path, 'rb') - lines = (line.decode(encoding) for line in inp) - return parse_multiline_adjlist(lines, - comments = comments, - delimiter = delimiter, - create_using = create_using, - nodetype = nodetype, - edgetype = edgetype) - def generate_adjlist(G, delimiter = ' '): """Generate a single line of the graph G in adjacency list format. - This function is a generator. + Parameters + ---------- + G : NetworkX graph + + delimiter : string, optional + Separator for node labels - See read_adjlist for line format details. + Yields + ------ + lines : string + Lines of data in adjlist format. Examples -------- - >>> G = nx.lollipop_graph(4, 3) - >>> adjlist_str = '' >>> for line in nx.generate_adjlist(G): - ... adjlist_str += line - ... - >>> print(adjlist_str[:-1]) + ... print(line) 0 1 2 3 1 2 3 2 3 @@ -399,6 +69,10 @@ def generate_adjlist(G, delimiter = ' '): 5 6 6 + See Also + -------- + write_adjlist, read_adjlist + """ directed=G.is_directed() seen=set() @@ -412,7 +86,6 @@ def generate_adjlist(G, delimiter = ' '): line += make_str(t) + delimiter else: line += make_str(t) + delimiter - line += '\n' if not directed: seen.add(s) yield line @@ -421,33 +94,42 @@ def generate_adjlist(G, delimiter = ' '): def write_adjlist(G, path, comments="#", delimiter=' ', encoding = 'utf-8'): """Write graph G in single-line adjacency-list format to path. - See read_adjlist for file format details. + + 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") - path can be a filehandle or a string with the name of the file. If a + 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) - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_adjlist(G, "test.adjlist.gz") + Notes + ----- + This format does not store graph, node, or edge data. - The file will use the utf-8 encoding by default. - It is possible to write files in other encodings by providing the - encoding argument to write_adjlist. - - >>> fh=open("test.adjlist", 'wb') - >>> nx.write_adjlist(G,fh, encoding='iso-8859-1') - - Does not handle edge data. - Use 'write_edgelist' or 'write_multiline_adjlist' + See Also + -------- + read_adjlist, generate_adjlist """ import sys import time @@ -459,18 +141,38 @@ def write_adjlist(G, path, comments="#", delimiter=' ', encoding = 'utf-8'): fh.write(header.encode(encoding)) for line in generate_adjlist(G, delimiter): + line+='\n' fh.write(line.encode(encoding)) def parse_adjlist(lines, comments = '#', delimiter = ' ', create_using = None, nodetype = None): - """Parse lines of an adjacency list representation of a graph. + """Parse lines of a graph adjacency list representation. + + Parameters + ---------- + lines : list or iterator of strings + Input data in adjlist format + + create_using: NetworkX graph container + Use given NetworkX graph for holding nodes or edges. + + nodetype : Python type, optional + Convert nodes to this type. + + comments : string, optional + Marker for comment lines + + delimiter : string, optional + Separator for node labels + + create_using: NetworkX graph container + Use given NetworkX graph for holding nodes or edges. - See read_adjlist for file format details. Returns ------- - G: NetworkX Graph + G: NetworkX graph The graph corresponding to the lines in adjacency list format. Examples @@ -480,11 +182,15 @@ def parse_adjlist(lines, comments = '#', delimiter = ' ', ... '3 5', ... '4', ... '5'] - >>> G = nx.parse_adjlist(iter(lines), nodetype = int) + >>> G = nx.parse_adjlist(lines, nodetype = int) >>> G.nodes() [1, 2, 3, 4, 5] >>> G.edges() [(1, 2), (1, 5), (2, 3), (2, 4), (3, 5)] + + See Also + -------- + read_adjlist """ if create_using is None: @@ -494,7 +200,7 @@ def parse_adjlist(lines, comments = '#', delimiter = ' ', G=create_using G.clear() except: - raise TypeError("Input graph is not a networkx graph type") + raise TypeError("Input graph is not a NetworkX graph type") for line in lines: p=line.find(comments) @@ -521,19 +227,44 @@ def parse_adjlist(lines, comments = '#', delimiter = ' ', G.add_edges_from([(u, v) for v in vlist]) return G -def read_adjlist(path, comments="#", delimiter=' ', - create_using=None, nodetype=None, - encoding = 'utf-8'): - """Read graph in single line adjacency list format from path. +def read_adjlist(path, comments="#", delimiter=' ', 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 container + Use given NetworkX graph for holding nodes or edges. + + nodetype : Python type, optional + Convert nodes to this type. + + comments : string, optional + Marker for comment lines + + delimiter : string, optional + Separator for node labels + + create_using: NetworkX graph container + Use given NetworkX graph for holding nodes or edges. + + + 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") - path can be a filehandle or a string with the name of the file. If a + 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') @@ -541,40 +272,33 @@ def read_adjlist(path, comments="#", delimiter=' ', Filenames ending in .gz or .bz2 will be compressed. - >>> nx.write_adjlist(G, "test.adjlist.gz") + >>> nx.write_adjlist(G,"test.adjlist.gz") >>> G=nx.read_adjlist("test.adjlist.gz") - nodetype is an optional function to convert node strings to nodetype + 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 + 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.) - create_using is an optional networkx graph type, the default is - Graph(), an undirected graph. + The optional create_using parameter is a NetworkX graph container. + The default is Graph(), an undirected graph. To read the data as + a directed graph use >>> G=nx.read_adjlist("test.adjlist", create_using=nx.DiGraph()) - Does not handle edge data: use 'read_edgelist' or 'read_multiline_adjlist' - - The comments character (default='#') at the beginning of a - line indicates a comment line. - - The entries are separated by delimiter (default=' '). - If whitespace is significant in node or edge labels you should use - some other delimiter such as a tab or other symbol. - - Sample format:: - - # source target - a b c - d e + Notes + ----- + This format does not store graph or node data. + See Also + -------- + write_adjlist """ fh=_get_fh(path, 'rb') lines = (line.decode(encoding) for line in fh) diff --git a/networkx/readwrite/multiline_adjlist.py b/networkx/readwrite/multiline_adjlist.py new file mode 100644 index 00000000..7c56facd --- /dev/null +++ b/networkx/readwrite/multiline_adjlist.py @@ -0,0 +1,389 @@ +# -*- coding: utf-8 -*- +""" +************************* +Multi-line Adjacency List +************************* +Read and write NetworkX graphs as multi-line adjacency lists. + +The multi-line adjacency list format is useful for graphs with +nodes that can be meaningfully represented as strings. With this format +simple edge data can be stored but node or graph data is not. + +Format +------ +The first label in a line is the source node label followed by the node degree +d. The next d lines are target node labels and optional edge data. +That pattern repeats for all nodes in the graph. + +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):: + + # example.multiline-adjlist + a 2 + b + c + d 1 + e +""" +__author__ = '\n'.join(['Aric Hagberg <hagberg@lanl.gov>', + 'Dan Schult <dschult@colgate.edu>', + 'Loïc Séguin-C. <loicseguin@gmail.com>']) +# Copyright (C) 2004-2010 by +# Aric Hagberg <hagberg@lanl.gov> +# Dan Schult <dschult@colgate.edu> +# Pieter Swart <swart@lanl.gov> +# All rights reserved. +# BSD license. + +__all__ = ['generate_multiline_adjlist', + 'write_multiline_adjlist', + 'parse_multiline_adjlist', + 'read_multiline_adjlist'] + +from networkx.utils import is_string_like, make_str, _get_fh +import networkx as nx + +def generate_multiline_adjlist(G, delimiter = ' '): + """Generate a single line of the graph G in multiline adjacency list format. + + Parameters + ---------- + G : NetworkX graph + + delimiter : string, optional + Separator for node labels + + Yields + ------ + lines : string + Lines of data in multiline adjlist format. + + Examples + -------- + >>> G = nx.lollipop_graph(4, 3) + >>> for line in nx.generate_multiline_adjlist(G): + ... print(line) + 0 3 + 1 {} + 2 {} + 3 {} + 1 2 + 2 {} + 3 {} + 2 1 + 3 {} + 3 1 + 4 {} + 4 1 + 5 {} + 5 1 + 6 {} + 6 0 + + See Also + -------- + write_multiline_adjlist, read_multiline_adjlist + """ + if G.is_directed(): + if G.is_multigraph(): + for s,nbrs in G.adjacency_iter(): + nbr_edges=[ (u,data) + for u,datadict in nbrs.items() + for key,data in datadict.items()] + deg=len(nbr_edges) + yield make_str(s)+delimiter+"%i"%(deg) + for u,d in nbr_edges: + if d is None: + yield make_str(u) + else: + yield make_str(u)+delimiter+make_str(d) + else: # directed single edges + for s,nbrs in G.adjacency_iter(): + deg=len(nbrs) + yield make_str(s)+delimiter+"%i"%(deg) + for u,d in nbrs.items(): + if d is None: + yield make_str(u) + else: + yield make_str(u)+delimiter+make_str(d) + else: # undirected + if G.is_multigraph(): + seen=set() # helper dict used to avoid duplicate edges + for s,nbrs in G.adjacency_iter(): + nbr_edges=[ (u,data) + for u,datadict in nbrs.items() + if u not in seen + for key,data in datadict.items()] + deg=len(nbr_edges) + yield make_str(s)+delimiter+"%i"%(deg) + for u,d in nbr_edges: + if d is None: + yield make_str(u) + else: + yield make_str(u)+delimiter+make_str(d) + seen.add(s) + else: # undirected single edges + seen=set() # helper dict used to avoid duplicate edges + for s,nbrs in G.adjacency_iter(): + nbr_edges=[ (u,d) for u,d in nbrs.items() if u not in seen] + deg=len(nbr_edges) + yield make_str(s)+delimiter+"%i"%(deg) + for u,d in nbr_edges: + if d is None: + yield make_str(u) + else: + yield make_str(u)+delimiter+make_str(d) + seen.add(s) + +def write_multiline_adjlist(G, path, delimiter=' ', + comments='#', encoding = 'utf-8'): + """ Write the graph G in multiline adjacency list format to path + + Parameters + ---------- + G : NetworkX graph + + 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_multiline_adjlist(G,"test.adjlist") + + The path can be a file handle or a string with the name of the file. If a + file handle is provided, it has to be opened in 'wb' mode. + + >>> fh=open("test.adjlist",'wb') + >>> nx.write_multiline_adjlist(G,fh) + + Filenames ending in .gz or .bz2 will be compressed. + + >>> nx.write_multiline_adjlist(G,"test.adjlist.gz") + + See Also + -------- + read_multiline_adjlist + """ + import sys + import time + + fh=_get_fh(path,mode='wb') + pargs=comments+" ".join(sys.argv) + header = ("%s\n" % (pargs) + + comments + " GMT %s\n" % (time.asctime(time.gmtime())) + + comments + " %s\n" % (G.name)) + fh.write(header.encode(encoding)) + + for multiline in generate_multiline_adjlist(G, delimiter): + multiline+='\n' + fh.write(multiline.encode(encoding)) + +def parse_multiline_adjlist(lines, comments = '#', delimiter = ' ', + create_using = None, nodetype = None, + edgetype = None): + """Parse lines of a multiline adjacency list representation of a graph. + + Parameters + ---------- + lines : list or iterator of strings + Input data in multiline adjlist format + + create_using: NetworkX graph container + Use given NetworkX graph for holding nodes or edges. + + nodetype : Python type, optional + Convert nodes to this type. + + comments : string, optional + Marker for comment lines + + delimiter : string, optional + Separator for node labels + + create_using: NetworkX graph container + Use given NetworkX graph for holding nodes or edges. + + + Returns + ------- + G: NetworkX graph + The graph corresponding to the lines in multiline adjacency list format. + + Examples + -------- + >>> lines = ['1 2', + ... "2 {'weight':3, 'name': 'Frodo'}", + ... "3 {}", + ... "2 1", + ... "5 {'weight':6, 'name': 'Saruman'}"] + >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype = int) + >>> G.nodes() + [1, 2, 3, 5] + >>> G.edges(data = True) + [(1, 2, {'name': 'Frodo', 'weight': 3}), (1, 3, {}), (2, 5, {'name': 'Saruman', 'weight': 6})] + + """ + from ast import literal_eval + if create_using is None: + G=nx.Graph() + else: + try: + G=create_using + G.clear() + except: + raise TypeError("Input graph is not a networkx graph type") + + for line in lines: + p=line.find(comments) + if p>=0: + line = line[:p] + if not line: continue + try: + (u,deg)=line.strip().split(delimiter) + deg=int(deg) + except: + raise TypeError("Failed to read node and degree on line (%s)"%line) + if nodetype is not None: + try: + u=nodetype(u) + except: + raise TypeError("Failed to convert node (%s) to type %s"\ + %(u,nodetype)) + G.add_node(u) + for i in range(deg): + while True: + try: + line = next(lines) + except StopIteration: + msg = "Failed to find neighbor for node (%s)" % (u,) + raise TypeError(msg) + p=line.find(comments) + if p>=0: + line = line[:p] + if line: break + vlist=line.strip().split(delimiter) + numb=len(vlist) + if numb<1: + continue # isolated node + v=vlist.pop(0) + data=''.join(vlist) + if nodetype is not None: + try: + v=nodetype(v) + except: + raise TypeError( + "Failed to convert node (%s) to type %s"\ + %(v,nodetype)) + if edgetype is not None: + try: + edgedata={'weight':edgetype(data)} + except: + raise TypeError( + "Failed to convert edge data (%s) to type %s"\ + %(data, edgetype)) + else: + try: # try to evaluate + edgedata=literal_eval(data) + except: + edgedata={} + G.add_edge(u,v,attr_dict=edgedata) + + return G + + +def read_multiline_adjlist(path, comments="#", delimiter=' ', + create_using=None, + nodetype=None, edgetype=None, + encoding = 'utf-8'): + """Read graph in multi-line 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 container + Use given NetworkX graph for holding nodes or edges. + + nodetype : Python type, optional + Convert nodes to this type. + + edgetype : Python type, optional + Convert edge data to this type. + + comments : string, optional + Marker for comment lines + + delimiter : string, optional + Separator for node labels + + create_using: NetworkX graph container + Use given NetworkX graph for holding nodes or edges. + + + Returns + ------- + G: NetworkX graph + + Examples + -------- + >>> G=nx.path_graph(4) + >>> nx.write_multiline_adjlist(G,"test.adjlist") + >>> G=nx.read_multiline_adjlist("test.adjlist") + + The path can be a file or a string with the name of the file. If a + file s provided, it has to be opened in 'rb' mode. + + >>> fh=open("test.adjlist", 'rb') + >>> G=nx.read_multiline_adjlist(fh) + + Filenames ending in .gz or .bz2 will be compressed. + + >>> nx.write_multiline_adjlist(G,"test.adjlist.gz") + >>> G=nx.read_multiline_adjlist("test.adjlist.gz") + + The optional nodetype is a function to convert node strings to nodetype. + + For example + + >>> G=nx.read_multiline_adjlist("test.adjlist", nodetype=int) + + will attempt to convert all nodes to integer type. + + The optional edgetype is a function to convert edge data strings to + edgetype. + + >>> G=nx.read_multiline_adjlist("test.adjlist") + + The optional create_using parameter is a NetworkX graph container. + The default is Graph(), an undirected graph. To read the data as + a directed graph use + + >>> G=nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph()) + + Notes + ----- + This format does not store graph, node, or edge data. + + See Also + -------- + write_multiline_adjlist + """ + inp=_get_fh(path, 'rb') + lines = (line.decode(encoding) for line in inp) + return parse_multiline_adjlist(lines, + comments = comments, + delimiter = delimiter, + create_using = create_using, + nodetype = nodetype, + edgetype = edgetype) + + |