using for loop to install conda package
This commit is contained in:
18
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__init__.py
vendored
Normal file
18
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__init__.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
A package for reading and writing graphs in various formats.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from networkx.readwrite.adjlist import *
|
||||
from networkx.readwrite.multiline_adjlist import *
|
||||
from networkx.readwrite.edgelist import *
|
||||
from networkx.readwrite.pajek import *
|
||||
from networkx.readwrite.leda import *
|
||||
from networkx.readwrite.sparse6 import *
|
||||
from networkx.readwrite.graph6 import *
|
||||
from networkx.readwrite.gml import *
|
||||
from networkx.readwrite.graphml import *
|
||||
from networkx.readwrite.gexf import *
|
||||
from networkx.readwrite.json_graph import *
|
||||
from networkx.readwrite.text import *
|
||||
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/adjlist.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/adjlist.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/edgelist.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/edgelist.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/gexf.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/gexf.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/gml.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/gml.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/graph6.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/graph6.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/graphml.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/graphml.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/leda.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/leda.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/multiline_adjlist.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/multiline_adjlist.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/p2g.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/p2g.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/pajek.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/pajek.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/sparse6.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/sparse6.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/text.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/__pycache__/text.cpython-311.pyc
vendored
Normal file
Binary file not shown.
308
.CondaPkg/env/Lib/site-packages/networkx/readwrite/adjlist.py
vendored
Normal file
308
.CondaPkg/env/Lib/site-packages/networkx/readwrite/adjlist.py
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
"""
|
||||
**************
|
||||
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)]
|
||||
|
||||
|
||||
@open_file(1, mode="wb")
|
||||
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
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
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,
|
||||
)
|
||||
486
.CondaPkg/env/Lib/site-packages/networkx/readwrite/edgelist.py
vendored
Normal file
486
.CondaPkg/env/Lib/site-packages/networkx/readwrite/edgelist.py
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
"""
|
||||
**********
|
||||
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 # missing data for this edge, should warn?
|
||||
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))
|
||||
|
||||
|
||||
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
|
||||
# split line, should have 2 or more
|
||||
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:
|
||||
# no data or data type specified
|
||||
edgedata = {}
|
||||
elif data is True:
|
||||
# no edge types specified
|
||||
try: # try to evaluate as dictionary
|
||||
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:
|
||||
# convert edge data to dictionary with specified keys and type
|
||||
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")
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
)
|
||||
1065
.CondaPkg/env/Lib/site-packages/networkx/readwrite/gexf.py
vendored
Normal file
1065
.CondaPkg/env/Lib/site-packages/networkx/readwrite/gexf.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
858
.CondaPkg/env/Lib/site-packages/networkx/readwrite/gml.py
vendored
Normal file
858
.CondaPkg/env/Lib/site-packages/networkx/readwrite/gml.py
vendored
Normal file
@@ -0,0 +1,858 @@
|
||||
"""
|
||||
Read graphs in GML format.
|
||||
|
||||
"GML, the Graph Modelling Language, is our proposal for a portable
|
||||
file format for graphs. GML's key features are portability, simple
|
||||
syntax, extensibility and flexibility. A GML file consists of a
|
||||
hierarchical key-value lists. Graphs can be annotated with arbitrary
|
||||
data structures. The idea for a common file format was born at the
|
||||
GD'95; this proposal is the outcome of many discussions. GML is the
|
||||
standard file format in the Graphlet graph editor system. It has been
|
||||
overtaken and adapted by several other systems for drawing graphs."
|
||||
|
||||
GML files are stored using a 7-bit ASCII encoding with any extended
|
||||
ASCII characters (iso8859-1) appearing as HTML character entities.
|
||||
You will need to give some thought into how the exported data should
|
||||
interact with different languages and even different Python versions.
|
||||
Re-importing from gml is also a concern.
|
||||
|
||||
Without specifying a `stringizer`/`destringizer`, the code is capable of
|
||||
writing `int`/`float`/`str`/`dict`/`list` data as required by the GML
|
||||
specification. For writing other data types, and for reading data other
|
||||
than `str` you need to explicitly supply a `stringizer`/`destringizer`.
|
||||
|
||||
For additional documentation on the GML file format, please see the
|
||||
`GML website <https://web.archive.org/web/20190207140002/http://www.fim.uni-passau.de/index.php?id=17297&L=1>`_.
|
||||
|
||||
Several example graphs in GML format may be found on Mark Newman's
|
||||
`Network data page <http://www-personal.umich.edu/~mejn/netdata/>`_.
|
||||
"""
|
||||
import html.entities as htmlentitydefs
|
||||
import re
|
||||
import warnings
|
||||
from ast import literal_eval
|
||||
from collections import defaultdict
|
||||
from enum import Enum
|
||||
from io import StringIO
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
import networkx as nx
|
||||
from networkx.exception import NetworkXError
|
||||
from networkx.utils import open_file
|
||||
|
||||
__all__ = ["read_gml", "parse_gml", "generate_gml", "write_gml"]
|
||||
|
||||
|
||||
def escape(text):
|
||||
"""Use XML character references to escape characters.
|
||||
|
||||
Use XML character references for unprintable or non-ASCII
|
||||
characters, double quotes and ampersands in a string
|
||||
"""
|
||||
|
||||
def fixup(m):
|
||||
ch = m.group(0)
|
||||
return "&#" + str(ord(ch)) + ";"
|
||||
|
||||
text = re.sub('[^ -~]|[&"]', fixup, text)
|
||||
return text if isinstance(text, str) else str(text)
|
||||
|
||||
|
||||
def unescape(text):
|
||||
"""Replace XML character references with the referenced characters"""
|
||||
|
||||
def fixup(m):
|
||||
text = m.group(0)
|
||||
if text[1] == "#":
|
||||
# Character reference
|
||||
if text[2] == "x":
|
||||
code = int(text[3:-1], 16)
|
||||
else:
|
||||
code = int(text[2:-1])
|
||||
else:
|
||||
# Named entity
|
||||
try:
|
||||
code = htmlentitydefs.name2codepoint[text[1:-1]]
|
||||
except KeyError:
|
||||
return text # leave unchanged
|
||||
try:
|
||||
return chr(code)
|
||||
except (ValueError, OverflowError):
|
||||
return text # leave unchanged
|
||||
|
||||
return re.sub("&(?:[0-9A-Za-z]+|#(?:[0-9]+|x[0-9A-Fa-f]+));", fixup, text)
|
||||
|
||||
|
||||
def literal_destringizer(rep):
|
||||
"""Convert a Python literal to the value it represents.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rep : string
|
||||
A Python literal.
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : object
|
||||
The value of the Python literal.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `rep` is not a Python literal.
|
||||
"""
|
||||
msg = "literal_destringizer is deprecated and will be removed in 3.0."
|
||||
warnings.warn(msg, DeprecationWarning)
|
||||
if isinstance(rep, str):
|
||||
orig_rep = rep
|
||||
try:
|
||||
return literal_eval(rep)
|
||||
except SyntaxError as err:
|
||||
raise ValueError(f"{orig_rep!r} is not a valid Python literal") from err
|
||||
else:
|
||||
raise ValueError(f"{rep!r} is not a string")
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
def read_gml(path, label="label", destringizer=None):
|
||||
"""Read graph in GML format from `path`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : filename or filehandle
|
||||
The filename or filehandle to read from.
|
||||
|
||||
label : string, optional
|
||||
If not None, the parsed nodes will be renamed according to node
|
||||
attributes indicated by `label`. Default value: 'label'.
|
||||
|
||||
destringizer : callable, optional
|
||||
A `destringizer` that recovers values stored as strings in GML. If it
|
||||
cannot convert a string to a value, a `ValueError` is raised. Default
|
||||
value : None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
The parsed graph.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the input cannot be parsed.
|
||||
|
||||
See Also
|
||||
--------
|
||||
write_gml, parse_gml
|
||||
literal_destringizer
|
||||
|
||||
Notes
|
||||
-----
|
||||
GML files are stored using a 7-bit ASCII encoding with any extended
|
||||
ASCII characters (iso8859-1) appearing as HTML character entities.
|
||||
Without specifying a `stringizer`/`destringizer`, the code is capable of
|
||||
writing `int`/`float`/`str`/`dict`/`list` data as required by the GML
|
||||
specification. For writing other data types, and for reading data other
|
||||
than `str` you need to explicitly supply a `stringizer`/`destringizer`.
|
||||
|
||||
For additional documentation on the GML file format, please see the
|
||||
`GML url <https://web.archive.org/web/20190207140002/http://www.fim.uni-passau.de/index.php?id=17297&L=1>`_.
|
||||
|
||||
See the module docstring :mod:`networkx.readwrite.gml` for more details.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(4)
|
||||
>>> nx.write_gml(G, "test.gml")
|
||||
|
||||
GML values are interpreted as strings by default:
|
||||
|
||||
>>> H = nx.read_gml("test.gml")
|
||||
>>> H.nodes
|
||||
NodeView(('0', '1', '2', '3'))
|
||||
|
||||
When a `destringizer` is provided, GML values are converted to the provided type.
|
||||
For example, integer nodes can be recovered as shown below:
|
||||
|
||||
>>> J = nx.read_gml("test.gml", destringizer=int)
|
||||
>>> J.nodes
|
||||
NodeView((0, 1, 2, 3))
|
||||
|
||||
"""
|
||||
|
||||
def filter_lines(lines):
|
||||
for line in lines:
|
||||
try:
|
||||
line = line.decode("ascii")
|
||||
except UnicodeDecodeError as err:
|
||||
raise NetworkXError("input is not ASCII-encoded") from err
|
||||
if not isinstance(line, str):
|
||||
lines = str(lines)
|
||||
if line and line[-1] == "\n":
|
||||
line = line[:-1]
|
||||
yield line
|
||||
|
||||
G = parse_gml_lines(filter_lines(path), label, destringizer)
|
||||
return G
|
||||
|
||||
|
||||
def parse_gml(lines, label="label", destringizer=None):
|
||||
"""Parse GML graph from a string or iterable.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lines : string or iterable of strings
|
||||
Data in GML format.
|
||||
|
||||
label : string, optional
|
||||
If not None, the parsed nodes will be renamed according to node
|
||||
attributes indicated by `label`. Default value: 'label'.
|
||||
|
||||
destringizer : callable, optional
|
||||
A `destringizer` that recovers values stored as strings in GML. If it
|
||||
cannot convert a string to a value, a `ValueError` is raised. Default
|
||||
value : None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
The parsed graph.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the input cannot be parsed.
|
||||
|
||||
See Also
|
||||
--------
|
||||
write_gml, read_gml
|
||||
|
||||
Notes
|
||||
-----
|
||||
This stores nested GML attributes as dictionaries in the NetworkX graph,
|
||||
node, and edge attribute structures.
|
||||
|
||||
GML files are stored using a 7-bit ASCII encoding with any extended
|
||||
ASCII characters (iso8859-1) appearing as HTML character entities.
|
||||
Without specifying a `stringizer`/`destringizer`, the code is capable of
|
||||
writing `int`/`float`/`str`/`dict`/`list` data as required by the GML
|
||||
specification. For writing other data types, and for reading data other
|
||||
than `str` you need to explicitly supply a `stringizer`/`destringizer`.
|
||||
|
||||
For additional documentation on the GML file format, please see the
|
||||
`GML url <https://web.archive.org/web/20190207140002/http://www.fim.uni-passau.de/index.php?id=17297&L=1>`_.
|
||||
|
||||
See the module docstring :mod:`networkx.readwrite.gml` for more details.
|
||||
"""
|
||||
|
||||
def decode_line(line):
|
||||
if isinstance(line, bytes):
|
||||
try:
|
||||
line.decode("ascii")
|
||||
except UnicodeDecodeError as err:
|
||||
raise NetworkXError("input is not ASCII-encoded") from err
|
||||
if not isinstance(line, str):
|
||||
line = str(line)
|
||||
return line
|
||||
|
||||
def filter_lines(lines):
|
||||
if isinstance(lines, str):
|
||||
lines = decode_line(lines)
|
||||
lines = lines.splitlines()
|
||||
yield from lines
|
||||
else:
|
||||
for line in lines:
|
||||
line = decode_line(line)
|
||||
if line and line[-1] == "\n":
|
||||
line = line[:-1]
|
||||
if line.find("\n") != -1:
|
||||
raise NetworkXError("input line contains newline")
|
||||
yield line
|
||||
|
||||
G = parse_gml_lines(filter_lines(lines), label, destringizer)
|
||||
return G
|
||||
|
||||
|
||||
class Pattern(Enum):
|
||||
"""encodes the index of each token-matching pattern in `tokenize`."""
|
||||
|
||||
KEYS = 0
|
||||
REALS = 1
|
||||
INTS = 2
|
||||
STRINGS = 3
|
||||
DICT_START = 4
|
||||
DICT_END = 5
|
||||
COMMENT_WHITESPACE = 6
|
||||
|
||||
|
||||
class Token(NamedTuple):
|
||||
category: Pattern
|
||||
value: Any
|
||||
line: int
|
||||
position: int
|
||||
|
||||
|
||||
LIST_START_VALUE = "_networkx_list_start"
|
||||
|
||||
|
||||
def parse_gml_lines(lines, label, destringizer):
|
||||
"""Parse GML `lines` into a graph."""
|
||||
|
||||
def tokenize():
|
||||
patterns = [
|
||||
r"[A-Za-z][0-9A-Za-z_]*\b", # keys
|
||||
# reals
|
||||
r"[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.[0-9]*|INF)(?:[Ee][+-]?[0-9]+)?",
|
||||
r"[+-]?[0-9]+", # ints
|
||||
r'".*?"', # strings
|
||||
r"\[", # dict start
|
||||
r"\]", # dict end
|
||||
r"#.*$|\s+", # comments and whitespaces
|
||||
]
|
||||
tokens = re.compile("|".join(f"({pattern})" for pattern in patterns))
|
||||
lineno = 0
|
||||
for line in lines:
|
||||
length = len(line)
|
||||
pos = 0
|
||||
while pos < length:
|
||||
match = tokens.match(line, pos)
|
||||
if match is None:
|
||||
m = f"cannot tokenize {line[pos:]} at ({lineno + 1}, {pos + 1})"
|
||||
raise NetworkXError(m)
|
||||
for i in range(len(patterns)):
|
||||
group = match.group(i + 1)
|
||||
if group is not None:
|
||||
if i == 0: # keys
|
||||
value = group.rstrip()
|
||||
elif i == 1: # reals
|
||||
value = float(group)
|
||||
elif i == 2: # ints
|
||||
value = int(group)
|
||||
else:
|
||||
value = group
|
||||
if i != 6: # comments and whitespaces
|
||||
yield Token(Pattern(i), value, lineno + 1, pos + 1)
|
||||
pos += len(group)
|
||||
break
|
||||
lineno += 1
|
||||
yield Token(None, None, lineno + 1, 1) # EOF
|
||||
|
||||
def unexpected(curr_token, expected):
|
||||
category, value, lineno, pos = curr_token
|
||||
value = repr(value) if value is not None else "EOF"
|
||||
raise NetworkXError(f"expected {expected}, found {value} at ({lineno}, {pos})")
|
||||
|
||||
def consume(curr_token, category, expected):
|
||||
if curr_token.category == category:
|
||||
return next(tokens)
|
||||
unexpected(curr_token, expected)
|
||||
|
||||
def parse_kv(curr_token):
|
||||
dct = defaultdict(list)
|
||||
while curr_token.category == Pattern.KEYS:
|
||||
key = curr_token.value
|
||||
curr_token = next(tokens)
|
||||
category = curr_token.category
|
||||
if category == Pattern.REALS or category == Pattern.INTS:
|
||||
value = curr_token.value
|
||||
curr_token = next(tokens)
|
||||
elif category == Pattern.STRINGS:
|
||||
value = unescape(curr_token.value[1:-1])
|
||||
if destringizer:
|
||||
try:
|
||||
value = destringizer(value)
|
||||
except ValueError:
|
||||
pass
|
||||
# Special handling for empty lists and tuples
|
||||
if value == "()":
|
||||
value = ()
|
||||
if value == "[]":
|
||||
value = []
|
||||
curr_token = next(tokens)
|
||||
elif category == Pattern.DICT_START:
|
||||
curr_token, value = parse_dict(curr_token)
|
||||
else:
|
||||
# Allow for string convertible id and label values
|
||||
if key in ("id", "label", "source", "target"):
|
||||
try:
|
||||
# String convert the token value
|
||||
value = unescape(str(curr_token.value))
|
||||
if destringizer:
|
||||
try:
|
||||
value = destringizer(value)
|
||||
except ValueError:
|
||||
pass
|
||||
curr_token = next(tokens)
|
||||
except Exception:
|
||||
msg = (
|
||||
"an int, float, string, '[' or string"
|
||||
+ " convertible ASCII value for node id or label"
|
||||
)
|
||||
unexpected(curr_token, msg)
|
||||
# Special handling for nan and infinity. Since the gml language
|
||||
# defines unquoted strings as keys, the numeric and string branches
|
||||
# are skipped and we end up in this special branch, so we need to
|
||||
# convert the current token value to a float for NAN and plain INF.
|
||||
# +/-INF are handled in the pattern for 'reals' in tokenize(). This
|
||||
# allows labels and values to be nan or infinity, but not keys.
|
||||
elif curr_token.value in {"NAN", "INF"}:
|
||||
value = float(curr_token.value)
|
||||
curr_token = next(tokens)
|
||||
else: # Otherwise error out
|
||||
unexpected(curr_token, "an int, float, string or '['")
|
||||
dct[key].append(value)
|
||||
|
||||
def clean_dict_value(value):
|
||||
if not isinstance(value, list):
|
||||
return value
|
||||
if len(value) == 1:
|
||||
return value[0]
|
||||
if value[0] == LIST_START_VALUE:
|
||||
return value[1:]
|
||||
return value
|
||||
|
||||
dct = {key: clean_dict_value(value) for key, value in dct.items()}
|
||||
return curr_token, dct
|
||||
|
||||
def parse_dict(curr_token):
|
||||
# dict start
|
||||
curr_token = consume(curr_token, Pattern.DICT_START, "'['")
|
||||
# dict contents
|
||||
curr_token, dct = parse_kv(curr_token)
|
||||
# dict end
|
||||
curr_token = consume(curr_token, Pattern.DICT_END, "']'")
|
||||
return curr_token, dct
|
||||
|
||||
def parse_graph():
|
||||
curr_token, dct = parse_kv(next(tokens))
|
||||
if curr_token.category is not None: # EOF
|
||||
unexpected(curr_token, "EOF")
|
||||
if "graph" not in dct:
|
||||
raise NetworkXError("input contains no graph")
|
||||
graph = dct["graph"]
|
||||
if isinstance(graph, list):
|
||||
raise NetworkXError("input contains more than one graph")
|
||||
return graph
|
||||
|
||||
tokens = tokenize()
|
||||
graph = parse_graph()
|
||||
|
||||
directed = graph.pop("directed", False)
|
||||
multigraph = graph.pop("multigraph", False)
|
||||
if not multigraph:
|
||||
G = nx.DiGraph() if directed else nx.Graph()
|
||||
else:
|
||||
G = nx.MultiDiGraph() if directed else nx.MultiGraph()
|
||||
graph_attr = {k: v for k, v in graph.items() if k not in ("node", "edge")}
|
||||
G.graph.update(graph_attr)
|
||||
|
||||
def pop_attr(dct, category, attr, i):
|
||||
try:
|
||||
return dct.pop(attr)
|
||||
except KeyError as err:
|
||||
raise NetworkXError(f"{category} #{i} has no {attr!r} attribute") from err
|
||||
|
||||
nodes = graph.get("node", [])
|
||||
mapping = {}
|
||||
node_labels = set()
|
||||
for i, node in enumerate(nodes if isinstance(nodes, list) else [nodes]):
|
||||
id = pop_attr(node, "node", "id", i)
|
||||
if id in G:
|
||||
raise NetworkXError(f"node id {id!r} is duplicated")
|
||||
if label is not None and label != "id":
|
||||
node_label = pop_attr(node, "node", label, i)
|
||||
if node_label in node_labels:
|
||||
raise NetworkXError(f"node label {node_label!r} is duplicated")
|
||||
node_labels.add(node_label)
|
||||
mapping[id] = node_label
|
||||
G.add_node(id, **node)
|
||||
|
||||
edges = graph.get("edge", [])
|
||||
for i, edge in enumerate(edges if isinstance(edges, list) else [edges]):
|
||||
source = pop_attr(edge, "edge", "source", i)
|
||||
target = pop_attr(edge, "edge", "target", i)
|
||||
if source not in G:
|
||||
raise NetworkXError(f"edge #{i} has undefined source {source!r}")
|
||||
if target not in G:
|
||||
raise NetworkXError(f"edge #{i} has undefined target {target!r}")
|
||||
if not multigraph:
|
||||
if not G.has_edge(source, target):
|
||||
G.add_edge(source, target, **edge)
|
||||
else:
|
||||
arrow = "->" if directed else "--"
|
||||
msg = f"edge #{i} ({source!r}{arrow}{target!r}) is duplicated"
|
||||
raise nx.NetworkXError(msg)
|
||||
else:
|
||||
key = edge.pop("key", None)
|
||||
if key is not None and G.has_edge(source, target, key):
|
||||
arrow = "->" if directed else "--"
|
||||
msg = f"edge #{i} ({source!r}{arrow}{target!r}, {key!r})"
|
||||
msg2 = 'Hint: If multigraph add "multigraph 1" to file header.'
|
||||
raise nx.NetworkXError(msg + " is duplicated\n" + msg2)
|
||||
G.add_edge(source, target, key, **edge)
|
||||
|
||||
if label is not None and label != "id":
|
||||
G = nx.relabel_nodes(G, mapping)
|
||||
return G
|
||||
|
||||
|
||||
def literal_stringizer(value):
|
||||
"""Convert a `value` to a Python literal in GML representation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
value : object
|
||||
The `value` to be converted to GML representation.
|
||||
|
||||
Returns
|
||||
-------
|
||||
rep : string
|
||||
A double-quoted Python literal representing value. Unprintable
|
||||
characters are replaced by XML character references.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `value` cannot be converted to GML.
|
||||
|
||||
Notes
|
||||
-----
|
||||
`literal_stringizer` is largely the same as `repr` in terms of
|
||||
functionality but attempts prefix `unicode` and `bytes` literals with
|
||||
`u` and `b` to provide better interoperability of data generated by
|
||||
Python 2 and Python 3.
|
||||
|
||||
The original value can be recovered using the
|
||||
:func:`networkx.readwrite.gml.literal_destringizer` function.
|
||||
"""
|
||||
msg = "literal_stringizer is deprecated and will be removed in 3.0."
|
||||
warnings.warn(msg, DeprecationWarning)
|
||||
|
||||
def stringize(value):
|
||||
if isinstance(value, (int, bool)) or value is None:
|
||||
if value is True: # GML uses 1/0 for boolean values.
|
||||
buf.write(str(1))
|
||||
elif value is False:
|
||||
buf.write(str(0))
|
||||
else:
|
||||
buf.write(str(value))
|
||||
elif isinstance(value, str):
|
||||
text = repr(value)
|
||||
if text[0] != "u":
|
||||
try:
|
||||
value.encode("latin1")
|
||||
except UnicodeEncodeError:
|
||||
text = "u" + text
|
||||
buf.write(text)
|
||||
elif isinstance(value, (float, complex, str, bytes)):
|
||||
buf.write(repr(value))
|
||||
elif isinstance(value, list):
|
||||
buf.write("[")
|
||||
first = True
|
||||
for item in value:
|
||||
if not first:
|
||||
buf.write(",")
|
||||
else:
|
||||
first = False
|
||||
stringize(item)
|
||||
buf.write("]")
|
||||
elif isinstance(value, tuple):
|
||||
if len(value) > 1:
|
||||
buf.write("(")
|
||||
first = True
|
||||
for item in value:
|
||||
if not first:
|
||||
buf.write(",")
|
||||
else:
|
||||
first = False
|
||||
stringize(item)
|
||||
buf.write(")")
|
||||
elif value:
|
||||
buf.write("(")
|
||||
stringize(value[0])
|
||||
buf.write(",)")
|
||||
else:
|
||||
buf.write("()")
|
||||
elif isinstance(value, dict):
|
||||
buf.write("{")
|
||||
first = True
|
||||
for key, value in value.items():
|
||||
if not first:
|
||||
buf.write(",")
|
||||
else:
|
||||
first = False
|
||||
stringize(key)
|
||||
buf.write(":")
|
||||
stringize(value)
|
||||
buf.write("}")
|
||||
elif isinstance(value, set):
|
||||
buf.write("{")
|
||||
first = True
|
||||
for item in value:
|
||||
if not first:
|
||||
buf.write(",")
|
||||
else:
|
||||
first = False
|
||||
stringize(item)
|
||||
buf.write("}")
|
||||
else:
|
||||
msg = f"{value!r} cannot be converted into a Python literal"
|
||||
raise ValueError(msg)
|
||||
|
||||
buf = StringIO()
|
||||
stringize(value)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def generate_gml(G, stringizer=None):
|
||||
r"""Generate a single entry of the graph `G` in GML format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
The graph to be converted to GML.
|
||||
|
||||
stringizer : callable, optional
|
||||
A `stringizer` which converts non-int/non-float/non-dict values into
|
||||
strings. If it cannot convert a value into a string, it should raise a
|
||||
`ValueError` to indicate that. Default value: None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
lines: generator of strings
|
||||
Lines of GML data. Newlines are not appended.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If `stringizer` cannot convert a value into a string, or the value to
|
||||
convert is not a string while `stringizer` is None.
|
||||
|
||||
See Also
|
||||
--------
|
||||
literal_stringizer
|
||||
|
||||
Notes
|
||||
-----
|
||||
Graph attributes named 'directed', 'multigraph', 'node' or
|
||||
'edge', node attributes named 'id' or 'label', edge attributes
|
||||
named 'source' or 'target' (or 'key' if `G` is a multigraph)
|
||||
are ignored because these attribute names are used to encode the graph
|
||||
structure.
|
||||
|
||||
GML files are stored using a 7-bit ASCII encoding with any extended
|
||||
ASCII characters (iso8859-1) appearing as HTML character entities.
|
||||
Without specifying a `stringizer`/`destringizer`, the code is capable of
|
||||
writing `int`/`float`/`str`/`dict`/`list` data as required by the GML
|
||||
specification. For writing other data types, and for reading data other
|
||||
than `str` you need to explicitly supply a `stringizer`/`destringizer`.
|
||||
|
||||
For additional documentation on the GML file format, please see the
|
||||
`GML url <https://web.archive.org/web/20190207140002/http://www.fim.uni-passau.de/index.php?id=17297&L=1>`_.
|
||||
|
||||
See the module docstring :mod:`networkx.readwrite.gml` for more details.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.Graph()
|
||||
>>> G.add_node("1")
|
||||
>>> print("\n".join(nx.generate_gml(G)))
|
||||
graph [
|
||||
node [
|
||||
id 0
|
||||
label "1"
|
||||
]
|
||||
]
|
||||
>>> G = nx.MultiGraph([("a", "b"), ("a", "b")])
|
||||
>>> print("\n".join(nx.generate_gml(G)))
|
||||
graph [
|
||||
multigraph 1
|
||||
node [
|
||||
id 0
|
||||
label "a"
|
||||
]
|
||||
node [
|
||||
id 1
|
||||
label "b"
|
||||
]
|
||||
edge [
|
||||
source 0
|
||||
target 1
|
||||
key 0
|
||||
]
|
||||
edge [
|
||||
source 0
|
||||
target 1
|
||||
key 1
|
||||
]
|
||||
]
|
||||
"""
|
||||
valid_keys = re.compile("^[A-Za-z][0-9A-Za-z_]*$")
|
||||
|
||||
def stringize(key, value, ignored_keys, indent, in_list=False):
|
||||
if not isinstance(key, str):
|
||||
raise NetworkXError(f"{key!r} is not a string")
|
||||
if not valid_keys.match(key):
|
||||
raise NetworkXError(f"{key!r} is not a valid key")
|
||||
if not isinstance(key, str):
|
||||
key = str(key)
|
||||
if key not in ignored_keys:
|
||||
if isinstance(value, (int, bool)):
|
||||
if key == "label":
|
||||
yield indent + key + ' "' + str(value) + '"'
|
||||
elif value is True:
|
||||
# python bool is an instance of int
|
||||
yield indent + key + " 1"
|
||||
elif value is False:
|
||||
yield indent + key + " 0"
|
||||
# GML only supports signed 32-bit integers
|
||||
elif value < -(2**31) or value >= 2**31:
|
||||
yield indent + key + ' "' + str(value) + '"'
|
||||
else:
|
||||
yield indent + key + " " + str(value)
|
||||
elif isinstance(value, float):
|
||||
text = repr(value).upper()
|
||||
# GML matches INF to keys, so prepend + to INF. Use repr(float(*))
|
||||
# instead of string literal to future proof against changes to repr.
|
||||
if text == repr(float("inf")).upper():
|
||||
text = "+" + text
|
||||
else:
|
||||
# GML requires that a real literal contain a decimal point, but
|
||||
# repr may not output a decimal point when the mantissa is
|
||||
# integral and hence needs fixing.
|
||||
epos = text.rfind("E")
|
||||
if epos != -1 and text.find(".", 0, epos) == -1:
|
||||
text = text[:epos] + "." + text[epos:]
|
||||
if key == "label":
|
||||
yield indent + key + ' "' + text + '"'
|
||||
else:
|
||||
yield indent + key + " " + text
|
||||
elif isinstance(value, dict):
|
||||
yield indent + key + " ["
|
||||
next_indent = indent + " "
|
||||
for key, value in value.items():
|
||||
yield from stringize(key, value, (), next_indent)
|
||||
yield indent + "]"
|
||||
elif isinstance(value, (list, tuple)) and key != "label" and not in_list:
|
||||
if len(value) == 0:
|
||||
yield indent + key + " " + f'"{value!r}"'
|
||||
if len(value) == 1:
|
||||
yield indent + key + " " + f'"{LIST_START_VALUE}"'
|
||||
for val in value:
|
||||
yield from stringize(key, val, (), indent, True)
|
||||
else:
|
||||
if stringizer:
|
||||
try:
|
||||
value = stringizer(value)
|
||||
except ValueError as err:
|
||||
raise NetworkXError(
|
||||
f"{value!r} cannot be converted into a string"
|
||||
) from err
|
||||
if not isinstance(value, str):
|
||||
raise NetworkXError(f"{value!r} is not a string")
|
||||
yield indent + key + ' "' + escape(value) + '"'
|
||||
|
||||
multigraph = G.is_multigraph()
|
||||
yield "graph ["
|
||||
|
||||
# Output graph attributes
|
||||
if G.is_directed():
|
||||
yield " directed 1"
|
||||
if multigraph:
|
||||
yield " multigraph 1"
|
||||
ignored_keys = {"directed", "multigraph", "node", "edge"}
|
||||
for attr, value in G.graph.items():
|
||||
yield from stringize(attr, value, ignored_keys, " ")
|
||||
|
||||
# Output node data
|
||||
node_id = dict(zip(G, range(len(G))))
|
||||
ignored_keys = {"id", "label"}
|
||||
for node, attrs in G.nodes.items():
|
||||
yield " node ["
|
||||
yield " id " + str(node_id[node])
|
||||
yield from stringize("label", node, (), " ")
|
||||
for attr, value in attrs.items():
|
||||
yield from stringize(attr, value, ignored_keys, " ")
|
||||
yield " ]"
|
||||
|
||||
# Output edge data
|
||||
ignored_keys = {"source", "target"}
|
||||
kwargs = {"data": True}
|
||||
if multigraph:
|
||||
ignored_keys.add("key")
|
||||
kwargs["keys"] = True
|
||||
for e in G.edges(**kwargs):
|
||||
yield " edge ["
|
||||
yield " source " + str(node_id[e[0]])
|
||||
yield " target " + str(node_id[e[1]])
|
||||
if multigraph:
|
||||
yield from stringize("key", e[2], (), " ")
|
||||
for attr, value in e[-1].items():
|
||||
yield from stringize(attr, value, ignored_keys, " ")
|
||||
yield " ]"
|
||||
yield "]"
|
||||
|
||||
|
||||
@open_file(1, mode="wb")
|
||||
def write_gml(G, path, stringizer=None):
|
||||
"""Write a graph `G` in GML format to the file or file handle `path`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
The graph to be converted to GML.
|
||||
|
||||
path : filename or filehandle
|
||||
The filename or filehandle to write. Files whose names end with .gz or
|
||||
.bz2 will be compressed.
|
||||
|
||||
stringizer : callable, optional
|
||||
A `stringizer` which converts non-int/non-float/non-dict values into
|
||||
strings. If it cannot convert a value into a string, it should raise a
|
||||
`ValueError` to indicate that. Default value: None.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If `stringizer` cannot convert a value into a string, or the value to
|
||||
convert is not a string while `stringizer` is None.
|
||||
|
||||
See Also
|
||||
--------
|
||||
read_gml, generate_gml
|
||||
literal_stringizer
|
||||
|
||||
Notes
|
||||
-----
|
||||
Graph attributes named 'directed', 'multigraph', 'node' or
|
||||
'edge', node attributes named 'id' or 'label', edge attributes
|
||||
named 'source' or 'target' (or 'key' if `G` is a multigraph)
|
||||
are ignored because these attribute names are used to encode the graph
|
||||
structure.
|
||||
|
||||
GML files are stored using a 7-bit ASCII encoding with any extended
|
||||
ASCII characters (iso8859-1) appearing as HTML character entities.
|
||||
Without specifying a `stringizer`/`destringizer`, the code is capable of
|
||||
writing `int`/`float`/`str`/`dict`/`list` data as required by the GML
|
||||
specification. For writing other data types, and for reading data other
|
||||
than `str` you need to explicitly supply a `stringizer`/`destringizer`.
|
||||
|
||||
Note that while we allow non-standard GML to be read from a file, we make
|
||||
sure to write GML format. In particular, underscores are not allowed in
|
||||
attribute names.
|
||||
For additional documentation on the GML file format, please see the
|
||||
`GML url <https://web.archive.org/web/20190207140002/http://www.fim.uni-passau.de/index.php?id=17297&L=1>`_.
|
||||
|
||||
See the module docstring :mod:`networkx.readwrite.gml` for more details.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(4)
|
||||
>>> nx.write_gml(G, "test.gml")
|
||||
|
||||
Filenames ending in .gz or .bz2 will be compressed.
|
||||
|
||||
>>> nx.write_gml(G, "test.gml.gz")
|
||||
"""
|
||||
for line in generate_gml(G, stringizer):
|
||||
path.write((line + "\n").encode("ascii"))
|
||||
414
.CondaPkg/env/Lib/site-packages/networkx/readwrite/graph6.py
vendored
Normal file
414
.CondaPkg/env/Lib/site-packages/networkx/readwrite/graph6.py
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
# Original author: D. Eppstein, UC Irvine, August 12, 2003.
|
||||
# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain.
|
||||
"""Functions for reading and writing graphs in the *graph6* format.
|
||||
|
||||
The *graph6* file format is suitable for small graphs or large dense
|
||||
graphs. For large sparse graphs, use the *sparse6* format.
|
||||
|
||||
For more information, see the `graph6`_ homepage.
|
||||
|
||||
.. _graph6: http://users.cecs.anu.edu.au/~bdm/data/formats.html
|
||||
|
||||
"""
|
||||
from itertools import islice
|
||||
|
||||
import networkx as nx
|
||||
from networkx.exception import NetworkXError
|
||||
from networkx.utils import not_implemented_for, open_file
|
||||
|
||||
__all__ = ["from_graph6_bytes", "read_graph6", "to_graph6_bytes", "write_graph6"]
|
||||
|
||||
|
||||
def _generate_graph6_bytes(G, nodes, header):
|
||||
"""Yield bytes in the graph6 encoding of a graph.
|
||||
|
||||
`G` is an undirected simple graph. `nodes` is the list of nodes for
|
||||
which the node-induced subgraph will be encoded; if `nodes` is the
|
||||
list of all nodes in the graph, the entire graph will be
|
||||
encoded. `header` is a Boolean that specifies whether to generate
|
||||
the header ``b'>>graph6<<'`` before the remaining data.
|
||||
|
||||
This function generates `bytes` objects in the following order:
|
||||
|
||||
1. the header (if requested),
|
||||
2. the encoding of the number of nodes,
|
||||
3. each character, one-at-a-time, in the encoding of the requested
|
||||
node-induced subgraph,
|
||||
4. a newline character.
|
||||
|
||||
This function raises :exc:`ValueError` if the graph is too large for
|
||||
the graph6 format (that is, greater than ``2 ** 36`` nodes).
|
||||
|
||||
"""
|
||||
n = len(G)
|
||||
if n >= 2**36:
|
||||
raise ValueError(
|
||||
"graph6 is only defined if number of nodes is less " "than 2 ** 36"
|
||||
)
|
||||
if header:
|
||||
yield b">>graph6<<"
|
||||
for d in n_to_data(n):
|
||||
yield str.encode(chr(d + 63))
|
||||
# This generates the same as `(v in G[u] for u, v in combinations(G, 2))`,
|
||||
# but in "column-major" order instead of "row-major" order.
|
||||
bits = (nodes[j] in G[nodes[i]] for j in range(1, n) for i in range(j))
|
||||
chunk = list(islice(bits, 6))
|
||||
while chunk:
|
||||
d = sum(b << 5 - i for i, b in enumerate(chunk))
|
||||
yield str.encode(chr(d + 63))
|
||||
chunk = list(islice(bits, 6))
|
||||
yield b"\n"
|
||||
|
||||
|
||||
def from_graph6_bytes(bytes_in):
|
||||
"""Read a simple undirected graph in graph6 format from bytes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bytes_in : bytes
|
||||
Data in graph6 format, without a trailing newline.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : Graph
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If bytes_in is unable to be parsed in graph6 format
|
||||
|
||||
ValueError
|
||||
If any character ``c`` in bytes_in does not satisfy
|
||||
``63 <= ord(c) < 127``.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.from_graph6_bytes(b"A_")
|
||||
>>> sorted(G.edges())
|
||||
[(0, 1)]
|
||||
|
||||
See Also
|
||||
--------
|
||||
read_graph6, write_graph6
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Graph6 specification
|
||||
<http://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
|
||||
def bits():
|
||||
"""Returns sequence of individual bits from 6-bit-per-value
|
||||
list of data values."""
|
||||
for d in data:
|
||||
for i in [5, 4, 3, 2, 1, 0]:
|
||||
yield (d >> i) & 1
|
||||
|
||||
if bytes_in.startswith(b">>graph6<<"):
|
||||
bytes_in = bytes_in[10:]
|
||||
|
||||
data = [c - 63 for c in bytes_in]
|
||||
if any(c > 63 for c in data):
|
||||
raise ValueError("each input character must be in range(63, 127)")
|
||||
|
||||
n, data = data_to_n(data)
|
||||
nd = (n * (n - 1) // 2 + 5) // 6
|
||||
if len(data) != nd:
|
||||
raise NetworkXError(
|
||||
f"Expected {n * (n - 1) // 2} bits but got {len(data) * 6} in graph6"
|
||||
)
|
||||
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from(range(n))
|
||||
for (i, j), b in zip(((i, j) for j in range(1, n) for i in range(j)), bits()):
|
||||
if b:
|
||||
G.add_edge(i, j)
|
||||
|
||||
return G
|
||||
|
||||
|
||||
@not_implemented_for("directed")
|
||||
@not_implemented_for("multigraph")
|
||||
def to_graph6_bytes(G, nodes=None, header=True):
|
||||
"""Convert a simple undirected graph to bytes in graph6 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : Graph (undirected)
|
||||
|
||||
nodes: list or iterable
|
||||
Nodes are labeled 0...n-1 in the order provided. If None the ordering
|
||||
given by ``G.nodes()`` is used.
|
||||
|
||||
header: bool
|
||||
If True add '>>graph6<<' bytes to head of data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXNotImplemented
|
||||
If the graph is directed or is a multigraph.
|
||||
|
||||
ValueError
|
||||
If the graph has at least ``2 ** 36`` nodes; the graph6 format
|
||||
is only defined for graphs of order less than ``2 ** 36``.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> nx.to_graph6_bytes(nx.path_graph(2))
|
||||
b'>>graph6<<A_\\n'
|
||||
|
||||
See Also
|
||||
--------
|
||||
from_graph6_bytes, read_graph6, write_graph6_bytes
|
||||
|
||||
Notes
|
||||
-----
|
||||
The returned bytes end with a newline character.
|
||||
|
||||
The format does not support edge or node labels, parallel edges or
|
||||
self loops. If self loops are present they are silently ignored.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Graph6 specification
|
||||
<http://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
if nodes is not None:
|
||||
G = G.subgraph(nodes)
|
||||
H = nx.convert_node_labels_to_integers(G)
|
||||
nodes = sorted(H.nodes())
|
||||
return b"".join(_generate_graph6_bytes(H, nodes, header))
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
def read_graph6(path):
|
||||
"""Read simple undirected graphs in graph6 format from path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : file or string
|
||||
File or filename to write.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : Graph or list of Graphs
|
||||
If the file contains multiple lines then a list of graphs is returned
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the string is unable to be parsed in graph6 format
|
||||
|
||||
Examples
|
||||
--------
|
||||
You can read a graph6 file by giving the path to the file::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
... _ = f.write(b">>graph6<<A_\\n")
|
||||
... _ = f.seek(0)
|
||||
... G = nx.read_graph6(f.name)
|
||||
>>> list(G.edges())
|
||||
[(0, 1)]
|
||||
|
||||
You can also read a graph6 file by giving an open file-like object::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile() as f:
|
||||
... _ = f.write(b">>graph6<<A_\\n")
|
||||
... _ = f.seek(0)
|
||||
... G = nx.read_graph6(f)
|
||||
>>> list(G.edges())
|
||||
[(0, 1)]
|
||||
|
||||
See Also
|
||||
--------
|
||||
from_graph6_bytes, write_graph6
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Graph6 specification
|
||||
<http://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
glist = []
|
||||
for line in path:
|
||||
line = line.strip()
|
||||
if not len(line):
|
||||
continue
|
||||
glist.append(from_graph6_bytes(line))
|
||||
if len(glist) == 1:
|
||||
return glist[0]
|
||||
else:
|
||||
return glist
|
||||
|
||||
|
||||
@not_implemented_for("directed")
|
||||
@not_implemented_for("multigraph")
|
||||
@open_file(1, mode="wb")
|
||||
def write_graph6(G, path, nodes=None, header=True):
|
||||
"""Write a simple undirected graph to a path in graph6 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : Graph (undirected)
|
||||
|
||||
path : str
|
||||
The path naming the file to which to write the graph.
|
||||
|
||||
nodes: list or iterable
|
||||
Nodes are labeled 0...n-1 in the order provided. If None the ordering
|
||||
given by ``G.nodes()`` is used.
|
||||
|
||||
header: bool
|
||||
If True add '>>graph6<<' string to head of data
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXNotImplemented
|
||||
If the graph is directed or is a multigraph.
|
||||
|
||||
ValueError
|
||||
If the graph has at least ``2 ** 36`` nodes; the graph6 format
|
||||
is only defined for graphs of order less than ``2 ** 36``.
|
||||
|
||||
Examples
|
||||
--------
|
||||
You can write a graph6 file by giving the path to a file::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
... nx.write_graph6(nx.path_graph(2), f.name)
|
||||
... _ = f.seek(0)
|
||||
... print(f.read())
|
||||
b'>>graph6<<A_\\n'
|
||||
|
||||
See Also
|
||||
--------
|
||||
from_graph6_bytes, read_graph6
|
||||
|
||||
Notes
|
||||
-----
|
||||
The function writes a newline character after writing the encoding
|
||||
of the graph.
|
||||
|
||||
The format does not support edge or node labels, parallel edges or
|
||||
self loops. If self loops are present they are silently ignored.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Graph6 specification
|
||||
<http://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
return write_graph6_file(G, path, nodes=nodes, header=header)
|
||||
|
||||
|
||||
@not_implemented_for("directed")
|
||||
@not_implemented_for("multigraph")
|
||||
def write_graph6_file(G, f, nodes=None, header=True):
|
||||
"""Write a simple undirected graph to a file-like object in graph6 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : Graph (undirected)
|
||||
|
||||
f : file-like object
|
||||
The file to write.
|
||||
|
||||
nodes: list or iterable
|
||||
Nodes are labeled 0...n-1 in the order provided. If None the ordering
|
||||
given by ``G.nodes()`` is used.
|
||||
|
||||
header: bool
|
||||
If True add '>>graph6<<' string to head of data
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXNotImplemented
|
||||
If the graph is directed or is a multigraph.
|
||||
|
||||
ValueError
|
||||
If the graph has at least ``2 ** 36`` nodes; the graph6 format
|
||||
is only defined for graphs of order less than ``2 ** 36``.
|
||||
|
||||
Examples
|
||||
--------
|
||||
You can write a graph6 file by giving an open file-like object::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile() as f:
|
||||
... nx.write_graph6(nx.path_graph(2), f)
|
||||
... _ = f.seek(0)
|
||||
... print(f.read())
|
||||
b'>>graph6<<A_\\n'
|
||||
|
||||
See Also
|
||||
--------
|
||||
from_graph6_bytes, read_graph6
|
||||
|
||||
Notes
|
||||
-----
|
||||
The function writes a newline character after writing the encoding
|
||||
of the graph.
|
||||
|
||||
The format does not support edge or node labels, parallel edges or
|
||||
self loops. If self loops are present they are silently ignored.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Graph6 specification
|
||||
<http://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
if nodes is not None:
|
||||
G = G.subgraph(nodes)
|
||||
H = nx.convert_node_labels_to_integers(G)
|
||||
nodes = sorted(H.nodes())
|
||||
for b in _generate_graph6_bytes(H, nodes, header):
|
||||
f.write(b)
|
||||
|
||||
|
||||
def data_to_n(data):
|
||||
"""Read initial one-, four- or eight-unit value from graph6
|
||||
integer sequence.
|
||||
|
||||
Return (value, rest of seq.)"""
|
||||
if data[0] <= 62:
|
||||
return data[0], data[1:]
|
||||
if data[1] <= 62:
|
||||
return (data[1] << 12) + (data[2] << 6) + data[3], data[4:]
|
||||
return (
|
||||
(data[2] << 30)
|
||||
+ (data[3] << 24)
|
||||
+ (data[4] << 18)
|
||||
+ (data[5] << 12)
|
||||
+ (data[6] << 6)
|
||||
+ data[7],
|
||||
data[8:],
|
||||
)
|
||||
|
||||
|
||||
def n_to_data(n):
|
||||
"""Convert an integer to one-, four- or eight-unit graph6 sequence.
|
||||
|
||||
This function is undefined if `n` is not in ``range(2 ** 36)``.
|
||||
|
||||
"""
|
||||
if n <= 62:
|
||||
return [n]
|
||||
elif n <= 258047:
|
||||
return [63, (n >> 12) & 0x3F, (n >> 6) & 0x3F, n & 0x3F]
|
||||
else: # if n <= 68719476735:
|
||||
return [
|
||||
63,
|
||||
63,
|
||||
(n >> 30) & 0x3F,
|
||||
(n >> 24) & 0x3F,
|
||||
(n >> 18) & 0x3F,
|
||||
(n >> 12) & 0x3F,
|
||||
(n >> 6) & 0x3F,
|
||||
n & 0x3F,
|
||||
]
|
||||
1050
.CondaPkg/env/Lib/site-packages/networkx/readwrite/graphml.py
vendored
Normal file
1050
.CondaPkg/env/Lib/site-packages/networkx/readwrite/graphml.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__init__.py
vendored
Normal file
18
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__init__.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
*********
|
||||
JSON data
|
||||
*********
|
||||
Generate and parse JSON serializable data for NetworkX graphs.
|
||||
|
||||
These formats are suitable for use with the d3.js examples https://d3js.org/
|
||||
|
||||
The three formats that you can generate with NetworkX are:
|
||||
|
||||
- node-link like in the d3.js example https://bl.ocks.org/mbostock/4062045
|
||||
- tree like in the d3.js example https://bl.ocks.org/mbostock/4063550
|
||||
- adjacency like in the d3.js example https://bost.ocks.org/mike/miserables/
|
||||
"""
|
||||
from networkx.readwrite.json_graph.node_link import *
|
||||
from networkx.readwrite.json_graph.adjacency import *
|
||||
from networkx.readwrite.json_graph.tree import *
|
||||
from networkx.readwrite.json_graph.cytoscape import *
|
||||
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/adjacency.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/adjacency.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/cytoscape.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/cytoscape.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/node_link.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/node_link.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/tree.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/__pycache__/tree.cpython-311.pyc
vendored
Normal file
Binary file not shown.
157
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/adjacency.py
vendored
Normal file
157
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/adjacency.py
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
from itertools import chain
|
||||
|
||||
import networkx as nx
|
||||
|
||||
__all__ = ["adjacency_data", "adjacency_graph"]
|
||||
|
||||
_attrs = {"id": "id", "key": "key"}
|
||||
|
||||
|
||||
def adjacency_data(G, attrs=_attrs):
|
||||
"""Returns data in adjacency format that is suitable for JSON serialization
|
||||
and use in Javascript documents.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
|
||||
attrs : dict
|
||||
A dictionary that contains two keys 'id' and 'key'. The corresponding
|
||||
values provide the attribute names for storing NetworkX-internal graph
|
||||
data. The values should be unique. Default value:
|
||||
:samp:`dict(id='id', key='key')`.
|
||||
|
||||
If some user-defined graph data use these attribute names as data keys,
|
||||
they may be silently dropped.
|
||||
|
||||
Returns
|
||||
-------
|
||||
data : dict
|
||||
A dictionary with adjacency formatted data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If values in attrs are not unique.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from networkx.readwrite import json_graph
|
||||
>>> G = nx.Graph([(1, 2)])
|
||||
>>> data = json_graph.adjacency_data(G)
|
||||
|
||||
To serialize with json
|
||||
|
||||
>>> import json
|
||||
>>> s = json.dumps(data)
|
||||
|
||||
Notes
|
||||
-----
|
||||
Graph, node, and link attributes will be written when using this format
|
||||
but attribute keys must be strings if you want to serialize the resulting
|
||||
data with JSON.
|
||||
|
||||
The default value of attrs will be changed in a future release of NetworkX.
|
||||
|
||||
See Also
|
||||
--------
|
||||
adjacency_graph, node_link_data, tree_data
|
||||
"""
|
||||
multigraph = G.is_multigraph()
|
||||
id_ = attrs["id"]
|
||||
# Allow 'key' to be omitted from attrs if the graph is not a multigraph.
|
||||
key = None if not multigraph else attrs["key"]
|
||||
if id_ == key:
|
||||
raise nx.NetworkXError("Attribute names are not unique.")
|
||||
data = {}
|
||||
data["directed"] = G.is_directed()
|
||||
data["multigraph"] = multigraph
|
||||
data["graph"] = list(G.graph.items())
|
||||
data["nodes"] = []
|
||||
data["adjacency"] = []
|
||||
for n, nbrdict in G.adjacency():
|
||||
data["nodes"].append(dict(chain(G.nodes[n].items(), [(id_, n)])))
|
||||
adj = []
|
||||
if multigraph:
|
||||
for nbr, keys in nbrdict.items():
|
||||
for k, d in keys.items():
|
||||
adj.append(dict(chain(d.items(), [(id_, nbr), (key, k)])))
|
||||
else:
|
||||
for nbr, d in nbrdict.items():
|
||||
adj.append(dict(chain(d.items(), [(id_, nbr)])))
|
||||
data["adjacency"].append(adj)
|
||||
return data
|
||||
|
||||
|
||||
def adjacency_graph(data, directed=False, multigraph=True, attrs=_attrs):
|
||||
"""Returns graph from adjacency data format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : dict
|
||||
Adjacency list formatted graph data
|
||||
|
||||
directed : bool
|
||||
If True, and direction not specified in data, return a directed graph.
|
||||
|
||||
multigraph : bool
|
||||
If True, and multigraph not specified in data, return a multigraph.
|
||||
|
||||
attrs : dict
|
||||
A dictionary that contains two keys 'id' and 'key'. The corresponding
|
||||
values provide the attribute names for storing NetworkX-internal graph
|
||||
data. The values should be unique. Default value:
|
||||
:samp:`dict(id='id', key='key')`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
A NetworkX graph object
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from networkx.readwrite import json_graph
|
||||
>>> G = nx.Graph([(1, 2)])
|
||||
>>> data = json_graph.adjacency_data(G)
|
||||
>>> H = json_graph.adjacency_graph(data)
|
||||
|
||||
Notes
|
||||
-----
|
||||
The default value of attrs will be changed in a future release of NetworkX.
|
||||
|
||||
See Also
|
||||
--------
|
||||
adjacency_graph, node_link_data, tree_data
|
||||
"""
|
||||
multigraph = data.get("multigraph", multigraph)
|
||||
directed = data.get("directed", directed)
|
||||
if multigraph:
|
||||
graph = nx.MultiGraph()
|
||||
else:
|
||||
graph = nx.Graph()
|
||||
if directed:
|
||||
graph = graph.to_directed()
|
||||
id_ = attrs["id"]
|
||||
# Allow 'key' to be omitted from attrs if the graph is not a multigraph.
|
||||
key = None if not multigraph else attrs["key"]
|
||||
graph.graph = dict(data.get("graph", []))
|
||||
mapping = []
|
||||
for d in data["nodes"]:
|
||||
node_data = d.copy()
|
||||
node = node_data.pop(id_)
|
||||
mapping.append(node)
|
||||
graph.add_node(node)
|
||||
graph.nodes[node].update(node_data)
|
||||
for i, d in enumerate(data["adjacency"]):
|
||||
source = mapping[i]
|
||||
for tdata in d:
|
||||
target_data = tdata.copy()
|
||||
target = target_data.pop(id_)
|
||||
if not multigraph:
|
||||
graph.add_edge(source, target)
|
||||
graph[source][target].update(tdata)
|
||||
else:
|
||||
ky = target_data.pop(key, None)
|
||||
graph.add_edge(source, target, key=ky)
|
||||
graph[source][target][ky].update(tdata)
|
||||
return graph
|
||||
173
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/cytoscape.py
vendored
Normal file
173
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/cytoscape.py
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
import networkx as nx
|
||||
|
||||
__all__ = ["cytoscape_data", "cytoscape_graph"]
|
||||
|
||||
|
||||
def cytoscape_data(G, name="name", ident="id"):
|
||||
"""Returns data in Cytoscape JSON format (cyjs).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX Graph
|
||||
The graph to convert to cytoscape format
|
||||
name : string
|
||||
A string which is mapped to the 'name' node element in cyjs format.
|
||||
Must not have the same value as `ident`.
|
||||
ident : string
|
||||
A string which is mapped to the 'id' node element in cyjs format.
|
||||
Must not have the same value as `name`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
data: dict
|
||||
A dictionary with cyjs formatted data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the values for `name` and `ident` are identical.
|
||||
|
||||
See Also
|
||||
--------
|
||||
cytoscape_graph: convert a dictionary in cyjs format to a graph
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Cytoscape user's manual:
|
||||
http://manual.cytoscape.org/en/stable/index.html
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(2)
|
||||
>>> nx.cytoscape_data(G) # doctest: +SKIP
|
||||
{'data': [],
|
||||
'directed': False,
|
||||
'multigraph': False,
|
||||
'elements': {'nodes': [{'data': {'id': '0', 'value': 0, 'name': '0'}},
|
||||
{'data': {'id': '1', 'value': 1, 'name': '1'}}],
|
||||
'edges': [{'data': {'source': 0, 'target': 1}}]}}
|
||||
"""
|
||||
if name == ident:
|
||||
raise nx.NetworkXError("name and ident must be different.")
|
||||
|
||||
jsondata = {"data": list(G.graph.items())}
|
||||
jsondata["directed"] = G.is_directed()
|
||||
jsondata["multigraph"] = G.is_multigraph()
|
||||
jsondata["elements"] = {"nodes": [], "edges": []}
|
||||
nodes = jsondata["elements"]["nodes"]
|
||||
edges = jsondata["elements"]["edges"]
|
||||
|
||||
for i, j in G.nodes.items():
|
||||
n = {"data": j.copy()}
|
||||
n["data"]["id"] = j.get(ident) or str(i)
|
||||
n["data"]["value"] = i
|
||||
n["data"]["name"] = j.get(name) or str(i)
|
||||
nodes.append(n)
|
||||
|
||||
if G.is_multigraph():
|
||||
for e in G.edges(keys=True):
|
||||
n = {"data": G.adj[e[0]][e[1]][e[2]].copy()}
|
||||
n["data"]["source"] = e[0]
|
||||
n["data"]["target"] = e[1]
|
||||
n["data"]["key"] = e[2]
|
||||
edges.append(n)
|
||||
else:
|
||||
for e in G.edges():
|
||||
n = {"data": G.adj[e[0]][e[1]].copy()}
|
||||
n["data"]["source"] = e[0]
|
||||
n["data"]["target"] = e[1]
|
||||
edges.append(n)
|
||||
return jsondata
|
||||
|
||||
|
||||
def cytoscape_graph(data, name="name", ident="id"):
|
||||
"""
|
||||
Create a NetworkX graph from a dictionary in cytoscape JSON format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : dict
|
||||
A dictionary of data conforming to cytoscape JSON format.
|
||||
name : string
|
||||
A string which is mapped to the 'name' node element in cyjs format.
|
||||
Must not have the same value as `ident`.
|
||||
ident : string
|
||||
A string which is mapped to the 'id' node element in cyjs format.
|
||||
Must not have the same value as `name`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
graph : a NetworkX graph instance
|
||||
The `graph` can be an instance of `Graph`, `DiGraph`, `MultiGraph`, or
|
||||
`MultiDiGraph` depending on the input data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the `name` and `ident` attributes are identical.
|
||||
|
||||
See Also
|
||||
--------
|
||||
cytoscape_data: convert a NetworkX graph to a dict in cyjs format
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Cytoscape user's manual:
|
||||
http://manual.cytoscape.org/en/stable/index.html
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> data_dict = {
|
||||
... 'data': [],
|
||||
... 'directed': False,
|
||||
... 'multigraph': False,
|
||||
... 'elements': {'nodes': [{'data': {'id': '0', 'value': 0, 'name': '0'}},
|
||||
... {'data': {'id': '1', 'value': 1, 'name': '1'}}],
|
||||
... 'edges': [{'data': {'source': 0, 'target': 1}}]}
|
||||
... }
|
||||
>>> G = nx.cytoscape_graph(data_dict)
|
||||
>>> G.name
|
||||
''
|
||||
>>> G.nodes()
|
||||
NodeView((0, 1))
|
||||
>>> G.nodes(data=True)[0]
|
||||
{'id': '0', 'value': 0, 'name': '0'}
|
||||
>>> G.edges(data=True)
|
||||
EdgeDataView([(0, 1, {'source': 0, 'target': 1})])
|
||||
"""
|
||||
if name == ident:
|
||||
raise nx.NetworkXError("name and ident must be different.")
|
||||
|
||||
multigraph = data.get("multigraph")
|
||||
directed = data.get("directed")
|
||||
if multigraph:
|
||||
graph = nx.MultiGraph()
|
||||
else:
|
||||
graph = nx.Graph()
|
||||
if directed:
|
||||
graph = graph.to_directed()
|
||||
graph.graph = dict(data.get("data"))
|
||||
for d in data["elements"]["nodes"]:
|
||||
node_data = d["data"].copy()
|
||||
node = d["data"]["value"]
|
||||
|
||||
if d["data"].get(name):
|
||||
node_data[name] = d["data"].get(name)
|
||||
if d["data"].get(ident):
|
||||
node_data[ident] = d["data"].get(ident)
|
||||
|
||||
graph.add_node(node)
|
||||
graph.nodes[node].update(node_data)
|
||||
|
||||
for d in data["elements"]["edges"]:
|
||||
edge_data = d["data"].copy()
|
||||
sour = d["data"]["source"]
|
||||
targ = d["data"]["target"]
|
||||
if multigraph:
|
||||
key = d["data"].get("key", 0)
|
||||
graph.add_edge(sour, targ, key=key)
|
||||
graph.edges[sour, targ, key].update(edge_data)
|
||||
else:
|
||||
graph.add_edge(sour, targ)
|
||||
graph.edges[sour, targ].update(edge_data)
|
||||
return graph
|
||||
339
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/node_link.py
vendored
Normal file
339
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/node_link.py
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
from itertools import chain, count
|
||||
|
||||
import networkx as nx
|
||||
|
||||
__all__ = ["node_link_data", "node_link_graph"]
|
||||
|
||||
|
||||
_attrs = {
|
||||
"source": "source",
|
||||
"target": "target",
|
||||
"name": "id",
|
||||
"key": "key",
|
||||
"link": "links",
|
||||
}
|
||||
|
||||
|
||||
def _to_tuple(x):
|
||||
"""Converts lists to tuples, including nested lists.
|
||||
|
||||
All other non-list inputs are passed through unmodified. This function is
|
||||
intended to be used to convert potentially nested lists from json files
|
||||
into valid nodes.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> _to_tuple([1, 2, [3, 4]])
|
||||
(1, 2, (3, 4))
|
||||
"""
|
||||
if not isinstance(x, (tuple, list)):
|
||||
return x
|
||||
return tuple(map(_to_tuple, x))
|
||||
|
||||
|
||||
def node_link_data(
|
||||
G,
|
||||
attrs=None,
|
||||
*,
|
||||
source="source",
|
||||
target="target",
|
||||
name="id",
|
||||
key="key",
|
||||
link="links",
|
||||
):
|
||||
"""Returns data in node-link format that is suitable for JSON serialization
|
||||
and use in Javascript documents.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
|
||||
attrs : dict
|
||||
A dictionary that contains five keys 'source', 'target', 'name',
|
||||
'key' and 'link'. The corresponding values provide the attribute
|
||||
names for storing NetworkX-internal graph data. The values should
|
||||
be unique. Default value::
|
||||
|
||||
dict(source='source', target='target', name='id',
|
||||
key='key', link='links')
|
||||
|
||||
If some user-defined graph data use these attribute names as data keys,
|
||||
they may be silently dropped.
|
||||
|
||||
.. deprecated:: 2.8.6
|
||||
|
||||
The `attrs` keyword argument will be replaced with `source`, `target`, `name`,
|
||||
`key` and `link`. in networkx 3.2
|
||||
|
||||
If the `attrs` keyword and the new keywords are both used in a single function call (not recommended)
|
||||
the `attrs` keyword argument will take precedence.
|
||||
|
||||
The values of the keywords must be unique.
|
||||
|
||||
source : string
|
||||
A string that provides the 'source' attribute name for storing NetworkX-internal graph data.
|
||||
target : string
|
||||
A string that provides the 'target' attribute name for storing NetworkX-internal graph data.
|
||||
name : string
|
||||
A string that provides the 'name' attribute name for storing NetworkX-internal graph data.
|
||||
key : string
|
||||
A string that provides the 'key' attribute name for storing NetworkX-internal graph data.
|
||||
link : string
|
||||
A string that provides the 'link' attribute name for storing NetworkX-internal graph data.
|
||||
|
||||
Returns
|
||||
-------
|
||||
data : dict
|
||||
A dictionary with node-link formatted data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the values of 'source', 'target' and 'key' are not unique.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.Graph([("A", "B")])
|
||||
>>> data1 = nx.node_link_data(G)
|
||||
>>> data1
|
||||
{'directed': False, 'multigraph': False, 'graph': {}, 'nodes': [{'id': 'A'}, {'id': 'B'}], 'links': [{'source': 'A', 'target': 'B'}]}
|
||||
|
||||
To serialize with JSON
|
||||
|
||||
>>> import json
|
||||
>>> s1 = json.dumps(data1)
|
||||
>>> s1
|
||||
'{"directed": false, "multigraph": false, "graph": {}, "nodes": [{"id": "A"}, {"id": "B"}], "links": [{"source": "A", "target": "B"}]}'
|
||||
|
||||
A graph can also be serialized by passing `node_link_data` as an encoder function. The two methods are equivalent.
|
||||
|
||||
>>> s1 = json.dumps(G, default=nx.node_link_data)
|
||||
>>> s1
|
||||
'{"directed": false, "multigraph": false, "graph": {}, "nodes": [{"id": "A"}, {"id": "B"}], "links": [{"source": "A", "target": "B"}]}'
|
||||
|
||||
The attribute names for storing NetworkX-internal graph data can
|
||||
be specified as keyword options.
|
||||
|
||||
>>> H = nx.gn_graph(2)
|
||||
>>> data2 = nx.node_link_data(H, link="edges", source="from", target="to")
|
||||
>>> data2
|
||||
{'directed': True, 'multigraph': False, 'graph': {}, 'nodes': [{'id': 0}, {'id': 1}], 'edges': [{'from': 1, 'to': 0}]}
|
||||
|
||||
Notes
|
||||
-----
|
||||
Graph, node, and link attributes are stored in this format. Note that
|
||||
attribute keys will be converted to strings in order to comply with JSON.
|
||||
|
||||
Attribute 'key' is only used for multigraphs.
|
||||
|
||||
To use `node_link_data` in conjunction with `node_link_graph`,
|
||||
the keyword names for the attributes must match.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
node_link_graph, adjacency_data, tree_data
|
||||
"""
|
||||
# ------ TODO: Remove between the lines after signature change is complete ----- #
|
||||
if attrs is not None:
|
||||
import warnings
|
||||
|
||||
msg = (
|
||||
"\n\nThe `attrs` keyword argument of node_link_data is deprecated\n"
|
||||
"and will be removed in networkx 3.2. It is replaced with explicit\n"
|
||||
"keyword arguments: `source`, `target`, `name`, `key` and `link`.\n"
|
||||
"To make this warning go away, and ensure usage is forward\n"
|
||||
"compatible, replace `attrs` with the keywords. "
|
||||
"For example:\n\n"
|
||||
" >>> node_link_data(G, attrs={'target': 'foo', 'name': 'bar'})\n\n"
|
||||
"should instead be written as\n\n"
|
||||
" >>> node_link_data(G, target='foo', name='bar')\n\n"
|
||||
"in networkx 3.2.\n"
|
||||
"The default values of the keywords will not change.\n"
|
||||
)
|
||||
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
||||
|
||||
source = attrs.get("source", "source")
|
||||
target = attrs.get("target", "target")
|
||||
name = attrs.get("name", "name")
|
||||
key = attrs.get("key", "key")
|
||||
link = attrs.get("link", "links")
|
||||
# -------------------------------------------------- #
|
||||
multigraph = G.is_multigraph()
|
||||
|
||||
# Allow 'key' to be omitted from attrs if the graph is not a multigraph.
|
||||
key = None if not multigraph else key
|
||||
if len({source, target, key}) < 3:
|
||||
raise nx.NetworkXError("Attribute names are not unique.")
|
||||
data = {
|
||||
"directed": G.is_directed(),
|
||||
"multigraph": multigraph,
|
||||
"graph": G.graph,
|
||||
"nodes": [dict(chain(G.nodes[n].items(), [(name, n)])) for n in G],
|
||||
}
|
||||
if multigraph:
|
||||
data[link] = [
|
||||
dict(chain(d.items(), [(source, u), (target, v), (key, k)]))
|
||||
for u, v, k, d in G.edges(keys=True, data=True)
|
||||
]
|
||||
else:
|
||||
data[link] = [
|
||||
dict(chain(d.items(), [(source, u), (target, v)]))
|
||||
for u, v, d in G.edges(data=True)
|
||||
]
|
||||
return data
|
||||
|
||||
|
||||
def node_link_graph(
|
||||
data,
|
||||
directed=False,
|
||||
multigraph=True,
|
||||
attrs=None,
|
||||
*,
|
||||
source="source",
|
||||
target="target",
|
||||
name="id",
|
||||
key="key",
|
||||
link="links",
|
||||
):
|
||||
"""Returns graph from node-link data format.
|
||||
Useful for de-serialization from JSON.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : dict
|
||||
node-link formatted graph data
|
||||
|
||||
directed : bool
|
||||
If True, and direction not specified in data, return a directed graph.
|
||||
|
||||
multigraph : bool
|
||||
If True, and multigraph not specified in data, return a multigraph.
|
||||
|
||||
attrs : dict
|
||||
A dictionary that contains five keys 'source', 'target', 'name',
|
||||
'key' and 'link'. The corresponding values provide the attribute
|
||||
names for storing NetworkX-internal graph data. Default value:
|
||||
|
||||
dict(source='source', target='target', name='id',
|
||||
key='key', link='links')
|
||||
|
||||
.. deprecated:: 2.8.6
|
||||
|
||||
The `attrs` keyword argument will be replaced with the individual keywords: `source`, `target`, `name`,
|
||||
`key` and `link`. in networkx 3.2.
|
||||
|
||||
If the `attrs` keyword and the new keywords are both used in a single function call (not recommended)
|
||||
the `attrs` keyword argument will take precedence.
|
||||
|
||||
The values of the keywords must be unique.
|
||||
|
||||
source : string
|
||||
A string that provides the 'source' attribute name for storing NetworkX-internal graph data.
|
||||
target : string
|
||||
A string that provides the 'target' attribute name for storing NetworkX-internal graph data.
|
||||
name : string
|
||||
A string that provides the 'name' attribute name for storing NetworkX-internal graph data.
|
||||
key : string
|
||||
A string that provides the 'key' attribute name for storing NetworkX-internal graph data.
|
||||
link : string
|
||||
A string that provides the 'link' attribute name for storing NetworkX-internal graph data.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
A NetworkX graph object
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Create data in node-link format by converting a graph.
|
||||
|
||||
>>> G = nx.Graph([('A', 'B')])
|
||||
>>> data = nx.node_link_data(G)
|
||||
>>> data
|
||||
{'directed': False, 'multigraph': False, 'graph': {}, 'nodes': [{'id': 'A'}, {'id': 'B'}], 'links': [{'source': 'A', 'target': 'B'}]}
|
||||
|
||||
Revert data in node-link format to a graph.
|
||||
|
||||
>>> H = nx.node_link_graph(data)
|
||||
>>> print(H.edges)
|
||||
[('A', 'B')]
|
||||
|
||||
To serialize and deserialize a graph with JSON,
|
||||
|
||||
>>> import json
|
||||
>>> d = json.dumps(node_link_data(G))
|
||||
>>> H = node_link_graph(json.loads(d))
|
||||
>>> print(G.edges, H.edges)
|
||||
[('A', 'B')] [('A', 'B')]
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
Attribute 'key' is only used for multigraphs.
|
||||
|
||||
To use `node_link_data` in conjunction with `node_link_graph`,
|
||||
the keyword names for the attributes must match.
|
||||
|
||||
See Also
|
||||
--------
|
||||
node_link_data, adjacency_data, tree_data
|
||||
"""
|
||||
# ------ TODO: Remove between the lines after signature change is complete ----- #
|
||||
if attrs is not None:
|
||||
import warnings
|
||||
|
||||
msg = (
|
||||
"\n\nThe `attrs` keyword argument of node_link_graph is deprecated\n"
|
||||
"and will be removed in networkx 3.2. It is replaced with explicit\n"
|
||||
"keyword arguments: `source`, `target`, `name`, `key` and `link`.\n"
|
||||
"To make this warning go away, and ensure usage is forward\n"
|
||||
"compatible, replace `attrs` with the keywords. "
|
||||
"For example:\n\n"
|
||||
" >>> node_link_graph(data, attrs={'target': 'foo', 'name': 'bar'})\n\n"
|
||||
"should instead be written as\n\n"
|
||||
" >>> node_link_graph(data, target='foo', name='bar')\n\n"
|
||||
"in networkx 3.2.\n"
|
||||
"The default values of the keywords will not change.\n"
|
||||
)
|
||||
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
||||
|
||||
source = attrs.get("source", "source")
|
||||
target = attrs.get("target", "target")
|
||||
name = attrs.get("name", "name")
|
||||
key = attrs.get("key", "key")
|
||||
link = attrs.get("link", "links")
|
||||
# -------------------------------------------------- #
|
||||
multigraph = data.get("multigraph", multigraph)
|
||||
directed = data.get("directed", directed)
|
||||
if multigraph:
|
||||
graph = nx.MultiGraph()
|
||||
else:
|
||||
graph = nx.Graph()
|
||||
if directed:
|
||||
graph = graph.to_directed()
|
||||
|
||||
# Allow 'key' to be omitted from attrs if the graph is not a multigraph.
|
||||
key = None if not multigraph else key
|
||||
graph.graph = data.get("graph", {})
|
||||
c = count()
|
||||
for d in data["nodes"]:
|
||||
node = _to_tuple(d.get(name, next(c)))
|
||||
nodedata = {str(k): v for k, v in d.items() if k != name}
|
||||
graph.add_node(node, **nodedata)
|
||||
for d in data[link]:
|
||||
src = tuple(d[source]) if isinstance(d[source], list) else d[source]
|
||||
tgt = tuple(d[target]) if isinstance(d[target], list) else d[target]
|
||||
if not multigraph:
|
||||
edgedata = {str(k): v for k, v in d.items() if k != source and k != target}
|
||||
graph.add_edge(src, tgt, **edgedata)
|
||||
else:
|
||||
ky = d.get(key, None)
|
||||
edgedata = {
|
||||
str(k): v
|
||||
for k, v in d.items()
|
||||
if k != source and k != target and k != key
|
||||
}
|
||||
graph.add_edge(src, tgt, ky, **edgedata)
|
||||
return graph
|
||||
0
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/__init__.py
vendored
Normal file
0
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/__init__.py
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
60
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_adjacency.py
vendored
Normal file
60
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_adjacency.py
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.readwrite.json_graph import adjacency_data, adjacency_graph
|
||||
|
||||
|
||||
class TestAdjacency:
|
||||
def test_graph(self):
|
||||
G = nx.path_graph(4)
|
||||
H = adjacency_graph(adjacency_data(G))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
def test_graph_attributes(self):
|
||||
G = nx.path_graph(4)
|
||||
G.add_node(1, color="red")
|
||||
G.add_edge(1, 2, width=7)
|
||||
G.graph["foo"] = "bar"
|
||||
G.graph[1] = "one"
|
||||
|
||||
H = adjacency_graph(adjacency_data(G))
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
|
||||
d = json.dumps(adjacency_data(G))
|
||||
H = adjacency_graph(json.loads(d))
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.graph[1] == "one"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
|
||||
def test_digraph(self):
|
||||
G = nx.DiGraph()
|
||||
nx.add_path(G, [1, 2, 3])
|
||||
H = adjacency_graph(adjacency_data(G))
|
||||
assert H.is_directed()
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
def test_multidigraph(self):
|
||||
G = nx.MultiDiGraph()
|
||||
nx.add_path(G, [1, 2, 3])
|
||||
H = adjacency_graph(adjacency_data(G))
|
||||
assert H.is_directed()
|
||||
assert H.is_multigraph()
|
||||
|
||||
def test_multigraph(self):
|
||||
G = nx.MultiGraph()
|
||||
G.add_edge(1, 2, key="first")
|
||||
G.add_edge(1, 2, key="second", color="blue")
|
||||
H = adjacency_graph(adjacency_data(G))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
assert H[1][2]["second"]["color"] == "blue"
|
||||
|
||||
def test_exception(self):
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G = nx.MultiDiGraph()
|
||||
attrs = {"id": "node", "key": "node"}
|
||||
adjacency_data(G, attrs)
|
||||
78
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_cytoscape.py
vendored
Normal file
78
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_cytoscape.py
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import copy
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.readwrite.json_graph import cytoscape_data, cytoscape_graph
|
||||
|
||||
|
||||
def test_graph():
|
||||
G = nx.path_graph(4)
|
||||
H = cytoscape_graph(cytoscape_data(G))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
|
||||
def test_input_data_is_not_modified_when_building_graph():
|
||||
G = nx.path_graph(4)
|
||||
input_data = cytoscape_data(G)
|
||||
orig_data = copy.deepcopy(input_data)
|
||||
# Ensure input is unmodified by cytoscape_graph (gh-4173)
|
||||
cytoscape_graph(input_data)
|
||||
assert input_data == orig_data
|
||||
|
||||
|
||||
def test_graph_attributes():
|
||||
G = nx.path_graph(4)
|
||||
G.add_node(1, color="red")
|
||||
G.add_edge(1, 2, width=7)
|
||||
G.graph["foo"] = "bar"
|
||||
G.graph[1] = "one"
|
||||
G.add_node(3, name="node", id="123")
|
||||
|
||||
H = cytoscape_graph(cytoscape_data(G))
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
assert H.nodes[3]["name"] == "node"
|
||||
assert H.nodes[3]["id"] == "123"
|
||||
|
||||
d = json.dumps(cytoscape_data(G))
|
||||
H = cytoscape_graph(json.loads(d))
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.graph[1] == "one"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
assert H.nodes[3]["name"] == "node"
|
||||
assert H.nodes[3]["id"] == "123"
|
||||
|
||||
|
||||
def test_digraph():
|
||||
G = nx.DiGraph()
|
||||
nx.add_path(G, [1, 2, 3])
|
||||
H = cytoscape_graph(cytoscape_data(G))
|
||||
assert H.is_directed()
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
|
||||
def test_multidigraph():
|
||||
G = nx.MultiDiGraph()
|
||||
nx.add_path(G, [1, 2, 3])
|
||||
H = cytoscape_graph(cytoscape_data(G))
|
||||
assert H.is_directed()
|
||||
assert H.is_multigraph()
|
||||
|
||||
|
||||
def test_multigraph():
|
||||
G = nx.MultiGraph()
|
||||
G.add_edge(1, 2, key="first")
|
||||
G.add_edge(1, 2, key="second", color="blue")
|
||||
H = cytoscape_graph(cytoscape_data(G))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
assert H[1][2]["second"]["color"] == "blue"
|
||||
|
||||
|
||||
def test_exception():
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G = nx.MultiDiGraph()
|
||||
cytoscape_data(G, name="foo", ident="foo")
|
||||
175
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_node_link.py
vendored
Normal file
175
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_node_link.py
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.readwrite.json_graph import node_link_data, node_link_graph
|
||||
|
||||
|
||||
# TODO: To be removed when signature change complete
|
||||
def test_attrs_deprecation(recwarn):
|
||||
G = nx.path_graph(3)
|
||||
|
||||
# No warnings when `attrs` kwarg not used
|
||||
data = node_link_data(G)
|
||||
H = node_link_graph(data)
|
||||
assert len(recwarn) == 0
|
||||
|
||||
# Future warning raised with `attrs` kwarg
|
||||
attrs = {
|
||||
"source": "source",
|
||||
"target": "target",
|
||||
"name": "id",
|
||||
"key": "key",
|
||||
"link": "links",
|
||||
}
|
||||
data = node_link_data(G, attrs=attrs)
|
||||
assert len(recwarn) == 1
|
||||
|
||||
recwarn.clear()
|
||||
H = node_link_graph(data, attrs=attrs)
|
||||
assert len(recwarn) == 1
|
||||
|
||||
|
||||
class TestNodeLink:
|
||||
# TODO: To be removed when signature change complete
|
||||
def test_custom_attrs_dep(self):
|
||||
G = nx.path_graph(4)
|
||||
G.add_node(1, color="red")
|
||||
G.add_edge(1, 2, width=7)
|
||||
G.graph[1] = "one"
|
||||
G.graph["foo"] = "bar"
|
||||
|
||||
attrs = {
|
||||
"source": "c_source",
|
||||
"target": "c_target",
|
||||
"name": "c_id",
|
||||
"key": "c_key",
|
||||
"link": "c_links",
|
||||
}
|
||||
|
||||
H = node_link_graph(
|
||||
node_link_data(G, attrs=attrs), multigraph=False, attrs=attrs
|
||||
)
|
||||
assert nx.is_isomorphic(G, H)
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
|
||||
# provide only a partial dictionary of keywords.
|
||||
# This is similar to an example in the doc string
|
||||
attrs = {
|
||||
"link": "c_links",
|
||||
"source": "c_source",
|
||||
"target": "c_target",
|
||||
}
|
||||
H = node_link_graph(
|
||||
node_link_data(G, attrs=attrs), multigraph=False, attrs=attrs
|
||||
)
|
||||
assert nx.is_isomorphic(G, H)
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
|
||||
# TODO: To be removed when signature change complete
|
||||
def test_exception_dep(self):
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G = nx.MultiDiGraph()
|
||||
attrs = {"name": "node", "source": "node", "target": "node", "key": "node"}
|
||||
node_link_data(G, attrs)
|
||||
|
||||
def test_graph(self):
|
||||
G = nx.path_graph(4)
|
||||
H = node_link_graph(node_link_data(G))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
def test_graph_attributes(self):
|
||||
G = nx.path_graph(4)
|
||||
G.add_node(1, color="red")
|
||||
G.add_edge(1, 2, width=7)
|
||||
G.graph[1] = "one"
|
||||
G.graph["foo"] = "bar"
|
||||
|
||||
H = node_link_graph(node_link_data(G))
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
|
||||
d = json.dumps(node_link_data(G))
|
||||
H = node_link_graph(json.loads(d))
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.graph["1"] == "one"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
|
||||
def test_digraph(self):
|
||||
G = nx.DiGraph()
|
||||
H = node_link_graph(node_link_data(G))
|
||||
assert H.is_directed()
|
||||
|
||||
def test_multigraph(self):
|
||||
G = nx.MultiGraph()
|
||||
G.add_edge(1, 2, key="first")
|
||||
G.add_edge(1, 2, key="second", color="blue")
|
||||
H = node_link_graph(node_link_data(G))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
assert H[1][2]["second"]["color"] == "blue"
|
||||
|
||||
def test_graph_with_tuple_nodes(self):
|
||||
G = nx.Graph()
|
||||
G.add_edge((0, 0), (1, 0), color=[255, 255, 0])
|
||||
d = node_link_data(G)
|
||||
dumped_d = json.dumps(d)
|
||||
dd = json.loads(dumped_d)
|
||||
H = node_link_graph(dd)
|
||||
assert H.nodes[(0, 0)] == G.nodes[(0, 0)]
|
||||
assert H[(0, 0)][(1, 0)]["color"] == [255, 255, 0]
|
||||
|
||||
def test_unicode_keys(self):
|
||||
q = "qualité"
|
||||
G = nx.Graph()
|
||||
G.add_node(1, **{q: q})
|
||||
s = node_link_data(G)
|
||||
output = json.dumps(s, ensure_ascii=False)
|
||||
data = json.loads(output)
|
||||
H = node_link_graph(data)
|
||||
assert H.nodes[1][q] == q
|
||||
|
||||
def test_exception(self):
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G = nx.MultiDiGraph()
|
||||
attrs = {"name": "node", "source": "node", "target": "node", "key": "node"}
|
||||
node_link_data(G, **attrs)
|
||||
|
||||
def test_string_ids(self):
|
||||
q = "qualité"
|
||||
G = nx.DiGraph()
|
||||
G.add_node("A")
|
||||
G.add_node(q)
|
||||
G.add_edge("A", q)
|
||||
data = node_link_data(G)
|
||||
assert data["links"][0]["source"] == "A"
|
||||
assert data["links"][0]["target"] == q
|
||||
H = node_link_graph(data)
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
def test_custom_attrs(self):
|
||||
G = nx.path_graph(4)
|
||||
G.add_node(1, color="red")
|
||||
G.add_edge(1, 2, width=7)
|
||||
G.graph[1] = "one"
|
||||
G.graph["foo"] = "bar"
|
||||
|
||||
attrs = {
|
||||
"source": "c_source",
|
||||
"target": "c_target",
|
||||
"name": "c_id",
|
||||
"key": "c_key",
|
||||
"link": "c_links",
|
||||
}
|
||||
|
||||
H = node_link_graph(node_link_data(G, **attrs), multigraph=False, **attrs)
|
||||
assert nx.is_isomorphic(G, H)
|
||||
assert H.graph["foo"] == "bar"
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
assert H[1][2]["width"] == 7
|
||||
48
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_tree.py
vendored
Normal file
48
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tests/test_tree.py
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.readwrite.json_graph import tree_data, tree_graph
|
||||
|
||||
|
||||
def test_graph():
|
||||
G = nx.DiGraph()
|
||||
G.add_nodes_from([1, 2, 3], color="red")
|
||||
G.add_edge(1, 2, foo=7)
|
||||
G.add_edge(1, 3, foo=10)
|
||||
G.add_edge(3, 4, foo=10)
|
||||
H = tree_graph(tree_data(G, 1))
|
||||
assert nx.is_isomorphic(G, H)
|
||||
|
||||
|
||||
def test_graph_attributes():
|
||||
G = nx.DiGraph()
|
||||
G.add_nodes_from([1, 2, 3], color="red")
|
||||
G.add_edge(1, 2, foo=7)
|
||||
G.add_edge(1, 3, foo=10)
|
||||
G.add_edge(3, 4, foo=10)
|
||||
H = tree_graph(tree_data(G, 1))
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
|
||||
d = json.dumps(tree_data(G, 1))
|
||||
H = tree_graph(json.loads(d))
|
||||
assert H.nodes[1]["color"] == "red"
|
||||
|
||||
|
||||
def test_exceptions():
|
||||
with pytest.raises(TypeError, match="is not a tree."):
|
||||
G = nx.complete_graph(3)
|
||||
tree_data(G, 0)
|
||||
with pytest.raises(TypeError, match="is not directed."):
|
||||
G = nx.path_graph(3)
|
||||
tree_data(G, 0)
|
||||
with pytest.raises(TypeError, match="is not weakly connected."):
|
||||
G = nx.path_graph(3, create_using=nx.DiGraph)
|
||||
G.add_edge(2, 0)
|
||||
G.add_node(3)
|
||||
tree_data(G, 0)
|
||||
with pytest.raises(nx.NetworkXError, match="must be different."):
|
||||
G = nx.MultiDiGraph()
|
||||
G.add_node(0)
|
||||
tree_data(G, 0, ident="node", children="node")
|
||||
138
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tree.py
vendored
Normal file
138
.CondaPkg/env/Lib/site-packages/networkx/readwrite/json_graph/tree.py
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
from itertools import chain
|
||||
|
||||
import networkx as nx
|
||||
|
||||
__all__ = ["tree_data", "tree_graph"]
|
||||
|
||||
|
||||
def tree_data(G, root, ident="id", children="children"):
|
||||
"""Returns data in tree format that is suitable for JSON serialization
|
||||
and use in Javascript documents.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
G must be an oriented tree
|
||||
|
||||
root : node
|
||||
The root of the tree
|
||||
|
||||
ident : string
|
||||
Attribute name for storing NetworkX-internal graph data. `ident` must
|
||||
have a different value than `children`. The default is 'id'.
|
||||
|
||||
children : string
|
||||
Attribute name for storing NetworkX-internal graph data. `children`
|
||||
must have a different value than `ident`. The default is 'children'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
data : dict
|
||||
A dictionary with node-link formatted data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If `children` and `ident` attributes are identical.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from networkx.readwrite import json_graph
|
||||
>>> G = nx.DiGraph([(1, 2)])
|
||||
>>> data = json_graph.tree_data(G, root=1)
|
||||
|
||||
To serialize with json
|
||||
|
||||
>>> import json
|
||||
>>> s = json.dumps(data)
|
||||
|
||||
Notes
|
||||
-----
|
||||
Node attributes are stored in this format but keys
|
||||
for attributes must be strings if you want to serialize with JSON.
|
||||
|
||||
Graph and edge attributes are not stored.
|
||||
|
||||
See Also
|
||||
--------
|
||||
tree_graph, node_link_data, adjacency_data
|
||||
"""
|
||||
if G.number_of_nodes() != G.number_of_edges() + 1:
|
||||
raise TypeError("G is not a tree.")
|
||||
if not G.is_directed():
|
||||
raise TypeError("G is not directed.")
|
||||
if not nx.is_weakly_connected(G):
|
||||
raise TypeError("G is not weakly connected.")
|
||||
|
||||
if ident == children:
|
||||
raise nx.NetworkXError("The values for `id` and `children` must be different.")
|
||||
|
||||
def add_children(n, G):
|
||||
nbrs = G[n]
|
||||
if len(nbrs) == 0:
|
||||
return []
|
||||
children_ = []
|
||||
for child in nbrs:
|
||||
d = dict(chain(G.nodes[child].items(), [(ident, child)]))
|
||||
c = add_children(child, G)
|
||||
if c:
|
||||
d[children] = c
|
||||
children_.append(d)
|
||||
return children_
|
||||
|
||||
data = dict(chain(G.nodes[root].items(), [(ident, root)]))
|
||||
data[children] = add_children(root, G)
|
||||
return data
|
||||
|
||||
|
||||
def tree_graph(data, ident="id", children="children"):
|
||||
"""Returns graph from tree data format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : dict
|
||||
Tree formatted graph data
|
||||
|
||||
ident : string
|
||||
Attribute name for storing NetworkX-internal graph data. `ident` must
|
||||
have a different value than `children`. The default is 'id'.
|
||||
|
||||
children : string
|
||||
Attribute name for storing NetworkX-internal graph data. `children`
|
||||
must have a different value than `ident`. The default is 'children'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX DiGraph
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from networkx.readwrite import json_graph
|
||||
>>> G = nx.DiGraph([(1, 2)])
|
||||
>>> data = json_graph.tree_data(G, root=1)
|
||||
>>> H = json_graph.tree_graph(data)
|
||||
|
||||
See Also
|
||||
--------
|
||||
tree_data, node_link_data, adjacency_data
|
||||
"""
|
||||
graph = nx.DiGraph()
|
||||
|
||||
def add_children(parent, children_):
|
||||
for data in children_:
|
||||
child = data[ident]
|
||||
graph.add_edge(parent, child)
|
||||
grandchildren = data.get(children, [])
|
||||
if grandchildren:
|
||||
add_children(child, grandchildren)
|
||||
nodedata = {
|
||||
str(k): v for k, v in data.items() if k != ident and k != children
|
||||
}
|
||||
graph.add_node(child, **nodedata)
|
||||
|
||||
root = data[ident]
|
||||
children_ = data.get(children, [])
|
||||
nodedata = {str(k): v for k, v in data.items() if k != ident and k != children}
|
||||
graph.add_node(root, **nodedata)
|
||||
add_children(root, children_)
|
||||
return graph
|
||||
106
.CondaPkg/env/Lib/site-packages/networkx/readwrite/leda.py
vendored
Normal file
106
.CondaPkg/env/Lib/site-packages/networkx/readwrite/leda.py
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Read graphs in LEDA format.
|
||||
|
||||
LEDA is a C++ class library for efficient data types and algorithms.
|
||||
|
||||
Format
|
||||
------
|
||||
See http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
|
||||
|
||||
"""
|
||||
# Original author: D. Eppstein, UC Irvine, August 12, 2003.
|
||||
# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain.
|
||||
|
||||
__all__ = ["read_leda", "parse_leda"]
|
||||
|
||||
import networkx as nx
|
||||
from networkx.exception import NetworkXError
|
||||
from networkx.utils import open_file
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
def read_leda(path, encoding="UTF-8"):
|
||||
"""Read graph in LEDA format from path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : file or string
|
||||
File or filename to read. Filenames ending in .gz or .bz2 will be
|
||||
uncompressed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
|
||||
Examples
|
||||
--------
|
||||
G=nx.read_leda('file.leda')
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
|
||||
"""
|
||||
lines = (line.decode(encoding) for line in path)
|
||||
G = parse_leda(lines)
|
||||
return G
|
||||
|
||||
|
||||
def parse_leda(lines):
|
||||
"""Read graph in LEDA format from string or iterable.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lines : string or iterable
|
||||
Data in LEDA format.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
|
||||
Examples
|
||||
--------
|
||||
G=nx.parse_leda(string)
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
|
||||
"""
|
||||
if isinstance(lines, str):
|
||||
lines = iter(lines.split("\n"))
|
||||
lines = iter(
|
||||
[
|
||||
line.rstrip("\n")
|
||||
for line in lines
|
||||
if not (line.startswith(("#", "\n")) or line == "")
|
||||
]
|
||||
)
|
||||
for i in range(3):
|
||||
next(lines)
|
||||
# Graph
|
||||
du = int(next(lines)) # -1=directed, -2=undirected
|
||||
if du == -1:
|
||||
G = nx.DiGraph()
|
||||
else:
|
||||
G = nx.Graph()
|
||||
|
||||
# Nodes
|
||||
n = int(next(lines)) # number of nodes
|
||||
node = {}
|
||||
for i in range(1, n + 1): # LEDA counts from 1 to n
|
||||
symbol = next(lines).rstrip().strip("|{}| ")
|
||||
if symbol == "":
|
||||
symbol = str(i) # use int if no label - could be trouble
|
||||
node[i] = symbol
|
||||
|
||||
G.add_nodes_from([s for i, s in node.items()])
|
||||
|
||||
# Edges
|
||||
m = int(next(lines)) # number of edges
|
||||
for i in range(m):
|
||||
try:
|
||||
s, t, reversal, label = next(lines).split()
|
||||
except BaseException as err:
|
||||
raise NetworkXError(f"Too few fields in LEDA.GRAPH edge {i+1}") from err
|
||||
# BEWARE: no handling of reversal edges
|
||||
G.add_edge(node[int(s)], node[int(t)], label=label[2:-2])
|
||||
return G
|
||||
391
.CondaPkg/env/Lib/site-packages/networkx/readwrite/multiline_adjlist.py
vendored
Normal file
391
.CondaPkg/env/Lib/site-packages/networkx/readwrite/multiline_adjlist.py
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
"""
|
||||
*************************
|
||||
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
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
"generate_multiline_adjlist",
|
||||
"write_multiline_adjlist",
|
||||
"parse_multiline_adjlist",
|
||||
"read_multiline_adjlist",
|
||||
]
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import open_file
|
||||
|
||||
|
||||
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
|
||||
|
||||
Returns
|
||||
-------
|
||||
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():
|
||||
nbr_edges = [
|
||||
(u, data)
|
||||
for u, datadict in nbrs.items()
|
||||
for key, data in datadict.items()
|
||||
]
|
||||
deg = len(nbr_edges)
|
||||
yield str(s) + delimiter + str(deg)
|
||||
for u, d in nbr_edges:
|
||||
if d is None:
|
||||
yield str(u)
|
||||
else:
|
||||
yield str(u) + delimiter + str(d)
|
||||
else: # directed single edges
|
||||
for s, nbrs in G.adjacency():
|
||||
deg = len(nbrs)
|
||||
yield str(s) + delimiter + str(deg)
|
||||
for u, d in nbrs.items():
|
||||
if d is None:
|
||||
yield str(u)
|
||||
else:
|
||||
yield str(u) + delimiter + str(d)
|
||||
else: # undirected
|
||||
if G.is_multigraph():
|
||||
seen = set() # helper dict used to avoid duplicate edges
|
||||
for s, nbrs in G.adjacency():
|
||||
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 str(s) + delimiter + str(deg)
|
||||
for u, d in nbr_edges:
|
||||
if d is None:
|
||||
yield str(u)
|
||||
else:
|
||||
yield str(u) + delimiter + str(d)
|
||||
seen.add(s)
|
||||
else: # undirected single edges
|
||||
seen = set() # helper dict used to avoid duplicate edges
|
||||
for s, nbrs in G.adjacency():
|
||||
nbr_edges = [(u, d) for u, d in nbrs.items() if u not in seen]
|
||||
deg = len(nbr_edges)
|
||||
yield str(s) + delimiter + str(deg)
|
||||
for u, d in nbr_edges:
|
||||
if d is None:
|
||||
yield str(u)
|
||||
else:
|
||||
yield str(u) + delimiter + str(d)
|
||||
seen.add(s)
|
||||
|
||||
|
||||
@open_file(1, mode="wb")
|
||||
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
|
||||
|
||||
path : string or file
|
||||
Filename or file handle to write to.
|
||||
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_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
|
||||
|
||||
pargs = comments + " ".join(sys.argv)
|
||||
header = (
|
||||
f"{pargs}\n"
|
||||
+ comments
|
||||
+ f" GMT {time.asctime(time.gmtime())}\n"
|
||||
+ comments
|
||||
+ f" {G.name}\n"
|
||||
)
|
||||
path.write(header.encode(encoding))
|
||||
|
||||
for multiline in generate_multiline_adjlist(G, delimiter):
|
||||
multiline += "\n"
|
||||
path.write(multiline.encode(encoding))
|
||||
|
||||
|
||||
def parse_multiline_adjlist(
|
||||
lines, comments="#", delimiter=None, 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 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.
|
||||
|
||||
edgetype : Python type, optional
|
||||
Convert edges 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 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)
|
||||
>>> list(G)
|
||||
[1, 2, 3, 5]
|
||||
|
||||
"""
|
||||
from ast import literal_eval
|
||||
|
||||
G = nx.empty_graph(0, create_using)
|
||||
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 BaseException as err:
|
||||
raise TypeError(f"Failed to read node and degree on line ({line})") from err
|
||||
if nodetype is not None:
|
||||
try:
|
||||
u = nodetype(u)
|
||||
except BaseException as err:
|
||||
raise TypeError(
|
||||
f"Failed to convert node ({u}) to " f"type {nodetype}"
|
||||
) from err
|
||||
G.add_node(u)
|
||||
for i in range(deg):
|
||||
while True:
|
||||
try:
|
||||
line = next(lines)
|
||||
except StopIteration as err:
|
||||
msg = f"Failed to find neighbor for node ({u})"
|
||||
raise TypeError(msg) from err
|
||||
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 BaseException as err:
|
||||
raise TypeError(
|
||||
f"Failed to convert node ({v}) " f"to type {nodetype}"
|
||||
) from err
|
||||
if edgetype is not None:
|
||||
try:
|
||||
edgedata = {"weight": edgetype(data)}
|
||||
except BaseException as err:
|
||||
raise TypeError(
|
||||
f"Failed to convert edge data ({data}) " f"to type {edgetype}"
|
||||
) from err
|
||||
else:
|
||||
try: # try to evaluate
|
||||
edgedata = literal_eval(data)
|
||||
except:
|
||||
edgedata = {}
|
||||
G.add_edge(u, v, **edgedata)
|
||||
|
||||
return G
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
def read_multiline_adjlist(
|
||||
path,
|
||||
comments="#",
|
||||
delimiter=None,
|
||||
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 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.
|
||||
|
||||
edgetype : Python type, optional
|
||||
Convert edge data 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
|
||||
|
||||
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
|
||||
"""
|
||||
lines = (line.decode(encoding) for line in path)
|
||||
return parse_multiline_adjlist(
|
||||
lines,
|
||||
comments=comments,
|
||||
delimiter=delimiter,
|
||||
create_using=create_using,
|
||||
nodetype=nodetype,
|
||||
edgetype=edgetype,
|
||||
)
|
||||
102
.CondaPkg/env/Lib/site-packages/networkx/readwrite/p2g.py
vendored
Normal file
102
.CondaPkg/env/Lib/site-packages/networkx/readwrite/p2g.py
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
This module provides the following: read and write of p2g format
|
||||
used in metabolic pathway studies.
|
||||
|
||||
See https://web.archive.org/web/20080626113807/http://www.cs.purdue.edu/homes/koyuturk/pathway/ for a description.
|
||||
|
||||
The summary is included here:
|
||||
|
||||
A file that describes a uniquely labeled graph (with extension ".gr")
|
||||
format looks like the following:
|
||||
|
||||
|
||||
name
|
||||
3 4
|
||||
a
|
||||
1 2
|
||||
b
|
||||
|
||||
c
|
||||
0 2
|
||||
|
||||
"name" is simply a description of what the graph corresponds to. The
|
||||
second line displays the number of nodes and number of edges,
|
||||
respectively. This sample graph contains three nodes labeled "a", "b",
|
||||
and "c". The rest of the graph contains two lines for each node. The
|
||||
first line for a node contains the node label. After the declaration
|
||||
of the node label, the out-edges of that node in the graph are
|
||||
provided. For instance, "a" is linked to nodes 1 and 2, which are
|
||||
labeled "b" and "c", while the node labeled "b" has no outgoing
|
||||
edges. Observe that node labeled "c" has an outgoing edge to
|
||||
itself. Indeed, self-loops are allowed. Node index starts from 0.
|
||||
|
||||
"""
|
||||
import networkx
|
||||
from networkx.utils import open_file
|
||||
|
||||
|
||||
@open_file(1, mode="w")
|
||||
def write_p2g(G, path, encoding="utf-8"):
|
||||
"""Write NetworkX graph in p2g format.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This format is meant to be used with directed graphs with
|
||||
possible self loops.
|
||||
"""
|
||||
path.write((f"{G.name}\n").encode(encoding))
|
||||
path.write((f"{G.order()} {G.size()}\n").encode(encoding))
|
||||
nodes = list(G)
|
||||
# make dictionary mapping nodes to integers
|
||||
nodenumber = dict(zip(nodes, range(len(nodes))))
|
||||
for n in nodes:
|
||||
path.write((f"{n}\n").encode(encoding))
|
||||
for nbr in G.neighbors(n):
|
||||
path.write((f"{nodenumber[nbr]} ").encode(encoding))
|
||||
path.write("\n".encode(encoding))
|
||||
|
||||
|
||||
@open_file(0, mode="r")
|
||||
def read_p2g(path, encoding="utf-8"):
|
||||
"""Read graph in p2g format from path.
|
||||
|
||||
Returns
|
||||
-------
|
||||
MultiDiGraph
|
||||
|
||||
Notes
|
||||
-----
|
||||
If you want a DiGraph (with no self loops allowed and no edge data)
|
||||
use D=networkx.DiGraph(read_p2g(path))
|
||||
"""
|
||||
lines = (line.decode(encoding) for line in path)
|
||||
G = parse_p2g(lines)
|
||||
return G
|
||||
|
||||
|
||||
def parse_p2g(lines):
|
||||
"""Parse p2g format graph from string or iterable.
|
||||
|
||||
Returns
|
||||
-------
|
||||
MultiDiGraph
|
||||
"""
|
||||
description = next(lines).strip()
|
||||
# are multiedges (parallel edges) allowed?
|
||||
G = networkx.MultiDiGraph(name=description, selfloops=True)
|
||||
nnodes, nedges = map(int, next(lines).split())
|
||||
nodelabel = {}
|
||||
nbrs = {}
|
||||
# loop over the nodes keeping track of node labels and out neighbors
|
||||
# defer adding edges until all node labels are known
|
||||
for i in range(nnodes):
|
||||
n = next(lines).strip()
|
||||
nodelabel[i] = n
|
||||
G.add_node(n)
|
||||
nbrs[n] = map(int, next(lines).split())
|
||||
# now we know all of the node labels so we can add the edges
|
||||
# with the correct labels
|
||||
for n in G:
|
||||
for nbr in nbrs[n]:
|
||||
G.add_edge(n, nodelabel[nbr])
|
||||
return G
|
||||
284
.CondaPkg/env/Lib/site-packages/networkx/readwrite/pajek.py
vendored
Normal file
284
.CondaPkg/env/Lib/site-packages/networkx/readwrite/pajek.py
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
"""
|
||||
*****
|
||||
Pajek
|
||||
*****
|
||||
Read graphs in Pajek format.
|
||||
|
||||
This implementation handles directed and undirected graphs including
|
||||
those with self loops and parallel edges.
|
||||
|
||||
Format
|
||||
------
|
||||
See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm
|
||||
for format information.
|
||||
|
||||
"""
|
||||
|
||||
import warnings
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import open_file
|
||||
|
||||
__all__ = ["read_pajek", "parse_pajek", "generate_pajek", "write_pajek"]
|
||||
|
||||
|
||||
def generate_pajek(G):
|
||||
"""Generate lines in Pajek graph format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : graph
|
||||
A Networkx graph
|
||||
|
||||
References
|
||||
----------
|
||||
See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm
|
||||
for format information.
|
||||
"""
|
||||
if G.name == "":
|
||||
name = "NetworkX"
|
||||
else:
|
||||
name = G.name
|
||||
# Apparently many Pajek format readers can't process this line
|
||||
# So we'll leave it out for now.
|
||||
# yield '*network %s'%name
|
||||
|
||||
# write nodes with attributes
|
||||
yield f"*vertices {G.order()}"
|
||||
nodes = list(G)
|
||||
# make dictionary mapping nodes to integers
|
||||
nodenumber = dict(zip(nodes, range(1, len(nodes) + 1)))
|
||||
for n in nodes:
|
||||
# copy node attributes and pop mandatory attributes
|
||||
# to avoid duplication.
|
||||
na = G.nodes.get(n, {}).copy()
|
||||
x = na.pop("x", 0.0)
|
||||
y = na.pop("y", 0.0)
|
||||
try:
|
||||
id = int(na.pop("id", nodenumber[n]))
|
||||
except ValueError as err:
|
||||
err.args += (
|
||||
(
|
||||
"Pajek format requires 'id' to be an int()."
|
||||
" Refer to the 'Relabeling nodes' section."
|
||||
),
|
||||
)
|
||||
raise
|
||||
nodenumber[n] = id
|
||||
shape = na.pop("shape", "ellipse")
|
||||
s = " ".join(map(make_qstr, (id, n, x, y, shape)))
|
||||
# only optional attributes are left in na.
|
||||
for k, v in na.items():
|
||||
if isinstance(v, str) and v.strip() != "":
|
||||
s += f" {make_qstr(k)} {make_qstr(v)}"
|
||||
else:
|
||||
warnings.warn(
|
||||
f"Node attribute {k} is not processed. {('Empty attribute' if isinstance(v, str) else 'Non-string attribute')}."
|
||||
)
|
||||
yield s
|
||||
|
||||
# write edges with attributes
|
||||
if G.is_directed():
|
||||
yield "*arcs"
|
||||
else:
|
||||
yield "*edges"
|
||||
for u, v, edgedata in G.edges(data=True):
|
||||
d = edgedata.copy()
|
||||
value = d.pop("weight", 1.0) # use 1 as default edge value
|
||||
s = " ".join(map(make_qstr, (nodenumber[u], nodenumber[v], value)))
|
||||
for k, v in d.items():
|
||||
if isinstance(v, str) and v.strip() != "":
|
||||
s += f" {make_qstr(k)} {make_qstr(v)}"
|
||||
else:
|
||||
warnings.warn(
|
||||
f"Edge attribute {k} is not processed. {('Empty attribute' if isinstance(v, str) else 'Non-string attribute')}."
|
||||
)
|
||||
yield s
|
||||
|
||||
|
||||
@open_file(1, mode="wb")
|
||||
def write_pajek(G, path, encoding="UTF-8"):
|
||||
"""Write graph in Pajek format to path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : graph
|
||||
A Networkx graph
|
||||
path : file or string
|
||||
File or filename to write.
|
||||
Filenames ending in .gz or .bz2 will be compressed.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(4)
|
||||
>>> nx.write_pajek(G, "test.net")
|
||||
|
||||
Warnings
|
||||
--------
|
||||
Optional node attributes and edge attributes must be non-empty strings.
|
||||
Otherwise it will not be written into the file. You will need to
|
||||
convert those attributes to strings if you want to keep them.
|
||||
|
||||
References
|
||||
----------
|
||||
See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm
|
||||
for format information.
|
||||
"""
|
||||
for line in generate_pajek(G):
|
||||
line += "\n"
|
||||
path.write(line.encode(encoding))
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
def read_pajek(path, encoding="UTF-8"):
|
||||
"""Read graph in Pajek format from path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : file or string
|
||||
File or filename to write.
|
||||
Filenames ending in .gz or .bz2 will be uncompressed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX MultiGraph or MultiDiGraph.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(4)
|
||||
>>> nx.write_pajek(G, "test.net")
|
||||
>>> G = nx.read_pajek("test.net")
|
||||
|
||||
To create a Graph instead of a MultiGraph use
|
||||
|
||||
>>> G1 = nx.Graph(G)
|
||||
|
||||
References
|
||||
----------
|
||||
See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm
|
||||
for format information.
|
||||
"""
|
||||
lines = (line.decode(encoding) for line in path)
|
||||
return parse_pajek(lines)
|
||||
|
||||
|
||||
def parse_pajek(lines):
|
||||
"""Parse Pajek format graph from string or iterable.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lines : string or iterable
|
||||
Data in Pajek format.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : NetworkX graph
|
||||
|
||||
See Also
|
||||
--------
|
||||
read_pajek
|
||||
|
||||
"""
|
||||
import shlex
|
||||
|
||||
# multigraph=False
|
||||
if isinstance(lines, str):
|
||||
lines = iter(lines.split("\n"))
|
||||
lines = iter([line.rstrip("\n") for line in lines])
|
||||
G = nx.MultiDiGraph() # are multiedges allowed in Pajek? assume yes
|
||||
labels = [] # in the order of the file, needed for matrix
|
||||
while lines:
|
||||
try:
|
||||
l = next(lines)
|
||||
except: # EOF
|
||||
break
|
||||
if l.lower().startswith("*network"):
|
||||
try:
|
||||
label, name = l.split(None, 1)
|
||||
except ValueError:
|
||||
# Line was not of the form: *network NAME
|
||||
pass
|
||||
else:
|
||||
G.graph["name"] = name
|
||||
elif l.lower().startswith("*vertices"):
|
||||
nodelabels = {}
|
||||
l, nnodes = l.split()
|
||||
for i in range(int(nnodes)):
|
||||
l = next(lines)
|
||||
try:
|
||||
splitline = [
|
||||
x.decode("utf-8") for x in shlex.split(str(l).encode("utf-8"))
|
||||
]
|
||||
except AttributeError:
|
||||
splitline = shlex.split(str(l))
|
||||
id, label = splitline[0:2]
|
||||
labels.append(label)
|
||||
G.add_node(label)
|
||||
nodelabels[id] = label
|
||||
G.nodes[label]["id"] = id
|
||||
try:
|
||||
x, y, shape = splitline[2:5]
|
||||
G.nodes[label].update(
|
||||
{"x": float(x), "y": float(y), "shape": shape}
|
||||
)
|
||||
except:
|
||||
pass
|
||||
extra_attr = zip(splitline[5::2], splitline[6::2])
|
||||
G.nodes[label].update(extra_attr)
|
||||
elif l.lower().startswith("*edges") or l.lower().startswith("*arcs"):
|
||||
if l.lower().startswith("*edge"):
|
||||
# switch from multidigraph to multigraph
|
||||
G = nx.MultiGraph(G)
|
||||
if l.lower().startswith("*arcs"):
|
||||
# switch to directed with multiple arcs for each existing edge
|
||||
G = G.to_directed()
|
||||
for l in lines:
|
||||
try:
|
||||
splitline = [
|
||||
x.decode("utf-8") for x in shlex.split(str(l).encode("utf-8"))
|
||||
]
|
||||
except AttributeError:
|
||||
splitline = shlex.split(str(l))
|
||||
|
||||
if len(splitline) < 2:
|
||||
continue
|
||||
ui, vi = splitline[0:2]
|
||||
u = nodelabels.get(ui, ui)
|
||||
v = nodelabels.get(vi, vi)
|
||||
# parse the data attached to this edge and put in a dictionary
|
||||
edge_data = {}
|
||||
try:
|
||||
# there should always be a single value on the edge?
|
||||
w = splitline[2:3]
|
||||
edge_data.update({"weight": float(w[0])})
|
||||
except:
|
||||
pass
|
||||
# if there isn't, just assign a 1
|
||||
# edge_data.update({'value':1})
|
||||
extra_attr = zip(splitline[3::2], splitline[4::2])
|
||||
edge_data.update(extra_attr)
|
||||
# if G.has_edge(u,v):
|
||||
# multigraph=True
|
||||
G.add_edge(u, v, **edge_data)
|
||||
elif l.lower().startswith("*matrix"):
|
||||
G = nx.DiGraph(G)
|
||||
adj_list = (
|
||||
(labels[row], labels[col], {"weight": int(data)})
|
||||
for (row, line) in enumerate(lines)
|
||||
for (col, data) in enumerate(line.split())
|
||||
if int(data) != 0
|
||||
)
|
||||
G.add_edges_from(adj_list)
|
||||
|
||||
return G
|
||||
|
||||
|
||||
def make_qstr(t):
|
||||
"""Returns the string representation of t.
|
||||
Add outer double-quotes if the string has a space.
|
||||
"""
|
||||
if not isinstance(t, str):
|
||||
t = str(t)
|
||||
if " " in t:
|
||||
t = f'"{t}"'
|
||||
return t
|
||||
374
.CondaPkg/env/Lib/site-packages/networkx/readwrite/sparse6.py
vendored
Normal file
374
.CondaPkg/env/Lib/site-packages/networkx/readwrite/sparse6.py
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
# Original author: D. Eppstein, UC Irvine, August 12, 2003.
|
||||
# The original code at https://www.ics.uci.edu/~eppstein/PADS/ is public domain.
|
||||
"""Functions for reading and writing graphs in the *sparse6* format.
|
||||
|
||||
The *sparse6* file format is a space-efficient format for large sparse
|
||||
graphs. For small graphs or large dense graphs, use the *graph6* file
|
||||
format.
|
||||
|
||||
For more information, see the `sparse6`_ homepage.
|
||||
|
||||
.. _sparse6: https://users.cecs.anu.edu.au/~bdm/data/formats.html
|
||||
|
||||
"""
|
||||
import networkx as nx
|
||||
from networkx.exception import NetworkXError
|
||||
from networkx.readwrite.graph6 import data_to_n, n_to_data
|
||||
from networkx.utils import not_implemented_for, open_file
|
||||
|
||||
__all__ = ["from_sparse6_bytes", "read_sparse6", "to_sparse6_bytes", "write_sparse6"]
|
||||
|
||||
|
||||
def _generate_sparse6_bytes(G, nodes, header):
|
||||
"""Yield bytes in the sparse6 encoding of a graph.
|
||||
|
||||
`G` is an undirected simple graph. `nodes` is the list of nodes for
|
||||
which the node-induced subgraph will be encoded; if `nodes` is the
|
||||
list of all nodes in the graph, the entire graph will be
|
||||
encoded. `header` is a Boolean that specifies whether to generate
|
||||
the header ``b'>>sparse6<<'`` before the remaining data.
|
||||
|
||||
This function generates `bytes` objects in the following order:
|
||||
|
||||
1. the header (if requested),
|
||||
2. the encoding of the number of nodes,
|
||||
3. each character, one-at-a-time, in the encoding of the requested
|
||||
node-induced subgraph,
|
||||
4. a newline character.
|
||||
|
||||
This function raises :exc:`ValueError` if the graph is too large for
|
||||
the graph6 format (that is, greater than ``2 ** 36`` nodes).
|
||||
|
||||
"""
|
||||
n = len(G)
|
||||
if n >= 2**36:
|
||||
raise ValueError(
|
||||
"sparse6 is only defined if number of nodes is less " "than 2 ** 36"
|
||||
)
|
||||
if header:
|
||||
yield b">>sparse6<<"
|
||||
yield b":"
|
||||
for d in n_to_data(n):
|
||||
yield str.encode(chr(d + 63))
|
||||
|
||||
k = 1
|
||||
while 1 << k < n:
|
||||
k += 1
|
||||
|
||||
def enc(x):
|
||||
"""Big endian k-bit encoding of x"""
|
||||
return [1 if (x & 1 << (k - 1 - i)) else 0 for i in range(k)]
|
||||
|
||||
edges = sorted((max(u, v), min(u, v)) for u, v in G.edges())
|
||||
bits = []
|
||||
curv = 0
|
||||
for v, u in edges:
|
||||
if v == curv: # current vertex edge
|
||||
bits.append(0)
|
||||
bits.extend(enc(u))
|
||||
elif v == curv + 1: # next vertex edge
|
||||
curv += 1
|
||||
bits.append(1)
|
||||
bits.extend(enc(u))
|
||||
else: # skip to vertex v and then add edge to u
|
||||
curv = v
|
||||
bits.append(1)
|
||||
bits.extend(enc(v))
|
||||
bits.append(0)
|
||||
bits.extend(enc(u))
|
||||
if k < 6 and n == (1 << k) and ((-len(bits)) % 6) >= k and curv < (n - 1):
|
||||
# Padding special case: small k, n=2^k,
|
||||
# more than k bits of padding needed,
|
||||
# current vertex is not (n-1) --
|
||||
# appending 1111... would add a loop on (n-1)
|
||||
bits.append(0)
|
||||
bits.extend([1] * ((-len(bits)) % 6))
|
||||
else:
|
||||
bits.extend([1] * ((-len(bits)) % 6))
|
||||
|
||||
data = [
|
||||
(bits[i + 0] << 5)
|
||||
+ (bits[i + 1] << 4)
|
||||
+ (bits[i + 2] << 3)
|
||||
+ (bits[i + 3] << 2)
|
||||
+ (bits[i + 4] << 1)
|
||||
+ (bits[i + 5] << 0)
|
||||
for i in range(0, len(bits), 6)
|
||||
]
|
||||
|
||||
for d in data:
|
||||
yield str.encode(chr(d + 63))
|
||||
yield b"\n"
|
||||
|
||||
|
||||
def from_sparse6_bytes(string):
|
||||
"""Read an undirected graph in sparse6 format from string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
string : string
|
||||
Data in sparse6 format
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : Graph
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the string is unable to be parsed in sparse6 format
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.from_sparse6_bytes(b":A_")
|
||||
>>> sorted(G.edges())
|
||||
[(0, 1), (0, 1), (0, 1)]
|
||||
|
||||
See Also
|
||||
--------
|
||||
read_sparse6, write_sparse6
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Sparse6 specification
|
||||
<https://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
if string.startswith(b">>sparse6<<"):
|
||||
string = string[11:]
|
||||
if not string.startswith(b":"):
|
||||
raise NetworkXError("Expected leading colon in sparse6")
|
||||
|
||||
chars = [c - 63 for c in string[1:]]
|
||||
n, data = data_to_n(chars)
|
||||
k = 1
|
||||
while 1 << k < n:
|
||||
k += 1
|
||||
|
||||
def parseData():
|
||||
"""Returns stream of pairs b[i], x[i] for sparse6 format."""
|
||||
chunks = iter(data)
|
||||
d = None # partial data word
|
||||
dLen = 0 # how many unparsed bits are left in d
|
||||
|
||||
while 1:
|
||||
if dLen < 1:
|
||||
try:
|
||||
d = next(chunks)
|
||||
except StopIteration:
|
||||
return
|
||||
dLen = 6
|
||||
dLen -= 1
|
||||
b = (d >> dLen) & 1 # grab top remaining bit
|
||||
|
||||
x = d & ((1 << dLen) - 1) # partially built up value of x
|
||||
xLen = dLen # how many bits included so far in x
|
||||
while xLen < k: # now grab full chunks until we have enough
|
||||
try:
|
||||
d = next(chunks)
|
||||
except StopIteration:
|
||||
return
|
||||
dLen = 6
|
||||
x = (x << 6) + d
|
||||
xLen += 6
|
||||
x = x >> (xLen - k) # shift back the extra bits
|
||||
dLen = xLen - k
|
||||
yield b, x
|
||||
|
||||
v = 0
|
||||
|
||||
G = nx.MultiGraph()
|
||||
G.add_nodes_from(range(n))
|
||||
|
||||
multigraph = False
|
||||
for b, x in parseData():
|
||||
if b == 1:
|
||||
v += 1
|
||||
# padding with ones can cause overlarge number here
|
||||
if x >= n or v >= n:
|
||||
break
|
||||
elif x > v:
|
||||
v = x
|
||||
else:
|
||||
if G.has_edge(x, v):
|
||||
multigraph = True
|
||||
G.add_edge(x, v)
|
||||
if not multigraph:
|
||||
G = nx.Graph(G)
|
||||
return G
|
||||
|
||||
|
||||
def to_sparse6_bytes(G, nodes=None, header=True):
|
||||
"""Convert an undirected graph to bytes in sparse6 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : Graph (undirected)
|
||||
|
||||
nodes: list or iterable
|
||||
Nodes are labeled 0...n-1 in the order provided. If None the ordering
|
||||
given by ``G.nodes()`` is used.
|
||||
|
||||
header: bool
|
||||
If True add '>>sparse6<<' bytes to head of data.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXNotImplemented
|
||||
If the graph is directed.
|
||||
|
||||
ValueError
|
||||
If the graph has at least ``2 ** 36`` nodes; the sparse6 format
|
||||
is only defined for graphs of order less than ``2 ** 36``.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> nx.to_sparse6_bytes(nx.path_graph(2))
|
||||
b'>>sparse6<<:An\\n'
|
||||
|
||||
See Also
|
||||
--------
|
||||
to_sparse6_bytes, read_sparse6, write_sparse6_bytes
|
||||
|
||||
Notes
|
||||
-----
|
||||
The returned bytes end with a newline character.
|
||||
|
||||
The format does not support edge or node labels.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Graph6 specification
|
||||
<https://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
if nodes is not None:
|
||||
G = G.subgraph(nodes)
|
||||
G = nx.convert_node_labels_to_integers(G, ordering="sorted")
|
||||
return b"".join(_generate_sparse6_bytes(G, nodes, header))
|
||||
|
||||
|
||||
@open_file(0, mode="rb")
|
||||
def read_sparse6(path):
|
||||
"""Read an undirected graph in sparse6 format from path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : file or string
|
||||
File or filename to write.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : Graph/Multigraph or list of Graphs/MultiGraphs
|
||||
If the file contains multiple lines then a list of graphs is returned
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the string is unable to be parsed in sparse6 format
|
||||
|
||||
Examples
|
||||
--------
|
||||
You can read a sparse6 file by giving the path to the file::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
... _ = f.write(b">>sparse6<<:An\\n")
|
||||
... _ = f.seek(0)
|
||||
... G = nx.read_sparse6(f.name)
|
||||
>>> list(G.edges())
|
||||
[(0, 1)]
|
||||
|
||||
You can also read a sparse6 file by giving an open file-like object::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile() as f:
|
||||
... _ = f.write(b">>sparse6<<:An\\n")
|
||||
... _ = f.seek(0)
|
||||
... G = nx.read_sparse6(f)
|
||||
>>> list(G.edges())
|
||||
[(0, 1)]
|
||||
|
||||
See Also
|
||||
--------
|
||||
read_sparse6, from_sparse6_bytes
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Sparse6 specification
|
||||
<https://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
glist = []
|
||||
for line in path:
|
||||
line = line.strip()
|
||||
if not len(line):
|
||||
continue
|
||||
glist.append(from_sparse6_bytes(line))
|
||||
if len(glist) == 1:
|
||||
return glist[0]
|
||||
else:
|
||||
return glist
|
||||
|
||||
|
||||
@not_implemented_for("directed")
|
||||
@open_file(1, mode="wb")
|
||||
def write_sparse6(G, path, nodes=None, header=True):
|
||||
"""Write graph G to given path in sparse6 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : Graph (undirected)
|
||||
|
||||
path : file or string
|
||||
File or filename to write
|
||||
|
||||
nodes: list or iterable
|
||||
Nodes are labeled 0...n-1 in the order provided. If None the ordering
|
||||
given by G.nodes() is used.
|
||||
|
||||
header: bool
|
||||
If True add '>>sparse6<<' string to head of data
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If the graph is directed
|
||||
|
||||
Examples
|
||||
--------
|
||||
You can write a sparse6 file by giving the path to the file::
|
||||
|
||||
>>> import tempfile
|
||||
>>> with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
... nx.write_sparse6(nx.path_graph(2), f.name)
|
||||
... print(f.read())
|
||||
b'>>sparse6<<:An\\n'
|
||||
|
||||
You can also write a sparse6 file by giving an open file-like object::
|
||||
|
||||
>>> with tempfile.NamedTemporaryFile() as f:
|
||||
... nx.write_sparse6(nx.path_graph(2), f)
|
||||
... _ = f.seek(0)
|
||||
... print(f.read())
|
||||
b'>>sparse6<<:An\\n'
|
||||
|
||||
See Also
|
||||
--------
|
||||
read_sparse6, from_sparse6_bytes
|
||||
|
||||
Notes
|
||||
-----
|
||||
The format does not support edge or node labels.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Sparse6 specification
|
||||
<https://users.cecs.anu.edu.au/~bdm/data/formats.html>
|
||||
|
||||
"""
|
||||
if nodes is not None:
|
||||
G = G.subgraph(nodes)
|
||||
G = nx.convert_node_labels_to_integers(G, ordering="sorted")
|
||||
for b in _generate_sparse6_bytes(G, nodes, header):
|
||||
path.write(b)
|
||||
0
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__init__.py
vendored
Normal file
0
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__init__.py
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_adjlist.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_adjlist.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_edgelist.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_edgelist.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_gexf.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_gexf.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_gml.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_gml.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_graph6.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_graph6.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_graphml.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_graphml.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_leda.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_leda.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_p2g.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_p2g.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_pajek.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_pajek.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_sparse6.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_sparse6.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_text.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/__pycache__/test_text.cpython-311.pyc
vendored
Normal file
Binary file not shown.
268
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_adjlist.py
vendored
Normal file
268
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_adjlist.py
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
"""
|
||||
Unit tests for adjlist.
|
||||
"""
|
||||
import io
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
||||
|
||||
|
||||
class TestAdjlist:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.Graph(name="test")
|
||||
e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")]
|
||||
cls.G.add_edges_from(e)
|
||||
cls.G.add_node("g")
|
||||
cls.DG = nx.DiGraph(cls.G)
|
||||
cls.XG = nx.MultiGraph()
|
||||
cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)])
|
||||
cls.XDG = nx.MultiDiGraph(cls.XG)
|
||||
|
||||
def test_read_multiline_adjlist_1(self):
|
||||
# Unit test for https://networkx.lanl.gov/trac/ticket/252
|
||||
s = b"""# comment line
|
||||
1 2
|
||||
# comment line
|
||||
2
|
||||
3
|
||||
"""
|
||||
bytesIO = io.BytesIO(s)
|
||||
G = nx.read_multiline_adjlist(bytesIO)
|
||||
adj = {"1": {"3": {}, "2": {}}, "3": {"1": {}}, "2": {"1": {}}}
|
||||
assert graphs_equal(G, nx.Graph(adj))
|
||||
|
||||
def test_unicode(self):
|
||||
G = nx.Graph()
|
||||
name1 = chr(2344) + chr(123) + chr(6543)
|
||||
name2 = chr(5543) + chr(1543) + chr(324)
|
||||
G.add_edge(name1, "Radiohead", **{name2: 3})
|
||||
fd, fname = tempfile.mkstemp()
|
||||
nx.write_multiline_adjlist(G, fname)
|
||||
H = nx.read_multiline_adjlist(fname)
|
||||
assert graphs_equal(G, H)
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_latin1_err(self):
|
||||
G = nx.Graph()
|
||||
name1 = chr(2344) + chr(123) + chr(6543)
|
||||
name2 = chr(5543) + chr(1543) + chr(324)
|
||||
G.add_edge(name1, "Radiohead", **{name2: 3})
|
||||
fd, fname = tempfile.mkstemp()
|
||||
pytest.raises(
|
||||
UnicodeEncodeError, nx.write_multiline_adjlist, G, fname, encoding="latin-1"
|
||||
)
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_latin1(self):
|
||||
G = nx.Graph()
|
||||
name1 = "Bj" + chr(246) + "rk"
|
||||
name2 = chr(220) + "ber"
|
||||
G.add_edge(name1, "Radiohead", **{name2: 3})
|
||||
fd, fname = tempfile.mkstemp()
|
||||
nx.write_multiline_adjlist(G, fname, encoding="latin-1")
|
||||
H = nx.read_multiline_adjlist(fname, encoding="latin-1")
|
||||
assert graphs_equal(G, H)
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_parse_adjlist(self):
|
||||
lines = ["1 2 5", "2 3 4", "3 5", "4", "5"]
|
||||
nx.parse_adjlist(lines, nodetype=int) # smoke test
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_adjlist(lines, nodetype="int")
|
||||
lines = ["1 2 5", "2 b", "c"]
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_adjlist(lines, nodetype=int)
|
||||
|
||||
def test_adjlist_graph(self):
|
||||
G = self.G
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_adjlist(G, fname)
|
||||
H = nx.read_adjlist(fname)
|
||||
H2 = nx.read_adjlist(fname)
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_adjlist_digraph(self):
|
||||
G = self.DG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_adjlist(G, fname)
|
||||
H = nx.read_adjlist(fname, create_using=nx.DiGraph())
|
||||
H2 = nx.read_adjlist(fname, create_using=nx.DiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_adjlist_integers(self):
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
G = nx.convert_node_labels_to_integers(self.G)
|
||||
nx.write_adjlist(G, fname)
|
||||
H = nx.read_adjlist(fname, nodetype=int)
|
||||
H2 = nx.read_adjlist(fname, nodetype=int)
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_adjlist_multigraph(self):
|
||||
G = self.XG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_adjlist(G, fname)
|
||||
H = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiGraph())
|
||||
H2 = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_adjlist_multidigraph(self):
|
||||
G = self.XDG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_adjlist(G, fname)
|
||||
H = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiDiGraph())
|
||||
H2 = nx.read_adjlist(fname, nodetype=int, create_using=nx.MultiDiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_adjlist_delimiter(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.path_graph(3)
|
||||
nx.write_adjlist(G, fh, delimiter=":")
|
||||
fh.seek(0)
|
||||
H = nx.read_adjlist(fh, nodetype=int, delimiter=":")
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
|
||||
|
||||
class TestMultilineAdjlist:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.Graph(name="test")
|
||||
e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")]
|
||||
cls.G.add_edges_from(e)
|
||||
cls.G.add_node("g")
|
||||
cls.DG = nx.DiGraph(cls.G)
|
||||
cls.DG.remove_edge("b", "a")
|
||||
cls.DG.remove_edge("b", "c")
|
||||
cls.XG = nx.MultiGraph()
|
||||
cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)])
|
||||
cls.XDG = nx.MultiDiGraph(cls.XG)
|
||||
|
||||
def test_parse_multiline_adjlist(self):
|
||||
lines = [
|
||||
"1 2",
|
||||
"b {'weight':3, 'name': 'Frodo'}",
|
||||
"c {}",
|
||||
"d 1",
|
||||
"e {'weight':6, 'name': 'Saruman'}",
|
||||
]
|
||||
nx.parse_multiline_adjlist(iter(lines)) # smoke test
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_multiline_adjlist(iter(lines), nodetype=int)
|
||||
nx.parse_multiline_adjlist(iter(lines), edgetype=str) # smoke test
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_multiline_adjlist(iter(lines), nodetype=int)
|
||||
lines = ["1 a"]
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_multiline_adjlist(iter(lines))
|
||||
lines = ["a 2"]
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_multiline_adjlist(iter(lines), nodetype=int)
|
||||
lines = ["1 2"]
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_multiline_adjlist(iter(lines))
|
||||
lines = ["1 2", "2 {}"]
|
||||
with pytest.raises(TypeError):
|
||||
nx.parse_multiline_adjlist(iter(lines))
|
||||
|
||||
def test_multiline_adjlist_graph(self):
|
||||
G = self.G
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_multiline_adjlist(G, fname)
|
||||
H = nx.read_multiline_adjlist(fname)
|
||||
H2 = nx.read_multiline_adjlist(fname)
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_multiline_adjlist_digraph(self):
|
||||
G = self.DG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_multiline_adjlist(G, fname)
|
||||
H = nx.read_multiline_adjlist(fname, create_using=nx.DiGraph())
|
||||
H2 = nx.read_multiline_adjlist(fname, create_using=nx.DiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_multiline_adjlist_integers(self):
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
G = nx.convert_node_labels_to_integers(self.G)
|
||||
nx.write_multiline_adjlist(G, fname)
|
||||
H = nx.read_multiline_adjlist(fname, nodetype=int)
|
||||
H2 = nx.read_multiline_adjlist(fname, nodetype=int)
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_multiline_adjlist_multigraph(self):
|
||||
G = self.XG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_multiline_adjlist(G, fname)
|
||||
H = nx.read_multiline_adjlist(fname, nodetype=int, create_using=nx.MultiGraph())
|
||||
H2 = nx.read_multiline_adjlist(
|
||||
fname, nodetype=int, create_using=nx.MultiGraph()
|
||||
)
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_multiline_adjlist_multidigraph(self):
|
||||
G = self.XDG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_multiline_adjlist(G, fname)
|
||||
H = nx.read_multiline_adjlist(
|
||||
fname, nodetype=int, create_using=nx.MultiDiGraph()
|
||||
)
|
||||
H2 = nx.read_multiline_adjlist(
|
||||
fname, nodetype=int, create_using=nx.MultiDiGraph()
|
||||
)
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_multiline_adjlist_delimiter(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.path_graph(3)
|
||||
nx.write_multiline_adjlist(G, fh, delimiter=":")
|
||||
fh.seek(0)
|
||||
H = nx.read_multiline_adjlist(fh, nodetype=int, delimiter=":")
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
314
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_edgelist.py
vendored
Normal file
314
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_edgelist.py
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
"""
|
||||
Unit tests for edgelists.
|
||||
"""
|
||||
import io
|
||||
import os
|
||||
import tempfile
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
||||
|
||||
edges_no_data = textwrap.dedent(
|
||||
"""
|
||||
# comment line
|
||||
1 2
|
||||
# comment line
|
||||
2 3
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
edges_with_values = textwrap.dedent(
|
||||
"""
|
||||
# comment line
|
||||
1 2 2.0
|
||||
# comment line
|
||||
2 3 3.0
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
edges_with_weight = textwrap.dedent(
|
||||
"""
|
||||
# comment line
|
||||
1 2 {'weight':2.0}
|
||||
# comment line
|
||||
2 3 {'weight':3.0}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
edges_with_multiple_attrs = textwrap.dedent(
|
||||
"""
|
||||
# comment line
|
||||
1 2 {'weight':2.0, 'color':'green'}
|
||||
# comment line
|
||||
2 3 {'weight':3.0, 'color':'red'}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
edges_with_multiple_attrs_csv = textwrap.dedent(
|
||||
"""
|
||||
# comment line
|
||||
1, 2, {'weight':2.0, 'color':'green'}
|
||||
# comment line
|
||||
2, 3, {'weight':3.0, 'color':'red'}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
_expected_edges_weights = [(1, 2, {"weight": 2.0}), (2, 3, {"weight": 3.0})]
|
||||
_expected_edges_multiattr = [
|
||||
(1, 2, {"weight": 2.0, "color": "green"}),
|
||||
(2, 3, {"weight": 3.0, "color": "red"}),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("data", "extra_kwargs"),
|
||||
(
|
||||
(edges_no_data, {}),
|
||||
(edges_with_values, {}),
|
||||
(edges_with_weight, {}),
|
||||
(edges_with_multiple_attrs, {}),
|
||||
(edges_with_multiple_attrs_csv, {"delimiter": ","}),
|
||||
),
|
||||
)
|
||||
def test_read_edgelist_no_data(data, extra_kwargs):
|
||||
bytesIO = io.BytesIO(data.encode("utf-8"))
|
||||
G = nx.read_edgelist(bytesIO, nodetype=int, data=False, **extra_kwargs)
|
||||
assert edges_equal(G.edges(), [(1, 2), (2, 3)])
|
||||
|
||||
|
||||
def test_read_weighted_edgelist():
|
||||
bytesIO = io.BytesIO(edges_with_values.encode("utf-8"))
|
||||
G = nx.read_weighted_edgelist(bytesIO, nodetype=int)
|
||||
assert edges_equal(G.edges(data=True), _expected_edges_weights)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("data", "extra_kwargs", "expected"),
|
||||
(
|
||||
(edges_with_weight, {}, _expected_edges_weights),
|
||||
(edges_with_multiple_attrs, {}, _expected_edges_multiattr),
|
||||
(edges_with_multiple_attrs_csv, {"delimiter": ","}, _expected_edges_multiattr),
|
||||
),
|
||||
)
|
||||
def test_read_edgelist_with_data(data, extra_kwargs, expected):
|
||||
bytesIO = io.BytesIO(data.encode("utf-8"))
|
||||
G = nx.read_edgelist(bytesIO, nodetype=int, **extra_kwargs)
|
||||
assert edges_equal(G.edges(data=True), expected)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def example_graph():
|
||||
G = nx.Graph()
|
||||
G.add_weighted_edges_from([(1, 2, 3.0), (2, 3, 27.0), (3, 4, 3.0)])
|
||||
return G
|
||||
|
||||
|
||||
def test_parse_edgelist_no_data(example_graph):
|
||||
G = example_graph
|
||||
H = nx.parse_edgelist(["1 2", "2 3", "3 4"], nodetype=int)
|
||||
assert nodes_equal(G.nodes, H.nodes)
|
||||
assert edges_equal(G.edges, H.edges)
|
||||
|
||||
|
||||
def test_parse_edgelist_with_data_dict(example_graph):
|
||||
G = example_graph
|
||||
H = nx.parse_edgelist(
|
||||
["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"], nodetype=int
|
||||
)
|
||||
assert nodes_equal(G.nodes, H.nodes)
|
||||
assert edges_equal(G.edges(data=True), H.edges(data=True))
|
||||
|
||||
|
||||
def test_parse_edgelist_with_data_list(example_graph):
|
||||
G = example_graph
|
||||
H = nx.parse_edgelist(
|
||||
["1 2 3", "2 3 27", "3 4 3.0"], nodetype=int, data=(("weight", float),)
|
||||
)
|
||||
assert nodes_equal(G.nodes, H.nodes)
|
||||
assert edges_equal(G.edges(data=True), H.edges(data=True))
|
||||
|
||||
|
||||
def test_parse_edgelist():
|
||||
# ignore lines with less than 2 nodes
|
||||
lines = ["1;2", "2 3", "3 4"]
|
||||
G = nx.parse_edgelist(lines, nodetype=int)
|
||||
assert list(G.edges()) == [(2, 3), (3, 4)]
|
||||
# unknown nodetype
|
||||
with pytest.raises(TypeError, match="Failed to convert nodes"):
|
||||
lines = ["1 2", "2 3", "3 4"]
|
||||
nx.parse_edgelist(lines, nodetype="nope")
|
||||
# lines have invalid edge format
|
||||
with pytest.raises(TypeError, match="Failed to convert edge data"):
|
||||
lines = ["1 2 3", "2 3", "3 4"]
|
||||
nx.parse_edgelist(lines, nodetype=int)
|
||||
# edge data and data_keys not the same length
|
||||
with pytest.raises(IndexError, match="not the same length"):
|
||||
lines = ["1 2 3", "2 3 27", "3 4 3.0"]
|
||||
nx.parse_edgelist(
|
||||
lines, nodetype=int, data=(("weight", float), ("capacity", int))
|
||||
)
|
||||
# edge data can't be converted to edge type
|
||||
with pytest.raises(TypeError, match="Failed to convert"):
|
||||
lines = ["1 2 't1'", "2 3 't3'", "3 4 't3'"]
|
||||
nx.parse_edgelist(lines, nodetype=int, data=(("weight", float),))
|
||||
|
||||
|
||||
def test_comments_None():
|
||||
edgelist = ["node#1 node#2", "node#2 node#3"]
|
||||
# comments=None supported to ignore all comment characters
|
||||
G = nx.parse_edgelist(edgelist, comments=None)
|
||||
H = nx.Graph([e.split(" ") for e in edgelist])
|
||||
assert edges_equal(G.edges, H.edges)
|
||||
|
||||
|
||||
class TestEdgelist:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.Graph(name="test")
|
||||
e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")]
|
||||
cls.G.add_edges_from(e)
|
||||
cls.G.add_node("g")
|
||||
cls.DG = nx.DiGraph(cls.G)
|
||||
cls.XG = nx.MultiGraph()
|
||||
cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)])
|
||||
cls.XDG = nx.MultiDiGraph(cls.XG)
|
||||
|
||||
def test_write_edgelist_1(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.Graph()
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
nx.write_edgelist(G, fh, data=False)
|
||||
fh.seek(0)
|
||||
assert fh.read() == b"1 2\n2 3\n"
|
||||
|
||||
def test_write_edgelist_2(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.Graph()
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
nx.write_edgelist(G, fh, data=True)
|
||||
fh.seek(0)
|
||||
assert fh.read() == b"1 2 {}\n2 3 {}\n"
|
||||
|
||||
def test_write_edgelist_3(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.Graph()
|
||||
G.add_edge(1, 2, weight=2.0)
|
||||
G.add_edge(2, 3, weight=3.0)
|
||||
nx.write_edgelist(G, fh, data=True)
|
||||
fh.seek(0)
|
||||
assert fh.read() == b"1 2 {'weight': 2.0}\n2 3 {'weight': 3.0}\n"
|
||||
|
||||
def test_write_edgelist_4(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.Graph()
|
||||
G.add_edge(1, 2, weight=2.0)
|
||||
G.add_edge(2, 3, weight=3.0)
|
||||
nx.write_edgelist(G, fh, data=[("weight")])
|
||||
fh.seek(0)
|
||||
assert fh.read() == b"1 2 2.0\n2 3 3.0\n"
|
||||
|
||||
def test_unicode(self):
|
||||
G = nx.Graph()
|
||||
name1 = chr(2344) + chr(123) + chr(6543)
|
||||
name2 = chr(5543) + chr(1543) + chr(324)
|
||||
G.add_edge(name1, "Radiohead", **{name2: 3})
|
||||
fd, fname = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname)
|
||||
H = nx.read_edgelist(fname)
|
||||
assert graphs_equal(G, H)
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_latin1_issue(self):
|
||||
G = nx.Graph()
|
||||
name1 = chr(2344) + chr(123) + chr(6543)
|
||||
name2 = chr(5543) + chr(1543) + chr(324)
|
||||
G.add_edge(name1, "Radiohead", **{name2: 3})
|
||||
fd, fname = tempfile.mkstemp()
|
||||
pytest.raises(
|
||||
UnicodeEncodeError, nx.write_edgelist, G, fname, encoding="latin-1"
|
||||
)
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_latin1(self):
|
||||
G = nx.Graph()
|
||||
name1 = "Bj" + chr(246) + "rk"
|
||||
name2 = chr(220) + "ber"
|
||||
G.add_edge(name1, "Radiohead", **{name2: 3})
|
||||
fd, fname = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname, encoding="latin-1")
|
||||
H = nx.read_edgelist(fname, encoding="latin-1")
|
||||
assert graphs_equal(G, H)
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_edgelist_graph(self):
|
||||
G = self.G
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname)
|
||||
H = nx.read_edgelist(fname)
|
||||
H2 = nx.read_edgelist(fname)
|
||||
assert H is not H2 # they should be different graphs
|
||||
G.remove_node("g") # isolated nodes are not written in edgelist
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_edgelist_digraph(self):
|
||||
G = self.DG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname)
|
||||
H = nx.read_edgelist(fname, create_using=nx.DiGraph())
|
||||
H2 = nx.read_edgelist(fname, create_using=nx.DiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
G.remove_node("g") # isolated nodes are not written in edgelist
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_edgelist_integers(self):
|
||||
G = nx.convert_node_labels_to_integers(self.G)
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname)
|
||||
H = nx.read_edgelist(fname, nodetype=int)
|
||||
# isolated nodes are not written in edgelist
|
||||
G.remove_nodes_from(list(nx.isolates(G)))
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_edgelist_multigraph(self):
|
||||
G = self.XG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname)
|
||||
H = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph())
|
||||
H2 = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_edgelist_multidigraph(self):
|
||||
G = self.XDG
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
nx.write_edgelist(G, fname)
|
||||
H = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiDiGraph())
|
||||
H2 = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiDiGraph())
|
||||
assert H is not H2 # they should be different graphs
|
||||
assert nodes_equal(list(H), list(G))
|
||||
assert edges_equal(list(H.edges()), list(G.edges()))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
557
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_gexf.py
vendored
Normal file
557
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_gexf.py
vendored
Normal file
@@ -0,0 +1,557 @@
|
||||
import io
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class TestGEXF:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.simple_directed_data = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
||||
<graph mode="static" defaultedgetype="directed">
|
||||
<nodes>
|
||||
<node id="0" label="Hello" />
|
||||
<node id="1" label="Word" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1" />
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
cls.simple_directed_graph = nx.DiGraph()
|
||||
cls.simple_directed_graph.add_node("0", label="Hello")
|
||||
cls.simple_directed_graph.add_node("1", label="World")
|
||||
cls.simple_directed_graph.add_edge("0", "1", id="0")
|
||||
|
||||
cls.simple_directed_fh = io.BytesIO(cls.simple_directed_data.encode("UTF-8"))
|
||||
|
||||
cls.attribute_data = """<?xml version="1.0" encoding="UTF-8"?>\
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" xmlns:xsi="http://www.w3.\
|
||||
org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gexf.net/\
|
||||
1.2draft http://www.gexf.net/1.2draft/gexf.xsd" version="1.2">
|
||||
<meta lastmodifieddate="2009-03-20">
|
||||
<creator>Gephi.org</creator>
|
||||
<description>A Web network</description>
|
||||
</meta>
|
||||
<graph defaultedgetype="directed">
|
||||
<attributes class="node">
|
||||
<attribute id="0" title="url" type="string"/>
|
||||
<attribute id="1" title="indegree" type="integer"/>
|
||||
<attribute id="2" title="frog" type="boolean">
|
||||
<default>true</default>
|
||||
</attribute>
|
||||
</attributes>
|
||||
<nodes>
|
||||
<node id="0" label="Gephi">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="https://gephi.org"/>
|
||||
<attvalue for="1" value="1"/>
|
||||
<attvalue for="2" value="false"/>
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="1" label="Webatlas">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="http://webatlas.fr"/>
|
||||
<attvalue for="1" value="2"/>
|
||||
<attvalue for="2" value="false"/>
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="2" label="RTGI">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="http://rtgi.fr"/>
|
||||
<attvalue for="1" value="1"/>
|
||||
<attvalue for="2" value="true"/>
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="3" label="BarabasiLab">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="http://barabasilab.com"/>
|
||||
<attvalue for="1" value="1"/>
|
||||
<attvalue for="2" value="true"/>
|
||||
</attvalues>
|
||||
</node>
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1" label="foo"/>
|
||||
<edge id="1" source="0" target="2"/>
|
||||
<edge id="2" source="1" target="0"/>
|
||||
<edge id="3" source="2" target="1"/>
|
||||
<edge id="4" source="0" target="3"/>
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
cls.attribute_graph = nx.DiGraph()
|
||||
cls.attribute_graph.graph["node_default"] = {"frog": True}
|
||||
cls.attribute_graph.add_node(
|
||||
"0", label="Gephi", url="https://gephi.org", indegree=1, frog=False
|
||||
)
|
||||
cls.attribute_graph.add_node(
|
||||
"1", label="Webatlas", url="http://webatlas.fr", indegree=2, frog=False
|
||||
)
|
||||
cls.attribute_graph.add_node(
|
||||
"2", label="RTGI", url="http://rtgi.fr", indegree=1, frog=True
|
||||
)
|
||||
cls.attribute_graph.add_node(
|
||||
"3",
|
||||
label="BarabasiLab",
|
||||
url="http://barabasilab.com",
|
||||
indegree=1,
|
||||
frog=True,
|
||||
)
|
||||
cls.attribute_graph.add_edge("0", "1", id="0", label="foo")
|
||||
cls.attribute_graph.add_edge("0", "2", id="1")
|
||||
cls.attribute_graph.add_edge("1", "0", id="2")
|
||||
cls.attribute_graph.add_edge("2", "1", id="3")
|
||||
cls.attribute_graph.add_edge("0", "3", id="4")
|
||||
cls.attribute_fh = io.BytesIO(cls.attribute_data.encode("UTF-8"))
|
||||
|
||||
cls.simple_undirected_data = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
|
||||
<graph mode="static" defaultedgetype="undirected">
|
||||
<nodes>
|
||||
<node id="0" label="Hello" />
|
||||
<node id="1" label="Word" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1" />
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
cls.simple_undirected_graph = nx.Graph()
|
||||
cls.simple_undirected_graph.add_node("0", label="Hello")
|
||||
cls.simple_undirected_graph.add_node("1", label="World")
|
||||
cls.simple_undirected_graph.add_edge("0", "1", id="0")
|
||||
|
||||
cls.simple_undirected_fh = io.BytesIO(
|
||||
cls.simple_undirected_data.encode("UTF-8")
|
||||
)
|
||||
|
||||
def test_read_simple_directed_graphml(self):
|
||||
G = self.simple_directed_graph
|
||||
H = nx.read_gexf(self.simple_directed_fh)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(G.edges()) == sorted(H.edges())
|
||||
assert sorted(G.edges(data=True)) == sorted(H.edges(data=True))
|
||||
self.simple_directed_fh.seek(0)
|
||||
|
||||
def test_write_read_simple_directed_graphml(self):
|
||||
G = self.simple_directed_graph
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(G.edges()) == sorted(H.edges())
|
||||
assert sorted(G.edges(data=True)) == sorted(H.edges(data=True))
|
||||
self.simple_directed_fh.seek(0)
|
||||
|
||||
def test_read_simple_undirected_graphml(self):
|
||||
G = self.simple_undirected_graph
|
||||
H = nx.read_gexf(self.simple_undirected_fh)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
self.simple_undirected_fh.seek(0)
|
||||
|
||||
def test_read_attribute_graphml(self):
|
||||
G = self.attribute_graph
|
||||
H = nx.read_gexf(self.attribute_fh)
|
||||
assert sorted(G.nodes(True)) == sorted(H.nodes(data=True))
|
||||
ge = sorted(G.edges(data=True))
|
||||
he = sorted(H.edges(data=True))
|
||||
for a, b in zip(ge, he):
|
||||
assert a == b
|
||||
self.attribute_fh.seek(0)
|
||||
|
||||
def test_directed_edge_in_undirected(self):
|
||||
s = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" version='1.2'>
|
||||
<graph mode="static" defaultedgetype="undirected" name="">
|
||||
<nodes>
|
||||
<node id="0" label="Hello" />
|
||||
<node id="1" label="Word" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1" type="directed"/>
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
fh = io.BytesIO(s.encode("UTF-8"))
|
||||
pytest.raises(nx.NetworkXError, nx.read_gexf, fh)
|
||||
|
||||
def test_undirected_edge_in_directed(self):
|
||||
s = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" version='1.2'>
|
||||
<graph mode="static" defaultedgetype="directed" name="">
|
||||
<nodes>
|
||||
<node id="0" label="Hello" />
|
||||
<node id="1" label="Word" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1" type="undirected"/>
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
fh = io.BytesIO(s.encode("UTF-8"))
|
||||
pytest.raises(nx.NetworkXError, nx.read_gexf, fh)
|
||||
|
||||
def test_key_raises(self):
|
||||
s = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" version='1.2'>
|
||||
<graph mode="static" defaultedgetype="directed" name="">
|
||||
<nodes>
|
||||
<node id="0" label="Hello">
|
||||
<attvalues>
|
||||
<attvalue for='0' value='1'/>
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="1" label="Word" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1" type="undirected"/>
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
fh = io.BytesIO(s.encode("UTF-8"))
|
||||
pytest.raises(nx.NetworkXError, nx.read_gexf, fh)
|
||||
|
||||
def test_relabel(self):
|
||||
s = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns="http://www.gexf.net/1.2draft" version='1.2'>
|
||||
<graph mode="static" defaultedgetype="directed" name="">
|
||||
<nodes>
|
||||
<node id="0" label="Hello" />
|
||||
<node id="1" label="Word" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge id="0" source="0" target="1"/>
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
||||
"""
|
||||
fh = io.BytesIO(s.encode("UTF-8"))
|
||||
G = nx.read_gexf(fh, relabel=True)
|
||||
assert sorted(G.nodes()) == ["Hello", "Word"]
|
||||
|
||||
def test_default_attribute(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(1, label="1", color="green")
|
||||
nx.add_path(G, [0, 1, 2, 3])
|
||||
G.add_edge(1, 2, foo=3)
|
||||
G.graph["node_default"] = {"color": "yellow"}
|
||||
G.graph["edge_default"] = {"foo": 7}
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
# Reading a gexf graph always sets mode attribute to either
|
||||
# 'static' or 'dynamic'. Remove the mode attribute from the
|
||||
# read graph for the sake of comparing remaining attributes.
|
||||
del H.graph["mode"]
|
||||
assert G.graph == H.graph
|
||||
|
||||
def test_serialize_ints_to_strings(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(1, id=7, label=77)
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert list(H) == [7]
|
||||
assert H.nodes[7]["label"] == "77"
|
||||
|
||||
def test_write_with_node_attributes(self):
|
||||
# Addresses #673.
|
||||
G = nx.Graph()
|
||||
G.add_edges_from([(0, 1), (1, 2), (2, 3)])
|
||||
for i in range(4):
|
||||
G.nodes[i]["id"] = i
|
||||
G.nodes[i]["label"] = i
|
||||
G.nodes[i]["pid"] = i
|
||||
G.nodes[i]["start"] = i
|
||||
G.nodes[i]["end"] = i + 1
|
||||
|
||||
expected = f"""<gexf xmlns="http://www.gexf.net/1.2draft" xmlns:xsi\
|
||||
="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=\
|
||||
"http://www.gexf.net/1.2draft http://www.gexf.net/1.2draft/\
|
||||
gexf.xsd" version="1.2">
|
||||
<meta lastmodifieddate="{time.strftime('%Y-%m-%d')}">
|
||||
<creator>NetworkX {nx.__version__}</creator>
|
||||
</meta>
|
||||
<graph defaultedgetype="undirected" mode="dynamic" name="" timeformat="long">
|
||||
<nodes>
|
||||
<node id="0" label="0" pid="0" start="0" end="1" />
|
||||
<node id="1" label="1" pid="1" start="1" end="2" />
|
||||
<node id="2" label="2" pid="2" start="2" end="3" />
|
||||
<node id="3" label="3" pid="3" start="3" end="4" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge source="0" target="1" id="0" />
|
||||
<edge source="1" target="2" id="1" />
|
||||
<edge source="2" target="3" id="2" />
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>"""
|
||||
obtained = "\n".join(nx.generate_gexf(G))
|
||||
assert expected == obtained
|
||||
|
||||
def test_edge_id_construct(self):
|
||||
G = nx.Graph()
|
||||
G.add_edges_from([(0, 1, {"id": 0}), (1, 2, {"id": 2}), (2, 3)])
|
||||
|
||||
expected = f"""<gexf xmlns="http://www.gexf.net/1.2draft" xmlns:xsi\
|
||||
="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.\
|
||||
gexf.net/1.2draft http://www.gexf.net/1.2draft/gexf.xsd" version="1.2">
|
||||
<meta lastmodifieddate="{time.strftime('%Y-%m-%d')}">
|
||||
<creator>NetworkX {nx.__version__}</creator>
|
||||
</meta>
|
||||
<graph defaultedgetype="undirected" mode="static" name="">
|
||||
<nodes>
|
||||
<node id="0" label="0" />
|
||||
<node id="1" label="1" />
|
||||
<node id="2" label="2" />
|
||||
<node id="3" label="3" />
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge source="0" target="1" id="0" />
|
||||
<edge source="1" target="2" id="2" />
|
||||
<edge source="2" target="3" id="1" />
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>"""
|
||||
|
||||
obtained = "\n".join(nx.generate_gexf(G))
|
||||
assert expected == obtained
|
||||
|
||||
def test_numpy_type(self):
|
||||
np = pytest.importorskip("numpy")
|
||||
G = nx.path_graph(4)
|
||||
nx.set_node_attributes(G, {n: n for n in np.arange(4)}, "number")
|
||||
G[0][1]["edge-number"] = np.float64(1.1)
|
||||
|
||||
expected = f"""<gexf xmlns="http://www.gexf.net/1.2draft"\
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation\
|
||||
="http://www.gexf.net/1.2draft http://www.gexf.net/1.2draft/gexf.xsd"\
|
||||
version="1.2">
|
||||
<meta lastmodifieddate="{time.strftime('%Y-%m-%d')}">
|
||||
<creator>NetworkX {nx.__version__}</creator>
|
||||
</meta>
|
||||
<graph defaultedgetype="undirected" mode="static" name="">
|
||||
<attributes mode="static" class="edge">
|
||||
<attribute id="1" title="edge-number" type="float" />
|
||||
</attributes>
|
||||
<attributes mode="static" class="node">
|
||||
<attribute id="0" title="number" type="int" />
|
||||
</attributes>
|
||||
<nodes>
|
||||
<node id="0" label="0">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="0" />
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="1" label="1">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="1" />
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="2" label="2">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="2" />
|
||||
</attvalues>
|
||||
</node>
|
||||
<node id="3" label="3">
|
||||
<attvalues>
|
||||
<attvalue for="0" value="3" />
|
||||
</attvalues>
|
||||
</node>
|
||||
</nodes>
|
||||
<edges>
|
||||
<edge source="0" target="1" id="0">
|
||||
<attvalues>
|
||||
<attvalue for="1" value="1.1" />
|
||||
</attvalues>
|
||||
</edge>
|
||||
<edge source="1" target="2" id="1" />
|
||||
<edge source="2" target="3" id="2" />
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>"""
|
||||
obtained = "\n".join(nx.generate_gexf(G))
|
||||
assert expected == obtained
|
||||
|
||||
def test_bool(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(1, testattr=True)
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert H.nodes[1]["testattr"]
|
||||
|
||||
# Test for NaN, INF and -INF
|
||||
def test_specials(self):
|
||||
from math import isnan
|
||||
|
||||
inf, nan = float("inf"), float("nan")
|
||||
G = nx.Graph()
|
||||
G.add_node(1, testattr=inf, strdata="inf", key="a")
|
||||
G.add_node(2, testattr=nan, strdata="nan", key="b")
|
||||
G.add_node(3, testattr=-inf, strdata="-inf", key="c")
|
||||
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
filetext = fh.read()
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
|
||||
assert b"INF" in filetext
|
||||
assert b"NaN" in filetext
|
||||
assert b"-INF" in filetext
|
||||
|
||||
assert H.nodes[1]["testattr"] == inf
|
||||
assert isnan(H.nodes[2]["testattr"])
|
||||
assert H.nodes[3]["testattr"] == -inf
|
||||
|
||||
assert H.nodes[1]["strdata"] == "inf"
|
||||
assert H.nodes[2]["strdata"] == "nan"
|
||||
assert H.nodes[3]["strdata"] == "-inf"
|
||||
|
||||
assert H.nodes[1]["networkx_key"] == "a"
|
||||
assert H.nodes[2]["networkx_key"] == "b"
|
||||
assert H.nodes[3]["networkx_key"] == "c"
|
||||
|
||||
def test_simple_list(self):
|
||||
G = nx.Graph()
|
||||
list_value = [(1, 2, 3), (9, 1, 2)]
|
||||
G.add_node(1, key=list_value)
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert H.nodes[1]["networkx_key"] == list_value
|
||||
|
||||
def test_dynamic_mode(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(1, label="1", color="green")
|
||||
G.graph["mode"] = "dynamic"
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
|
||||
def test_multigraph_with_missing_attributes(self):
|
||||
G = nx.MultiGraph()
|
||||
G.add_node(0, label="1", color="green")
|
||||
G.add_node(1, label="2", color="green")
|
||||
G.add_edge(0, 1, id="0", weight=3, type="undirected", start=0, end=1)
|
||||
G.add_edge(0, 1, id="1", label="foo", start=0, end=1)
|
||||
G.add_edge(0, 1)
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
|
||||
def test_missing_viz_attributes(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(0, label="1", color="green")
|
||||
G.nodes[0]["viz"] = {"size": 54}
|
||||
G.nodes[0]["viz"]["position"] = {"x": 0, "y": 1, "z": 0}
|
||||
G.nodes[0]["viz"]["color"] = {"r": 0, "g": 0, "b": 256}
|
||||
G.nodes[0]["viz"]["shape"] = "http://random.url"
|
||||
G.nodes[0]["viz"]["thickness"] = 2
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh, version="1.1draft")
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
|
||||
# Test missing alpha value for version >draft1.1 - set default alpha value
|
||||
# to 1.0 instead of `None` when writing for better general compatibility
|
||||
fh = io.BytesIO()
|
||||
# G.nodes[0]["viz"]["color"] does not have an alpha value explicitly defined
|
||||
# so the default is used instead
|
||||
nx.write_gexf(G, fh, version="1.2draft")
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert H.nodes[0]["viz"]["color"]["a"] == 1.0
|
||||
|
||||
# Second graph for the other branch
|
||||
G = nx.Graph()
|
||||
G.add_node(0, label="1", color="green")
|
||||
G.nodes[0]["viz"] = {"size": 54}
|
||||
G.nodes[0]["viz"]["position"] = {"x": 0, "y": 1, "z": 0}
|
||||
G.nodes[0]["viz"]["color"] = {"r": 0, "g": 0, "b": 256, "a": 0.5}
|
||||
G.nodes[0]["viz"]["shape"] = "ftp://random.url"
|
||||
G.nodes[0]["viz"]["thickness"] = 2
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
|
||||
def test_slice_and_spell(self):
|
||||
# Test spell first, so version = 1.2
|
||||
G = nx.Graph()
|
||||
G.add_node(0, label="1", color="green")
|
||||
G.nodes[0]["spells"] = [(1, 2)]
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
|
||||
G = nx.Graph()
|
||||
G.add_node(0, label="1", color="green")
|
||||
G.nodes[0]["slices"] = [(1, 2)]
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh, version="1.1draft")
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
|
||||
def test_add_parent(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(0, label="1", color="green", parents=[1, 2])
|
||||
fh = io.BytesIO()
|
||||
nx.write_gexf(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_gexf(fh, node_type=int)
|
||||
assert sorted(G.nodes()) == sorted(H.nodes())
|
||||
assert sorted(sorted(e) for e in G.edges()) == sorted(
|
||||
sorted(e) for e in H.edges()
|
||||
)
|
||||
730
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_gml.py
vendored
Normal file
730
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_gml.py
vendored
Normal file
@@ -0,0 +1,730 @@
|
||||
import codecs
|
||||
import io
|
||||
import math
|
||||
import os
|
||||
import tempfile
|
||||
from ast import literal_eval
|
||||
from contextlib import contextmanager
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.readwrite.gml import literal_destringizer, literal_stringizer
|
||||
|
||||
|
||||
class TestGraph:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.simple_data = """Creator "me"
|
||||
Version "xx"
|
||||
graph [
|
||||
comment "This is a sample graph"
|
||||
directed 1
|
||||
IsPlanar 1
|
||||
pos [ x 0 y 1 ]
|
||||
node [
|
||||
id 1
|
||||
label "Node 1"
|
||||
pos [ x 1 y 1 ]
|
||||
]
|
||||
node [
|
||||
id 2
|
||||
pos [ x 1 y 2 ]
|
||||
label "Node 2"
|
||||
]
|
||||
node [
|
||||
id 3
|
||||
label "Node 3"
|
||||
pos [ x 1 y 3 ]
|
||||
]
|
||||
edge [
|
||||
source 1
|
||||
target 2
|
||||
label "Edge from node 1 to node 2"
|
||||
color [line "blue" thickness 3]
|
||||
|
||||
]
|
||||
edge [
|
||||
source 2
|
||||
target 3
|
||||
label "Edge from node 2 to node 3"
|
||||
]
|
||||
edge [
|
||||
source 3
|
||||
target 1
|
||||
label "Edge from node 3 to node 1"
|
||||
]
|
||||
]
|
||||
"""
|
||||
|
||||
def test_parse_gml_cytoscape_bug(self):
|
||||
# example from issue #321, originally #324 in trac
|
||||
cytoscape_example = """
|
||||
Creator "Cytoscape"
|
||||
Version 1.0
|
||||
graph [
|
||||
node [
|
||||
root_index -3
|
||||
id -3
|
||||
graphics [
|
||||
x -96.0
|
||||
y -67.0
|
||||
w 40.0
|
||||
h 40.0
|
||||
fill "#ff9999"
|
||||
type "ellipse"
|
||||
outline "#666666"
|
||||
outline_width 1.5
|
||||
]
|
||||
label "node2"
|
||||
]
|
||||
node [
|
||||
root_index -2
|
||||
id -2
|
||||
graphics [
|
||||
x 63.0
|
||||
y 37.0
|
||||
w 40.0
|
||||
h 40.0
|
||||
fill "#ff9999"
|
||||
type "ellipse"
|
||||
outline "#666666"
|
||||
outline_width 1.5
|
||||
]
|
||||
label "node1"
|
||||
]
|
||||
node [
|
||||
root_index -1
|
||||
id -1
|
||||
graphics [
|
||||
x -31.0
|
||||
y -17.0
|
||||
w 40.0
|
||||
h 40.0
|
||||
fill "#ff9999"
|
||||
type "ellipse"
|
||||
outline "#666666"
|
||||
outline_width 1.5
|
||||
]
|
||||
label "node0"
|
||||
]
|
||||
edge [
|
||||
root_index -2
|
||||
target -2
|
||||
source -1
|
||||
graphics [
|
||||
width 1.5
|
||||
fill "#0000ff"
|
||||
type "line"
|
||||
Line [
|
||||
]
|
||||
source_arrow 0
|
||||
target_arrow 3
|
||||
]
|
||||
label "DirectedEdge"
|
||||
]
|
||||
edge [
|
||||
root_index -1
|
||||
target -1
|
||||
source -3
|
||||
graphics [
|
||||
width 1.5
|
||||
fill "#0000ff"
|
||||
type "line"
|
||||
Line [
|
||||
]
|
||||
source_arrow 0
|
||||
target_arrow 3
|
||||
]
|
||||
label "DirectedEdge"
|
||||
]
|
||||
]
|
||||
"""
|
||||
nx.parse_gml(cytoscape_example)
|
||||
|
||||
def test_parse_gml(self):
|
||||
G = nx.parse_gml(self.simple_data, label="label")
|
||||
assert sorted(G.nodes()) == ["Node 1", "Node 2", "Node 3"]
|
||||
assert sorted(G.edges()) == [
|
||||
("Node 1", "Node 2"),
|
||||
("Node 2", "Node 3"),
|
||||
("Node 3", "Node 1"),
|
||||
]
|
||||
|
||||
assert sorted(G.edges(data=True)) == [
|
||||
(
|
||||
"Node 1",
|
||||
"Node 2",
|
||||
{
|
||||
"color": {"line": "blue", "thickness": 3},
|
||||
"label": "Edge from node 1 to node 2",
|
||||
},
|
||||
),
|
||||
("Node 2", "Node 3", {"label": "Edge from node 2 to node 3"}),
|
||||
("Node 3", "Node 1", {"label": "Edge from node 3 to node 1"}),
|
||||
]
|
||||
|
||||
def test_read_gml(self):
|
||||
(fd, fname) = tempfile.mkstemp()
|
||||
fh = open(fname, "w")
|
||||
fh.write(self.simple_data)
|
||||
fh.close()
|
||||
Gin = nx.read_gml(fname, label="label")
|
||||
G = nx.parse_gml(self.simple_data, label="label")
|
||||
assert sorted(G.nodes(data=True)) == sorted(Gin.nodes(data=True))
|
||||
assert sorted(G.edges(data=True)) == sorted(Gin.edges(data=True))
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
def test_labels_are_strings(self):
|
||||
# GML requires labels to be strings (i.e., in quotes)
|
||||
answer = """graph [
|
||||
node [
|
||||
id 0
|
||||
label "1203"
|
||||
]
|
||||
]"""
|
||||
G = nx.Graph()
|
||||
G.add_node(1203)
|
||||
data = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer))
|
||||
assert data == answer
|
||||
|
||||
def test_relabel_duplicate(self):
|
||||
data = """
|
||||
graph
|
||||
[
|
||||
label ""
|
||||
directed 1
|
||||
node
|
||||
[
|
||||
id 0
|
||||
label "same"
|
||||
]
|
||||
node
|
||||
[
|
||||
id 1
|
||||
label "same"
|
||||
]
|
||||
]
|
||||
"""
|
||||
fh = io.BytesIO(data.encode("UTF-8"))
|
||||
fh.seek(0)
|
||||
pytest.raises(nx.NetworkXError, nx.read_gml, fh, label="label")
|
||||
|
||||
def test_tuplelabels(self):
|
||||
# https://github.com/networkx/networkx/pull/1048
|
||||
# Writing tuple labels to GML failed.
|
||||
G = nx.Graph()
|
||||
G.add_edge((0, 1), (1, 0))
|
||||
data = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer))
|
||||
answer = """graph [
|
||||
node [
|
||||
id 0
|
||||
label "(0,1)"
|
||||
]
|
||||
node [
|
||||
id 1
|
||||
label "(1,0)"
|
||||
]
|
||||
edge [
|
||||
source 0
|
||||
target 1
|
||||
]
|
||||
]"""
|
||||
assert data == answer
|
||||
|
||||
def test_quotes(self):
|
||||
# https://github.com/networkx/networkx/issues/1061
|
||||
# Encoding quotes as HTML entities.
|
||||
G = nx.path_graph(1)
|
||||
G.name = "path_graph(1)"
|
||||
attr = 'This is "quoted" and this is a copyright: ' + chr(169)
|
||||
G.nodes[0]["demo"] = attr
|
||||
fobj = tempfile.NamedTemporaryFile()
|
||||
nx.write_gml(G, fobj)
|
||||
fobj.seek(0)
|
||||
# Should be bytes in 2.x and 3.x
|
||||
data = fobj.read().strip().decode("ascii")
|
||||
answer = """graph [
|
||||
name "path_graph(1)"
|
||||
node [
|
||||
id 0
|
||||
label "0"
|
||||
demo "This is "quoted" and this is a copyright: ©"
|
||||
]
|
||||
]"""
|
||||
assert data == answer
|
||||
|
||||
def test_unicode_node(self):
|
||||
node = "node" + chr(169)
|
||||
G = nx.Graph()
|
||||
G.add_node(node)
|
||||
fobj = tempfile.NamedTemporaryFile()
|
||||
nx.write_gml(G, fobj)
|
||||
fobj.seek(0)
|
||||
# Should be bytes in 2.x and 3.x
|
||||
data = fobj.read().strip().decode("ascii")
|
||||
answer = """graph [
|
||||
node [
|
||||
id 0
|
||||
label "node©"
|
||||
]
|
||||
]"""
|
||||
assert data == answer
|
||||
|
||||
def test_float_label(self):
|
||||
node = 1.0
|
||||
G = nx.Graph()
|
||||
G.add_node(node)
|
||||
fobj = tempfile.NamedTemporaryFile()
|
||||
nx.write_gml(G, fobj)
|
||||
fobj.seek(0)
|
||||
# Should be bytes in 2.x and 3.x
|
||||
data = fobj.read().strip().decode("ascii")
|
||||
answer = """graph [
|
||||
node [
|
||||
id 0
|
||||
label "1.0"
|
||||
]
|
||||
]"""
|
||||
assert data == answer
|
||||
|
||||
def test_special_float_label(self):
|
||||
special_floats = [float("nan"), float("+inf"), float("-inf")]
|
||||
try:
|
||||
import numpy as np
|
||||
|
||||
special_floats += [np.nan, np.inf, np.inf * -1]
|
||||
except ImportError:
|
||||
special_floats += special_floats
|
||||
|
||||
G = nx.cycle_graph(len(special_floats))
|
||||
attrs = dict(enumerate(special_floats))
|
||||
nx.set_node_attributes(G, attrs, "nodefloat")
|
||||
edges = list(G.edges)
|
||||
attrs = {edges[i]: value for i, value in enumerate(special_floats)}
|
||||
nx.set_edge_attributes(G, attrs, "edgefloat")
|
||||
|
||||
fobj = tempfile.NamedTemporaryFile()
|
||||
nx.write_gml(G, fobj)
|
||||
fobj.seek(0)
|
||||
# Should be bytes in 2.x and 3.x
|
||||
data = fobj.read().strip().decode("ascii")
|
||||
answer = """graph [
|
||||
node [
|
||||
id 0
|
||||
label "0"
|
||||
nodefloat NAN
|
||||
]
|
||||
node [
|
||||
id 1
|
||||
label "1"
|
||||
nodefloat +INF
|
||||
]
|
||||
node [
|
||||
id 2
|
||||
label "2"
|
||||
nodefloat -INF
|
||||
]
|
||||
node [
|
||||
id 3
|
||||
label "3"
|
||||
nodefloat NAN
|
||||
]
|
||||
node [
|
||||
id 4
|
||||
label "4"
|
||||
nodefloat +INF
|
||||
]
|
||||
node [
|
||||
id 5
|
||||
label "5"
|
||||
nodefloat -INF
|
||||
]
|
||||
edge [
|
||||
source 0
|
||||
target 1
|
||||
edgefloat NAN
|
||||
]
|
||||
edge [
|
||||
source 0
|
||||
target 5
|
||||
edgefloat +INF
|
||||
]
|
||||
edge [
|
||||
source 1
|
||||
target 2
|
||||
edgefloat -INF
|
||||
]
|
||||
edge [
|
||||
source 2
|
||||
target 3
|
||||
edgefloat NAN
|
||||
]
|
||||
edge [
|
||||
source 3
|
||||
target 4
|
||||
edgefloat +INF
|
||||
]
|
||||
edge [
|
||||
source 4
|
||||
target 5
|
||||
edgefloat -INF
|
||||
]
|
||||
]"""
|
||||
assert data == answer
|
||||
|
||||
fobj.seek(0)
|
||||
graph = nx.read_gml(fobj)
|
||||
for indx, value in enumerate(special_floats):
|
||||
node_value = graph.nodes[str(indx)]["nodefloat"]
|
||||
if math.isnan(value):
|
||||
assert math.isnan(node_value)
|
||||
else:
|
||||
assert node_value == value
|
||||
|
||||
edge = edges[indx]
|
||||
string_edge = (str(edge[0]), str(edge[1]))
|
||||
edge_value = graph.edges[string_edge]["edgefloat"]
|
||||
if math.isnan(value):
|
||||
assert math.isnan(edge_value)
|
||||
else:
|
||||
assert edge_value == value
|
||||
|
||||
def test_name(self):
|
||||
G = nx.parse_gml('graph [ name "x" node [ id 0 label "x" ] ]')
|
||||
assert "x" == G.graph["name"]
|
||||
G = nx.parse_gml('graph [ node [ id 0 label "x" ] ]')
|
||||
assert "" == G.name
|
||||
assert "name" not in G.graph
|
||||
|
||||
def test_graph_types(self):
|
||||
for directed in [None, False, True]:
|
||||
for multigraph in [None, False, True]:
|
||||
gml = "graph ["
|
||||
if directed is not None:
|
||||
gml += " directed " + str(int(directed))
|
||||
if multigraph is not None:
|
||||
gml += " multigraph " + str(int(multigraph))
|
||||
gml += ' node [ id 0 label "0" ]'
|
||||
gml += " edge [ source 0 target 0 ]"
|
||||
gml += " ]"
|
||||
G = nx.parse_gml(gml)
|
||||
assert bool(directed) == G.is_directed()
|
||||
assert bool(multigraph) == G.is_multigraph()
|
||||
gml = "graph [\n"
|
||||
if directed is True:
|
||||
gml += " directed 1\n"
|
||||
if multigraph is True:
|
||||
gml += " multigraph 1\n"
|
||||
gml += """ node [
|
||||
id 0
|
||||
label "0"
|
||||
]
|
||||
edge [
|
||||
source 0
|
||||
target 0
|
||||
"""
|
||||
if multigraph:
|
||||
gml += " key 0\n"
|
||||
gml += " ]\n]"
|
||||
assert gml == "\n".join(nx.generate_gml(G))
|
||||
|
||||
def test_data_types(self):
|
||||
data = [
|
||||
True,
|
||||
False,
|
||||
10**20,
|
||||
-2e33,
|
||||
"'",
|
||||
'"&&&""',
|
||||
[{(b"\xfd",): "\x7f", chr(0x4444): (1, 2)}, (2, "3")],
|
||||
]
|
||||
data.append(chr(0x14444))
|
||||
data.append(literal_eval("{2.3j, 1 - 2.3j, ()}"))
|
||||
G = nx.Graph()
|
||||
G.name = data
|
||||
G.graph["data"] = data
|
||||
G.add_node(0, int=-1, data={"data": data})
|
||||
G.add_edge(0, 0, float=-2.5, data=data)
|
||||
gml = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer))
|
||||
G = nx.parse_gml(gml, destringizer=literal_destringizer)
|
||||
assert data == G.name
|
||||
assert {"name": data, "data": data} == G.graph
|
||||
assert list(G.nodes(data=True)) == [(0, {"int": -1, "data": {"data": data}})]
|
||||
assert list(G.edges(data=True)) == [(0, 0, {"float": -2.5, "data": data})]
|
||||
G = nx.Graph()
|
||||
G.graph["data"] = "frozenset([1, 2, 3])"
|
||||
G = nx.parse_gml(nx.generate_gml(G), destringizer=literal_eval)
|
||||
assert G.graph["data"] == "frozenset([1, 2, 3])"
|
||||
|
||||
def test_escape_unescape(self):
|
||||
gml = """graph [
|
||||
name "&"䑄��&unknown;"
|
||||
]"""
|
||||
G = nx.parse_gml(gml)
|
||||
assert (
|
||||
'&"\x0f' + chr(0x4444) + "��&unknown;"
|
||||
== G.name
|
||||
)
|
||||
gml = "\n".join(nx.generate_gml(G))
|
||||
alnu = "#1234567890;&#x1234567890abcdef"
|
||||
answer = (
|
||||
"""graph [
|
||||
name "&"䑄&"""
|
||||
+ alnu
|
||||
+ """;&unknown;"
|
||||
]"""
|
||||
)
|
||||
assert answer == gml
|
||||
|
||||
def test_exceptions(self):
|
||||
pytest.raises(ValueError, literal_destringizer, "(")
|
||||
pytest.raises(ValueError, literal_destringizer, "frozenset([1, 2, 3])")
|
||||
pytest.raises(ValueError, literal_destringizer, literal_destringizer)
|
||||
pytest.raises(ValueError, literal_stringizer, frozenset([1, 2, 3]))
|
||||
pytest.raises(ValueError, literal_stringizer, literal_stringizer)
|
||||
with tempfile.TemporaryFile() as f:
|
||||
f.write(codecs.BOM_UTF8 + b"graph[]")
|
||||
f.seek(0)
|
||||
pytest.raises(nx.NetworkXError, nx.read_gml, f)
|
||||
|
||||
def assert_parse_error(gml):
|
||||
pytest.raises(nx.NetworkXError, nx.parse_gml, gml)
|
||||
|
||||
assert_parse_error(["graph [\n\n", "]"])
|
||||
assert_parse_error("")
|
||||
assert_parse_error('Creator ""')
|
||||
assert_parse_error("0")
|
||||
assert_parse_error("graph ]")
|
||||
assert_parse_error("graph [ 1 ]")
|
||||
assert_parse_error("graph [ 1.E+2 ]")
|
||||
assert_parse_error('graph [ "A" ]')
|
||||
assert_parse_error("graph [ ] graph ]")
|
||||
assert_parse_error("graph [ ] graph [ ]")
|
||||
assert_parse_error("graph [ data [1, 2, 3] ]")
|
||||
assert_parse_error("graph [ node [ ] ]")
|
||||
assert_parse_error("graph [ node [ id 0 ] ]")
|
||||
nx.parse_gml('graph [ node [ id "a" ] ]', label="id")
|
||||
assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 0 label 1 ] ]")
|
||||
assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 1 label 0 ] ]")
|
||||
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ ] ]")
|
||||
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 ] ]")
|
||||
nx.parse_gml("graph [edge [ source 0 target 0 ] node [ id 0 label 0 ] ]")
|
||||
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 1 target 0 ] ]")
|
||||
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 target 1 ] ]")
|
||||
assert_parse_error(
|
||||
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] "
|
||||
"edge [ source 0 target 1 ] edge [ source 1 target 0 ] ]"
|
||||
)
|
||||
nx.parse_gml(
|
||||
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] "
|
||||
"edge [ source 0 target 1 ] edge [ source 1 target 0 ] "
|
||||
"directed 1 ]"
|
||||
)
|
||||
nx.parse_gml(
|
||||
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] "
|
||||
"edge [ source 0 target 1 ] edge [ source 0 target 1 ]"
|
||||
"multigraph 1 ]"
|
||||
)
|
||||
nx.parse_gml(
|
||||
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] "
|
||||
"edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 ]"
|
||||
"multigraph 1 ]"
|
||||
)
|
||||
assert_parse_error(
|
||||
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] "
|
||||
"edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 key 0 ]"
|
||||
"multigraph 1 ]"
|
||||
)
|
||||
nx.parse_gml(
|
||||
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] "
|
||||
"edge [ source 0 target 1 key 0 ] edge [ source 1 target 0 key 0 ]"
|
||||
"directed 1 multigraph 1 ]"
|
||||
)
|
||||
|
||||
# Tests for string convertible alphanumeric id and label values
|
||||
nx.parse_gml("graph [edge [ source a target a ] node [ id a label b ] ]")
|
||||
nx.parse_gml(
|
||||
"graph [ node [ id n42 label 0 ] node [ id x43 label 1 ]"
|
||||
"edge [ source n42 target x43 key 0 ]"
|
||||
"edge [ source x43 target n42 key 0 ]"
|
||||
"directed 1 multigraph 1 ]"
|
||||
)
|
||||
assert_parse_error(
|
||||
"graph [edge [ source u'u\4200' target u'u\4200' ] "
|
||||
+ "node [ id u'u\4200' label b ] ]"
|
||||
)
|
||||
|
||||
def assert_generate_error(*args, **kwargs):
|
||||
pytest.raises(
|
||||
nx.NetworkXError, lambda: list(nx.generate_gml(*args, **kwargs))
|
||||
)
|
||||
|
||||
G = nx.Graph()
|
||||
G.graph[3] = 3
|
||||
assert_generate_error(G)
|
||||
G = nx.Graph()
|
||||
G.graph["3"] = 3
|
||||
assert_generate_error(G)
|
||||
G = nx.Graph()
|
||||
G.graph["data"] = frozenset([1, 2, 3])
|
||||
assert_generate_error(G, stringizer=literal_stringizer)
|
||||
|
||||
def test_label_kwarg(self):
|
||||
G = nx.parse_gml(self.simple_data, label="id")
|
||||
assert sorted(G.nodes) == [1, 2, 3]
|
||||
labels = [G.nodes[n]["label"] for n in sorted(G.nodes)]
|
||||
assert labels == ["Node 1", "Node 2", "Node 3"]
|
||||
|
||||
G = nx.parse_gml(self.simple_data, label=None)
|
||||
assert sorted(G.nodes) == [1, 2, 3]
|
||||
labels = [G.nodes[n]["label"] for n in sorted(G.nodes)]
|
||||
assert labels == ["Node 1", "Node 2", "Node 3"]
|
||||
|
||||
def test_outofrange_integers(self):
|
||||
# GML restricts integers to 32 signed bits.
|
||||
# Check that we honor this restriction on export
|
||||
G = nx.Graph()
|
||||
# Test export for numbers that barely fit or don't fit into 32 bits,
|
||||
# and 3 numbers in the middle
|
||||
numbers = {
|
||||
"toosmall": (-(2**31)) - 1,
|
||||
"small": -(2**31),
|
||||
"med1": -4,
|
||||
"med2": 0,
|
||||
"med3": 17,
|
||||
"big": (2**31) - 1,
|
||||
"toobig": 2**31,
|
||||
}
|
||||
G.add_node("Node", **numbers)
|
||||
|
||||
fd, fname = tempfile.mkstemp()
|
||||
try:
|
||||
nx.write_gml(G, fname)
|
||||
# Check that the export wrote the nonfitting numbers as strings
|
||||
G2 = nx.read_gml(fname)
|
||||
for attr, value in G2.nodes["Node"].items():
|
||||
if attr == "toosmall" or attr == "toobig":
|
||||
assert type(value) == str
|
||||
else:
|
||||
assert type(value) == int
|
||||
finally:
|
||||
os.close(fd)
|
||||
os.unlink(fname)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def byte_file():
|
||||
_file_handle = io.BytesIO()
|
||||
yield _file_handle
|
||||
_file_handle.seek(0)
|
||||
|
||||
|
||||
class TestPropertyLists:
|
||||
def test_writing_graph_with_multi_element_property_list(self):
|
||||
g = nx.Graph()
|
||||
g.add_node("n1", properties=["element", 0, 1, 2.5, True, False])
|
||||
with byte_file() as f:
|
||||
nx.write_gml(g, f)
|
||||
result = f.read().decode()
|
||||
|
||||
assert result == dedent(
|
||||
"""\
|
||||
graph [
|
||||
node [
|
||||
id 0
|
||||
label "n1"
|
||||
properties "element"
|
||||
properties 0
|
||||
properties 1
|
||||
properties 2.5
|
||||
properties 1
|
||||
properties 0
|
||||
]
|
||||
]
|
||||
"""
|
||||
)
|
||||
|
||||
def test_writing_graph_with_one_element_property_list(self):
|
||||
g = nx.Graph()
|
||||
g.add_node("n1", properties=["element"])
|
||||
with byte_file() as f:
|
||||
nx.write_gml(g, f)
|
||||
result = f.read().decode()
|
||||
|
||||
assert result == dedent(
|
||||
"""\
|
||||
graph [
|
||||
node [
|
||||
id 0
|
||||
label "n1"
|
||||
properties "_networkx_list_start"
|
||||
properties "element"
|
||||
]
|
||||
]
|
||||
"""
|
||||
)
|
||||
|
||||
def test_reading_graph_with_list_property(self):
|
||||
with byte_file() as f:
|
||||
f.write(
|
||||
dedent(
|
||||
"""
|
||||
graph [
|
||||
node [
|
||||
id 0
|
||||
label "n1"
|
||||
properties "element"
|
||||
properties 0
|
||||
properties 1
|
||||
properties 2.5
|
||||
]
|
||||
]
|
||||
"""
|
||||
).encode("ascii")
|
||||
)
|
||||
f.seek(0)
|
||||
graph = nx.read_gml(f)
|
||||
assert graph.nodes(data=True)["n1"] == {"properties": ["element", 0, 1, 2.5]}
|
||||
|
||||
def test_reading_graph_with_single_element_list_property(self):
|
||||
with byte_file() as f:
|
||||
f.write(
|
||||
dedent(
|
||||
"""
|
||||
graph [
|
||||
node [
|
||||
id 0
|
||||
label "n1"
|
||||
properties "_networkx_list_start"
|
||||
properties "element"
|
||||
]
|
||||
]
|
||||
"""
|
||||
).encode("ascii")
|
||||
)
|
||||
f.seek(0)
|
||||
graph = nx.read_gml(f)
|
||||
assert graph.nodes(data=True)["n1"] == {"properties": ["element"]}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("coll", ([], ()))
|
||||
def test_stringize_empty_list_tuple(coll):
|
||||
G = nx.path_graph(2)
|
||||
G.nodes[0]["test"] = coll # test serializing an empty collection
|
||||
f = io.BytesIO()
|
||||
nx.write_gml(G, f) # Smoke test - should not raise
|
||||
f.seek(0)
|
||||
H = nx.read_gml(f)
|
||||
assert H.nodes["0"]["test"] == coll # Check empty list round-trips properly
|
||||
# Check full round-tripping. Note that nodes are loaded as strings by
|
||||
# default, so there needs to be some remapping prior to comparison
|
||||
H = nx.relabel_nodes(H, {"0": 0, "1": 1})
|
||||
assert nx.utils.graphs_equal(G, H)
|
||||
# Same as above, but use destringizer for node remapping. Should have no
|
||||
# effect on node attr
|
||||
f.seek(0)
|
||||
H = nx.read_gml(f, destringizer=int)
|
||||
assert nx.utils.graphs_equal(G, H)
|
||||
169
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_graph6.py
vendored
Normal file
169
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_graph6.py
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
import tempfile
|
||||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
import networkx.readwrite.graph6 as g6
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class TestGraph6Utils:
|
||||
def test_n_data_n_conversion(self):
|
||||
for i in [0, 1, 42, 62, 63, 64, 258047, 258048, 7744773, 68719476735]:
|
||||
assert g6.data_to_n(g6.n_to_data(i))[0] == i
|
||||
assert g6.data_to_n(g6.n_to_data(i))[1] == []
|
||||
assert g6.data_to_n(g6.n_to_data(i) + [42, 43])[1] == [42, 43]
|
||||
|
||||
|
||||
class TestFromGraph6Bytes:
|
||||
def test_from_graph6_bytes(self):
|
||||
data = b"DF{"
|
||||
G = nx.from_graph6_bytes(data)
|
||||
assert nodes_equal(G.nodes(), [0, 1, 2, 3, 4])
|
||||
assert edges_equal(
|
||||
G.edges(), [(0, 3), (0, 4), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
|
||||
)
|
||||
|
||||
def test_read_equals_from_bytes(self):
|
||||
data = b"DF{"
|
||||
G = nx.from_graph6_bytes(data)
|
||||
fh = BytesIO(data)
|
||||
Gin = nx.read_graph6(fh)
|
||||
assert nodes_equal(G.nodes(), Gin.nodes())
|
||||
assert edges_equal(G.edges(), Gin.edges())
|
||||
|
||||
|
||||
class TestReadGraph6:
|
||||
def test_read_many_graph6(self):
|
||||
"""Test for reading many graphs from a file into a list."""
|
||||
data = b"DF{\nD`{\nDqK\nD~{\n"
|
||||
fh = BytesIO(data)
|
||||
glist = nx.read_graph6(fh)
|
||||
assert len(glist) == 4
|
||||
for G in glist:
|
||||
assert sorted(G) == list(range(5))
|
||||
|
||||
|
||||
class TestWriteGraph6:
|
||||
"""Unit tests for writing a graph to a file in graph6 format."""
|
||||
|
||||
def test_null_graph(self):
|
||||
result = BytesIO()
|
||||
nx.write_graph6(nx.null_graph(), result)
|
||||
assert result.getvalue() == b">>graph6<<?\n"
|
||||
|
||||
def test_trivial_graph(self):
|
||||
result = BytesIO()
|
||||
nx.write_graph6(nx.trivial_graph(), result)
|
||||
assert result.getvalue() == b">>graph6<<@\n"
|
||||
|
||||
def test_complete_graph(self):
|
||||
result = BytesIO()
|
||||
nx.write_graph6(nx.complete_graph(4), result)
|
||||
assert result.getvalue() == b">>graph6<<C~\n"
|
||||
|
||||
def test_large_complete_graph(self):
|
||||
result = BytesIO()
|
||||
nx.write_graph6(nx.complete_graph(67), result, header=False)
|
||||
assert result.getvalue() == b"~?@B" + b"~" * 368 + b"w\n"
|
||||
|
||||
def test_no_header(self):
|
||||
result = BytesIO()
|
||||
nx.write_graph6(nx.complete_graph(4), result, header=False)
|
||||
assert result.getvalue() == b"C~\n"
|
||||
|
||||
def test_complete_bipartite_graph(self):
|
||||
result = BytesIO()
|
||||
G = nx.complete_bipartite_graph(6, 9)
|
||||
nx.write_graph6(G, result, header=False)
|
||||
# The expected encoding here was verified by Sage.
|
||||
assert result.getvalue() == b"N??F~z{~Fw^_~?~?^_?\n"
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.MultiGraph(), nx.DiGraph()))
|
||||
def test_no_directed_or_multi_graphs(self, G):
|
||||
with pytest.raises(nx.NetworkXNotImplemented):
|
||||
nx.write_graph6(G, BytesIO())
|
||||
|
||||
def test_length(self):
|
||||
for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
|
||||
g = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
|
||||
gstr = BytesIO()
|
||||
nx.write_graph6(g, gstr, header=False)
|
||||
# Strip the trailing newline.
|
||||
gstr = gstr.getvalue().rstrip()
|
||||
assert len(gstr) == ((i - 1) * i // 2 + 5) // 6 + (1 if i < 63 else 4)
|
||||
|
||||
def test_roundtrip(self):
|
||||
for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
|
||||
G = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
|
||||
f = BytesIO()
|
||||
nx.write_graph6(G, f)
|
||||
f.seek(0)
|
||||
H = nx.read_graph6(f)
|
||||
assert nodes_equal(G.nodes(), H.nodes())
|
||||
assert edges_equal(G.edges(), H.edges())
|
||||
|
||||
def test_write_path(self):
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
g6.write_graph6_file(nx.null_graph(), f)
|
||||
f.seek(0)
|
||||
assert f.read() == b">>graph6<<?\n"
|
||||
|
||||
@pytest.mark.parametrize("edge", ((0, 1), (1, 2), (1, 42)))
|
||||
def test_relabeling(self, edge):
|
||||
G = nx.Graph([edge])
|
||||
f = BytesIO()
|
||||
nx.write_graph6(G, f)
|
||||
f.seek(0)
|
||||
assert f.read() == b">>graph6<<A_\n"
|
||||
|
||||
|
||||
class TestToGraph6Bytes:
|
||||
def test_null_graph(self):
|
||||
G = nx.null_graph()
|
||||
assert g6.to_graph6_bytes(G) == b">>graph6<<?\n"
|
||||
|
||||
def test_trivial_graph(self):
|
||||
G = nx.trivial_graph()
|
||||
assert g6.to_graph6_bytes(G) == b">>graph6<<@\n"
|
||||
|
||||
def test_complete_graph(self):
|
||||
assert g6.to_graph6_bytes(nx.complete_graph(4)) == b">>graph6<<C~\n"
|
||||
|
||||
def test_large_complete_graph(self):
|
||||
G = nx.complete_graph(67)
|
||||
assert g6.to_graph6_bytes(G, header=False) == b"~?@B" + b"~" * 368 + b"w\n"
|
||||
|
||||
def test_no_header(self):
|
||||
G = nx.complete_graph(4)
|
||||
assert g6.to_graph6_bytes(G, header=False) == b"C~\n"
|
||||
|
||||
def test_complete_bipartite_graph(self):
|
||||
G = nx.complete_bipartite_graph(6, 9)
|
||||
assert g6.to_graph6_bytes(G, header=False) == b"N??F~z{~Fw^_~?~?^_?\n"
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.MultiGraph(), nx.DiGraph()))
|
||||
def test_no_directed_or_multi_graphs(self, G):
|
||||
with pytest.raises(nx.NetworkXNotImplemented):
|
||||
g6.to_graph6_bytes(G)
|
||||
|
||||
def test_length(self):
|
||||
for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
|
||||
G = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
|
||||
# Strip the trailing newline.
|
||||
gstr = g6.to_graph6_bytes(G, header=False).rstrip()
|
||||
assert len(gstr) == ((i - 1) * i // 2 + 5) // 6 + (1 if i < 63 else 4)
|
||||
|
||||
def test_roundtrip(self):
|
||||
for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
|
||||
G = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
|
||||
data = g6.to_graph6_bytes(G)
|
||||
H = nx.from_graph6_bytes(data.rstrip())
|
||||
assert nodes_equal(G.nodes(), H.nodes())
|
||||
assert edges_equal(G.edges(), H.edges())
|
||||
|
||||
@pytest.mark.parametrize("edge", ((0, 1), (1, 2), (1, 42)))
|
||||
def test_relabeling(self, edge):
|
||||
G = nx.Graph([edge])
|
||||
assert g6.to_graph6_bytes(G) == b">>graph6<<A_\n"
|
||||
1540
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_graphml.py
vendored
Normal file
1540
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_graphml.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
30
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_leda.py
vendored
Normal file
30
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_leda.py
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import io
|
||||
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class TestLEDA:
|
||||
def test_parse_leda(self):
|
||||
data = """#header section \nLEDA.GRAPH \nstring\nint\n-1\n#nodes section\n5 \n|{v1}| \n|{v2}| \n|{v3}| \n|{v4}| \n|{v5}| \n\n#edges section\n7 \n1 2 0 |{4}| \n1 3 0 |{3}| \n2 3 0 |{2}| \n3 4 0 |{3}| \n3 5 0 |{7}| \n4 5 0 |{6}| \n5 1 0 |{foo}|"""
|
||||
G = nx.parse_leda(data)
|
||||
G = nx.parse_leda(data.split("\n"))
|
||||
assert sorted(G.nodes()) == ["v1", "v2", "v3", "v4", "v5"]
|
||||
assert sorted(G.edges(data=True)) == [
|
||||
("v1", "v2", {"label": "4"}),
|
||||
("v1", "v3", {"label": "3"}),
|
||||
("v2", "v3", {"label": "2"}),
|
||||
("v3", "v4", {"label": "3"}),
|
||||
("v3", "v5", {"label": "7"}),
|
||||
("v4", "v5", {"label": "6"}),
|
||||
("v5", "v1", {"label": "foo"}),
|
||||
]
|
||||
|
||||
def test_read_LEDA(self):
|
||||
fh = io.BytesIO()
|
||||
data = """#header section \nLEDA.GRAPH \nstring\nint\n-1\n#nodes section\n5 \n|{v1}| \n|{v2}| \n|{v3}| \n|{v4}| \n|{v5}| \n\n#edges section\n7 \n1 2 0 |{4}| \n1 3 0 |{3}| \n2 3 0 |{2}| \n3 4 0 |{3}| \n3 5 0 |{7}| \n4 5 0 |{6}| \n5 1 0 |{foo}|"""
|
||||
G = nx.parse_leda(data)
|
||||
fh.write(data.encode("UTF-8"))
|
||||
fh.seek(0)
|
||||
Gin = nx.read_leda(fh)
|
||||
assert sorted(G.nodes()) == sorted(Gin.nodes())
|
||||
assert sorted(G.edges()) == sorted(Gin.edges())
|
||||
62
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_p2g.py
vendored
Normal file
62
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_p2g.py
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
import io
|
||||
|
||||
import networkx as nx
|
||||
from networkx.readwrite.p2g import read_p2g, write_p2g
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
|
||||
class TestP2G:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.Graph(name="test")
|
||||
e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")]
|
||||
cls.G.add_edges_from(e)
|
||||
cls.G.add_node("g")
|
||||
cls.DG = nx.DiGraph(cls.G)
|
||||
|
||||
def test_read_p2g(self):
|
||||
s = b"""\
|
||||
name
|
||||
3 4
|
||||
a
|
||||
1 2
|
||||
b
|
||||
|
||||
c
|
||||
0 2
|
||||
"""
|
||||
bytesIO = io.BytesIO(s)
|
||||
G = read_p2g(bytesIO)
|
||||
assert G.name == "name"
|
||||
assert sorted(G) == ["a", "b", "c"]
|
||||
edges = [(str(u), str(v)) for u, v in G.edges()]
|
||||
assert edges_equal(G.edges(), [("a", "c"), ("a", "b"), ("c", "a"), ("c", "c")])
|
||||
|
||||
def test_write_p2g(self):
|
||||
s = b"""foo
|
||||
3 2
|
||||
1
|
||||
1
|
||||
2
|
||||
2
|
||||
3
|
||||
|
||||
"""
|
||||
fh = io.BytesIO()
|
||||
G = nx.DiGraph()
|
||||
G.name = "foo"
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
write_p2g(G, fh)
|
||||
fh.seek(0)
|
||||
r = fh.read()
|
||||
assert r == s
|
||||
|
||||
def test_write_read_p2g(self):
|
||||
fh = io.BytesIO()
|
||||
G = nx.DiGraph()
|
||||
G.name = "foo"
|
||||
G.add_edges_from([("a", "b"), ("b", "c")])
|
||||
write_p2g(G, fh)
|
||||
fh.seek(0)
|
||||
H = read_p2g(fh)
|
||||
assert edges_equal(G.edges(), H.edges())
|
||||
130
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_pajek.py
vendored
Normal file
130
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_pajek.py
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
Pajek tests
|
||||
"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class TestPajek:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.data = """*network Tralala\n*vertices 4\n 1 "A1" 0.0938 0.0896 ellipse x_fact 1 y_fact 1\n 2 "Bb" 0.8188 0.2458 ellipse x_fact 1 y_fact 1\n 3 "C" 0.3688 0.7792 ellipse x_fact 1\n 4 "D2" 0.9583 0.8563 ellipse x_fact 1\n*arcs\n1 1 1 h2 0 w 3 c Blue s 3 a1 -130 k1 0.6 a2 -130 k2 0.6 ap 0.5 l "Bezier loop" lc BlueViolet fos 20 lr 58 lp 0.3 la 360\n2 1 1 h2 0 a1 120 k1 1.3 a2 -120 k2 0.3 ap 25 l "Bezier arc" lphi 270 la 180 lr 19 lp 0.5\n1 2 1 h2 0 a1 40 k1 2.8 a2 30 k2 0.8 ap 25 l "Bezier arc" lphi 90 la 0 lp 0.65\n4 2 -1 h2 0 w 1 k1 -2 k2 250 ap 25 l "Circular arc" c Red lc OrangeRed\n3 4 1 p Dashed h2 0 w 2 c OliveGreen ap 25 l "Straight arc" lc PineGreen\n1 3 1 p Dashed h2 0 w 5 k1 -1 k2 -20 ap 25 l "Oval arc" c Brown lc Black\n3 3 -1 h1 6 w 1 h2 12 k1 -2 k2 -15 ap 0.5 l "Circular loop" c Red lc OrangeRed lphi 270 la 180"""
|
||||
cls.G = nx.MultiDiGraph()
|
||||
cls.G.add_nodes_from(["A1", "Bb", "C", "D2"])
|
||||
cls.G.add_edges_from(
|
||||
[
|
||||
("A1", "A1"),
|
||||
("A1", "Bb"),
|
||||
("A1", "C"),
|
||||
("Bb", "A1"),
|
||||
("C", "C"),
|
||||
("C", "D2"),
|
||||
("D2", "Bb"),
|
||||
]
|
||||
)
|
||||
|
||||
cls.G.graph["name"] = "Tralala"
|
||||
(fd, cls.fname) = tempfile.mkstemp()
|
||||
with os.fdopen(fd, "wb") as fh:
|
||||
fh.write(cls.data.encode("UTF-8"))
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
os.unlink(cls.fname)
|
||||
|
||||
def test_parse_pajek_simple(self):
|
||||
# Example without node positions or shape
|
||||
data = """*Vertices 2\n1 "1"\n2 "2"\n*Edges\n1 2\n2 1"""
|
||||
G = nx.parse_pajek(data)
|
||||
assert sorted(G.nodes()) == ["1", "2"]
|
||||
assert edges_equal(G.edges(), [("1", "2"), ("1", "2")])
|
||||
|
||||
def test_parse_pajek(self):
|
||||
G = nx.parse_pajek(self.data)
|
||||
assert sorted(G.nodes()) == ["A1", "Bb", "C", "D2"]
|
||||
assert edges_equal(
|
||||
G.edges(),
|
||||
[
|
||||
("A1", "A1"),
|
||||
("A1", "Bb"),
|
||||
("A1", "C"),
|
||||
("Bb", "A1"),
|
||||
("C", "C"),
|
||||
("C", "D2"),
|
||||
("D2", "Bb"),
|
||||
],
|
||||
)
|
||||
|
||||
def test_parse_pajet_mat(self):
|
||||
data = """*Vertices 3\n1 "one"\n2 "two"\n3 "three"\n*Matrix\n1 1 0\n0 1 0\n0 1 0\n"""
|
||||
G = nx.parse_pajek(data)
|
||||
assert set(G.nodes()) == {"one", "two", "three"}
|
||||
assert G.nodes["two"] == {"id": "2"}
|
||||
assert edges_equal(
|
||||
set(G.edges()),
|
||||
{("one", "one"), ("two", "one"), ("two", "two"), ("two", "three")},
|
||||
)
|
||||
|
||||
def test_read_pajek(self):
|
||||
G = nx.parse_pajek(self.data)
|
||||
Gin = nx.read_pajek(self.fname)
|
||||
assert sorted(G.nodes()) == sorted(Gin.nodes())
|
||||
assert edges_equal(G.edges(), Gin.edges())
|
||||
assert self.G.graph == Gin.graph
|
||||
for n in G:
|
||||
assert G.nodes[n] == Gin.nodes[n]
|
||||
|
||||
def test_write_pajek(self):
|
||||
import io
|
||||
|
||||
G = nx.parse_pajek(self.data)
|
||||
fh = io.BytesIO()
|
||||
nx.write_pajek(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_pajek(fh)
|
||||
assert nodes_equal(list(G), list(H))
|
||||
assert edges_equal(list(G.edges()), list(H.edges()))
|
||||
# Graph name is left out for now, therefore it is not tested.
|
||||
# assert_equal(G.graph, H.graph)
|
||||
|
||||
def test_ignored_attribute(self):
|
||||
import io
|
||||
|
||||
G = nx.Graph()
|
||||
fh = io.BytesIO()
|
||||
G.add_node(1, int_attr=1)
|
||||
G.add_node(2, empty_attr=" ")
|
||||
G.add_edge(1, 2, int_attr=2)
|
||||
G.add_edge(2, 3, empty_attr=" ")
|
||||
|
||||
import warnings
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
nx.write_pajek(G, fh)
|
||||
assert len(w) == 4
|
||||
|
||||
def test_noname(self):
|
||||
# Make sure we can parse a line such as: *network
|
||||
# Issue #952
|
||||
line = "*network\n"
|
||||
other_lines = self.data.split("\n")[1:]
|
||||
data = line + "\n".join(other_lines)
|
||||
G = nx.parse_pajek(data)
|
||||
|
||||
def test_unicode(self):
|
||||
import io
|
||||
|
||||
G = nx.Graph()
|
||||
name1 = chr(2344) + chr(123) + chr(6543)
|
||||
name2 = chr(5543) + chr(1543) + chr(324)
|
||||
G.add_edge(name1, "Radiohead", foo=name2)
|
||||
fh = io.BytesIO()
|
||||
nx.write_pajek(G, fh)
|
||||
fh.seek(0)
|
||||
H = nx.read_pajek(fh)
|
||||
assert nodes_equal(list(G), list(H))
|
||||
assert edges_equal(list(G.edges()), list(H.edges()))
|
||||
assert G.graph == H.graph
|
||||
173
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_sparse6.py
vendored
Normal file
173
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_sparse6.py
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
import tempfile
|
||||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class TestSparseGraph6:
|
||||
def test_from_sparse6_bytes(self):
|
||||
data = b":Q___eDcdFcDeFcE`GaJ`IaHbKNbLM"
|
||||
G = nx.from_sparse6_bytes(data)
|
||||
assert nodes_equal(
|
||||
sorted(G.nodes()),
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
|
||||
)
|
||||
assert edges_equal(
|
||||
G.edges(),
|
||||
[
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(0, 3),
|
||||
(1, 12),
|
||||
(1, 14),
|
||||
(2, 13),
|
||||
(2, 15),
|
||||
(3, 16),
|
||||
(3, 17),
|
||||
(4, 7),
|
||||
(4, 9),
|
||||
(4, 11),
|
||||
(5, 6),
|
||||
(5, 8),
|
||||
(5, 9),
|
||||
(6, 10),
|
||||
(6, 11),
|
||||
(7, 8),
|
||||
(7, 10),
|
||||
(8, 12),
|
||||
(9, 15),
|
||||
(10, 14),
|
||||
(11, 13),
|
||||
(12, 16),
|
||||
(13, 17),
|
||||
(14, 17),
|
||||
(15, 16),
|
||||
],
|
||||
)
|
||||
|
||||
def test_from_bytes_multigraph_graph(self):
|
||||
graph_data = b":An"
|
||||
G = nx.from_sparse6_bytes(graph_data)
|
||||
assert type(G) == nx.Graph
|
||||
multigraph_data = b":Ab"
|
||||
M = nx.from_sparse6_bytes(multigraph_data)
|
||||
assert type(M) == nx.MultiGraph
|
||||
|
||||
def test_read_sparse6(self):
|
||||
data = b":Q___eDcdFcDeFcE`GaJ`IaHbKNbLM"
|
||||
G = nx.from_sparse6_bytes(data)
|
||||
fh = BytesIO(data)
|
||||
Gin = nx.read_sparse6(fh)
|
||||
assert nodes_equal(G.nodes(), Gin.nodes())
|
||||
assert edges_equal(G.edges(), Gin.edges())
|
||||
|
||||
def test_read_many_graph6(self):
|
||||
# Read many graphs into list
|
||||
data = b":Q___eDcdFcDeFcE`GaJ`IaHbKNbLM\n" b":Q___dCfDEdcEgcbEGbFIaJ`JaHN`IM"
|
||||
fh = BytesIO(data)
|
||||
glist = nx.read_sparse6(fh)
|
||||
assert len(glist) == 2
|
||||
for G in glist:
|
||||
assert nodes_equal(
|
||||
G.nodes(),
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
|
||||
)
|
||||
|
||||
|
||||
class TestWriteSparse6:
|
||||
"""Unit tests for writing graphs in the sparse6 format.
|
||||
|
||||
Most of the test cases were checked against the sparse6 encoder in Sage.
|
||||
|
||||
"""
|
||||
|
||||
def test_null_graph(self):
|
||||
G = nx.null_graph()
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
assert result.getvalue() == b">>sparse6<<:?\n"
|
||||
|
||||
def test_trivial_graph(self):
|
||||
G = nx.trivial_graph()
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
assert result.getvalue() == b">>sparse6<<:@\n"
|
||||
|
||||
def test_empty_graph(self):
|
||||
G = nx.empty_graph(5)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
assert result.getvalue() == b">>sparse6<<:D\n"
|
||||
|
||||
def test_large_empty_graph(self):
|
||||
G = nx.empty_graph(68)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
assert result.getvalue() == b">>sparse6<<:~?@C\n"
|
||||
|
||||
def test_very_large_empty_graph(self):
|
||||
G = nx.empty_graph(258049)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
assert result.getvalue() == b">>sparse6<<:~~???~?@\n"
|
||||
|
||||
def test_complete_graph(self):
|
||||
G = nx.complete_graph(4)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
assert result.getvalue() == b">>sparse6<<:CcKI\n"
|
||||
|
||||
def test_no_header(self):
|
||||
G = nx.complete_graph(4)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result, header=False)
|
||||
assert result.getvalue() == b":CcKI\n"
|
||||
|
||||
def test_padding(self):
|
||||
codes = (b":Cdv", b":DaYn", b":EaYnN", b":FaYnL", b":GaYnLz")
|
||||
for n, code in enumerate(codes, start=4):
|
||||
G = nx.path_graph(n)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result, header=False)
|
||||
assert result.getvalue() == code + b"\n"
|
||||
|
||||
def test_complete_bipartite(self):
|
||||
G = nx.complete_bipartite_graph(6, 9)
|
||||
result = BytesIO()
|
||||
nx.write_sparse6(G, result)
|
||||
# Compared with sage
|
||||
expected = b">>sparse6<<:Nk" + b"?G`cJ" * 9 + b"\n"
|
||||
assert result.getvalue() == expected
|
||||
|
||||
def test_read_write_inverse(self):
|
||||
for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
|
||||
m = min(2 * i, i * i // 2)
|
||||
g = nx.random_graphs.gnm_random_graph(i, m, seed=i)
|
||||
gstr = BytesIO()
|
||||
nx.write_sparse6(g, gstr, header=False)
|
||||
# Strip the trailing newline.
|
||||
gstr = gstr.getvalue().rstrip()
|
||||
g2 = nx.from_sparse6_bytes(gstr)
|
||||
assert g2.order() == g.order()
|
||||
assert edges_equal(g2.edges(), g.edges())
|
||||
|
||||
def test_no_directed_graphs(self):
|
||||
with pytest.raises(nx.NetworkXNotImplemented):
|
||||
nx.write_sparse6(nx.DiGraph(), BytesIO())
|
||||
|
||||
def test_write_path(self):
|
||||
# On Windows, we can't reopen a file that is open
|
||||
# So, for test we get a valid name from tempfile but close it.
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
fullfilename = f.name
|
||||
# file should be closed now, so write_sparse6 can open it
|
||||
nx.write_sparse6(nx.null_graph(), fullfilename)
|
||||
fh = open(fullfilename, mode="rb")
|
||||
assert fh.read() == b">>sparse6<<:?\n"
|
||||
fh.close()
|
||||
import os
|
||||
|
||||
os.remove(fullfilename)
|
||||
1498
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_text.py
vendored
Normal file
1498
.CondaPkg/env/Lib/site-packages/networkx/readwrite/tests/test_text.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
562
.CondaPkg/env/Lib/site-packages/networkx/readwrite/text.py
vendored
Normal file
562
.CondaPkg/env/Lib/site-packages/networkx/readwrite/text.py
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
"""
|
||||
Text-based visual representations of graphs
|
||||
"""
|
||||
import sys
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import open_file
|
||||
|
||||
__all__ = ["forest_str", "generate_network_text", "write_network_text"]
|
||||
|
||||
|
||||
class _AsciiBaseGlyphs:
|
||||
empty = "+"
|
||||
newtree_last = "+-- "
|
||||
newtree_mid = "+-- "
|
||||
endof_forest = " "
|
||||
within_forest = ": "
|
||||
within_tree = "| "
|
||||
|
||||
|
||||
class AsciiDirectedGlyphs(_AsciiBaseGlyphs):
|
||||
last = "L-> "
|
||||
mid = "|-> "
|
||||
backedge = "<-"
|
||||
|
||||
|
||||
class AsciiUndirectedGlyphs(_AsciiBaseGlyphs):
|
||||
last = "L-- "
|
||||
mid = "|-- "
|
||||
backedge = "-"
|
||||
|
||||
|
||||
class _UtfBaseGlyphs:
|
||||
# Notes on available box and arrow characters
|
||||
# https://en.wikipedia.org/wiki/Box-drawing_character
|
||||
# https://stackoverflow.com/questions/2701192/triangle-arrow
|
||||
empty = "╙"
|
||||
newtree_last = "╙── "
|
||||
newtree_mid = "╟── "
|
||||
endof_forest = " "
|
||||
within_forest = "╎ "
|
||||
within_tree = "│ "
|
||||
|
||||
|
||||
class UtfDirectedGlyphs(_UtfBaseGlyphs):
|
||||
last = "└─╼ "
|
||||
mid = "├─╼ "
|
||||
backedge = "╾"
|
||||
|
||||
|
||||
class UtfUndirectedGlyphs(_UtfBaseGlyphs):
|
||||
last = "└── "
|
||||
mid = "├── "
|
||||
backedge = "─"
|
||||
|
||||
|
||||
def generate_network_text(
|
||||
graph, with_labels=True, sources=None, max_depth=None, ascii_only=False
|
||||
):
|
||||
"""Generate lines in the "network text" format
|
||||
|
||||
This works via a depth-first traversal of the graph and writing a line for
|
||||
each unique node encountered. Non-tree edges are written to the right of
|
||||
each node, and connection to a non-tree edge is indicated with an ellipsis.
|
||||
This representation works best when the input graph is a forest, but any
|
||||
graph can be represented.
|
||||
|
||||
This notation is original to networkx, although it is simple enough that it
|
||||
may be known in existing literature. See #5602 for details. The procedure
|
||||
is summarized as follows:
|
||||
|
||||
1. Given a set of source nodes (which can be specified, or automatically
|
||||
discovered via finding the (strongly) connected components and choosing one
|
||||
node with minimum degree from each), we traverse the graph in depth first
|
||||
order.
|
||||
|
||||
2. Each reachable node will be printed exactly once on it's own line.
|
||||
|
||||
3. Edges are indicated in one of three ways:
|
||||
|
||||
a. a parent "L-style" connection on the upper left. This corresponds to
|
||||
a traversal in the directed DFS tree.
|
||||
|
||||
b. a backref "<-style" connection shown directly on the right. For
|
||||
directed graphs, these are drawn for any incoming edges to a node that
|
||||
is not a parent edge. For undirected graphs, these are drawn for only
|
||||
the non-parent edges that have already been represented (The edges that
|
||||
have not been represented will be handled in the recursive case).
|
||||
|
||||
c. a child "L-style" connection on the lower right. Drawing of the
|
||||
children are handled recursively.
|
||||
|
||||
4. The children of each node (wrt the directed DFS tree) are drawn
|
||||
underneath and to the right of it. In the case that a child node has already
|
||||
been drawn the connection is replaced with an ellipsis ("...") to indicate
|
||||
that there is one or more connections represented elsewhere.
|
||||
|
||||
5. If a maximum depth is specified, an edge to nodes past this maximum
|
||||
depth will be represented by an ellipsis.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
graph : nx.DiGraph | nx.Graph
|
||||
Graph to represent
|
||||
|
||||
with_labels : bool | str
|
||||
If True will use the "label" attribute of a node to display if it
|
||||
exists otherwise it will use the node value itself. If given as a
|
||||
string, then that attribute name will be used instead of "label".
|
||||
Defaults to True.
|
||||
|
||||
sources : List
|
||||
Specifies which nodes to start traversal from. Note: nodes that are not
|
||||
reachable from one of these sources may not be shown. If unspecified,
|
||||
the minimal set of nodes needed to reach all others will be used.
|
||||
|
||||
max_depth : int | None
|
||||
The maximum depth to traverse before stopping. Defaults to None.
|
||||
|
||||
ascii_only : Boolean
|
||||
If True only ASCII characters are used to construct the visualization
|
||||
|
||||
Yields
|
||||
------
|
||||
str : a line of generated text
|
||||
"""
|
||||
is_directed = graph.is_directed()
|
||||
|
||||
if is_directed:
|
||||
glyphs = AsciiDirectedGlyphs if ascii_only else UtfDirectedGlyphs
|
||||
succ = graph.succ
|
||||
pred = graph.pred
|
||||
else:
|
||||
glyphs = AsciiUndirectedGlyphs if ascii_only else UtfUndirectedGlyphs
|
||||
succ = graph.adj
|
||||
pred = graph.adj
|
||||
|
||||
if isinstance(with_labels, str):
|
||||
label_attr = with_labels
|
||||
elif with_labels:
|
||||
label_attr = "label"
|
||||
else:
|
||||
label_attr = None
|
||||
|
||||
if max_depth == 0:
|
||||
yield glyphs.empty + " ..."
|
||||
elif len(graph.nodes) == 0:
|
||||
yield glyphs.empty
|
||||
else:
|
||||
# If the nodes to traverse are unspecified, find the minimal set of
|
||||
# nodes that will reach the entire graph
|
||||
if sources is None:
|
||||
sources = _find_sources(graph)
|
||||
|
||||
# Populate the stack with each:
|
||||
# 1. parent node in the DFS tree (or None for root nodes),
|
||||
# 2. the current node in the DFS tree
|
||||
# 2. a list of indentations indicating depth
|
||||
# 3. a flag indicating if the node is the final one to be written.
|
||||
# Reverse the stack so sources are popped in the correct order.
|
||||
last_idx = len(sources) - 1
|
||||
stack = [
|
||||
(None, node, [], (idx == last_idx)) for idx, node in enumerate(sources)
|
||||
][::-1]
|
||||
|
||||
num_skipped_children = defaultdict(lambda: 0)
|
||||
seen_nodes = set()
|
||||
while stack:
|
||||
parent, node, indents, this_islast = stack.pop()
|
||||
|
||||
if node is not Ellipsis:
|
||||
skip = node in seen_nodes
|
||||
if skip:
|
||||
# Mark that we skipped a parent's child
|
||||
num_skipped_children[parent] += 1
|
||||
|
||||
if this_islast:
|
||||
# If we reached the last child of a parent, and we skipped
|
||||
# any of that parents children, then we should emit an
|
||||
# ellipsis at the end after this.
|
||||
if num_skipped_children[parent] and parent is not None:
|
||||
# Append the ellipsis to be emitted last
|
||||
next_islast = True
|
||||
try_frame = (node, Ellipsis, indents, next_islast)
|
||||
stack.append(try_frame)
|
||||
|
||||
# Redo this frame, but not as a last object
|
||||
next_islast = False
|
||||
try_frame = (parent, node, indents, next_islast)
|
||||
stack.append(try_frame)
|
||||
continue
|
||||
|
||||
if skip:
|
||||
continue
|
||||
seen_nodes.add(node)
|
||||
|
||||
if not indents:
|
||||
# Top level items (i.e. trees in the forest) get different
|
||||
# glyphs to indicate they are not actually connected
|
||||
if this_islast:
|
||||
this_prefix = indents + [glyphs.newtree_last]
|
||||
next_prefix = indents + [glyphs.endof_forest]
|
||||
else:
|
||||
this_prefix = indents + [glyphs.newtree_mid]
|
||||
next_prefix = indents + [glyphs.within_forest]
|
||||
|
||||
else:
|
||||
# For individual tree edges distinguish between directed and
|
||||
# undirected cases
|
||||
if this_islast:
|
||||
this_prefix = indents + [glyphs.last]
|
||||
next_prefix = indents + [glyphs.endof_forest]
|
||||
else:
|
||||
this_prefix = indents + [glyphs.mid]
|
||||
next_prefix = indents + [glyphs.within_tree]
|
||||
|
||||
if node is Ellipsis:
|
||||
label = " ..."
|
||||
suffix = ""
|
||||
children = []
|
||||
else:
|
||||
if label_attr is not None:
|
||||
label = str(graph.nodes[node].get(label_attr, node))
|
||||
else:
|
||||
label = str(node)
|
||||
|
||||
# Determine:
|
||||
# (1) children to traverse into after showing this node.
|
||||
# (2) parents to immediately show to the right of this node.
|
||||
if is_directed:
|
||||
# In the directed case we must show every successor node
|
||||
# note: it may be skipped later, but we don't have that
|
||||
# information here.
|
||||
children = list(succ[node])
|
||||
# In the directed case we must show every predecessor
|
||||
# except for parent we directly traversed from.
|
||||
handled_parents = {parent}
|
||||
else:
|
||||
# Showing only the unseen children results in a more
|
||||
# concise representation for the undirected case.
|
||||
children = [
|
||||
child for child in succ[node] if child not in seen_nodes
|
||||
]
|
||||
|
||||
# In the undirected case, parents are also children, so we
|
||||
# only need to immediately show the ones we can no longer
|
||||
# traverse
|
||||
handled_parents = {*children, parent}
|
||||
|
||||
if max_depth is not None and len(indents) == max_depth - 1:
|
||||
# Use ellipsis to indicate we have reached maximum depth
|
||||
if children:
|
||||
children = [Ellipsis]
|
||||
handled_parents = {parent}
|
||||
|
||||
# The other parents are other predecessors of this node that
|
||||
# are not handled elsewhere.
|
||||
other_parents = [p for p in pred[node] if p not in handled_parents]
|
||||
if other_parents:
|
||||
if label_attr is not None:
|
||||
other_parents_labels = ", ".join(
|
||||
[
|
||||
str(graph.nodes[p].get(label_attr, p))
|
||||
for p in other_parents
|
||||
]
|
||||
)
|
||||
else:
|
||||
other_parents_labels = ", ".join(
|
||||
[str(p) for p in other_parents]
|
||||
)
|
||||
suffix = " ".join(["", glyphs.backedge, other_parents_labels])
|
||||
else:
|
||||
suffix = ""
|
||||
|
||||
# Emit the line for this node, this will be called for each node
|
||||
# exactly once.
|
||||
yield "".join(this_prefix + [label, suffix])
|
||||
|
||||
# Push children on the stack in reverse order so they are popped in
|
||||
# the original order.
|
||||
for idx, child in enumerate(children[::-1]):
|
||||
next_islast = idx == 0
|
||||
try_frame = (node, child, next_prefix, next_islast)
|
||||
stack.append(try_frame)
|
||||
|
||||
|
||||
@open_file(1, "w")
|
||||
def write_network_text(
|
||||
graph,
|
||||
path=None,
|
||||
with_labels=True,
|
||||
sources=None,
|
||||
max_depth=None,
|
||||
ascii_only=False,
|
||||
end="\n",
|
||||
):
|
||||
"""Creates a nice text representation of a graph
|
||||
|
||||
This works via a depth-first traversal of the graph and writing a line for
|
||||
each unique node encountered. Non-tree edges are written to the right of
|
||||
each node, and connection to a non-tree edge is indicated with an ellipsis.
|
||||
This representation works best when the input graph is a forest, but any
|
||||
graph can be represented.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
graph : nx.DiGraph | nx.Graph
|
||||
Graph to represent
|
||||
|
||||
path : string or file or callable or None
|
||||
Filename or file handle for data output.
|
||||
if a function, then it will be called for each generated line.
|
||||
if None, this will default to "sys.stdout.write"
|
||||
|
||||
with_labels : bool | str
|
||||
If True will use the "label" attribute of a node to display if it
|
||||
exists otherwise it will use the node value itself. If given as a
|
||||
string, then that attribute name will be used instead of "label".
|
||||
Defaults to True.
|
||||
|
||||
sources : List
|
||||
Specifies which nodes to start traversal from. Note: nodes that are not
|
||||
reachable from one of these sources may not be shown. If unspecified,
|
||||
the minimal set of nodes needed to reach all others will be used.
|
||||
|
||||
max_depth : int | None
|
||||
The maximum depth to traverse before stopping. Defaults to None.
|
||||
|
||||
ascii_only : Boolean
|
||||
If True only ASCII characters are used to construct the visualization
|
||||
|
||||
end : string
|
||||
The line ending character
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> graph = nx.balanced_tree(r=2, h=2, create_using=nx.DiGraph)
|
||||
>>> nx.write_network_text(graph)
|
||||
╙── 0
|
||||
├─╼ 1
|
||||
│ ├─╼ 3
|
||||
│ └─╼ 4
|
||||
└─╼ 2
|
||||
├─╼ 5
|
||||
└─╼ 6
|
||||
|
||||
>>> # A near tree with one non-tree edge
|
||||
>>> graph.add_edge(5, 1)
|
||||
>>> nx.write_network_text(graph)
|
||||
╙── 0
|
||||
├─╼ 1 ╾ 5
|
||||
│ ├─╼ 3
|
||||
│ └─╼ 4
|
||||
└─╼ 2
|
||||
├─╼ 5
|
||||
│ └─╼ ...
|
||||
└─╼ 6
|
||||
|
||||
>>> graph = nx.cycle_graph(5)
|
||||
>>> nx.write_network_text(graph)
|
||||
╙── 0
|
||||
├── 1
|
||||
│ └── 2
|
||||
│ └── 3
|
||||
│ └── 4 ─ 0
|
||||
└── ...
|
||||
|
||||
>>> graph = nx.generators.barbell_graph(4, 2)
|
||||
>>> nx.write_network_text(graph)
|
||||
╙── 4
|
||||
├── 5
|
||||
│ └── 6
|
||||
│ ├── 7
|
||||
│ │ ├── 8 ─ 6
|
||||
│ │ │ └── 9 ─ 6, 7
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
└── 3
|
||||
├── 0
|
||||
│ ├── 1 ─ 3
|
||||
│ │ └── 2 ─ 0, 3
|
||||
│ └── ...
|
||||
└── ...
|
||||
|
||||
>>> graph = nx.complete_graph(5, create_using=nx.Graph)
|
||||
>>> nx.write_network_text(graph)
|
||||
╙── 0
|
||||
├── 1
|
||||
│ ├── 2 ─ 0
|
||||
│ │ ├── 3 ─ 0, 1
|
||||
│ │ │ └── 4 ─ 0, 1, 2
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
└── ...
|
||||
|
||||
>>> graph = nx.complete_graph(3, create_using=nx.DiGraph)
|
||||
>>> nx.write_network_text(graph)
|
||||
╙── 0 ╾ 1, 2
|
||||
├─╼ 1 ╾ 2
|
||||
│ ├─╼ 2 ╾ 0
|
||||
│ │ └─╼ ...
|
||||
│ └─╼ ...
|
||||
└─╼ ...
|
||||
"""
|
||||
if path is None:
|
||||
# The path is unspecified, write to stdout
|
||||
_write = sys.stdout.write
|
||||
elif hasattr(path, "write"):
|
||||
# The path is already an open file
|
||||
_write = path.write
|
||||
elif callable(path):
|
||||
# The path is a custom callable
|
||||
_write = path
|
||||
else:
|
||||
raise TypeError(type(path))
|
||||
|
||||
for line in generate_network_text(
|
||||
graph,
|
||||
with_labels=with_labels,
|
||||
sources=sources,
|
||||
max_depth=max_depth,
|
||||
ascii_only=ascii_only,
|
||||
):
|
||||
_write(line + end)
|
||||
|
||||
|
||||
def _find_sources(graph):
|
||||
"""
|
||||
Determine a minimal set of nodes such that the entire graph is reachable
|
||||
"""
|
||||
# For each connected part of the graph, choose at least
|
||||
# one node as a starting point, preferably without a parent
|
||||
if graph.is_directed():
|
||||
# Choose one node from each SCC with minimum in_degree
|
||||
sccs = list(nx.strongly_connected_components(graph))
|
||||
# condensing the SCCs forms a dag, the nodes in this graph with
|
||||
# 0 in-degree correspond to the SCCs from which the minimum set
|
||||
# of nodes from which all other nodes can be reached.
|
||||
scc_graph = nx.condensation(graph, sccs)
|
||||
supernode_to_nodes = {sn: [] for sn in scc_graph.nodes()}
|
||||
# Note: the order of mapping differs between pypy and cpython
|
||||
# so we have to loop over graph nodes for consistency
|
||||
mapping = scc_graph.graph["mapping"]
|
||||
for n in graph.nodes:
|
||||
sn = mapping[n]
|
||||
supernode_to_nodes[sn].append(n)
|
||||
sources = []
|
||||
for sn in scc_graph.nodes():
|
||||
if scc_graph.in_degree[sn] == 0:
|
||||
scc = supernode_to_nodes[sn]
|
||||
node = min(scc, key=lambda n: graph.in_degree[n])
|
||||
sources.append(node)
|
||||
else:
|
||||
# For undirected graph, the entire graph will be reachable as
|
||||
# long as we consider one node from every connected component
|
||||
sources = [
|
||||
min(cc, key=lambda n: graph.degree[n])
|
||||
for cc in nx.connected_components(graph)
|
||||
]
|
||||
sources = sorted(sources, key=lambda n: graph.degree[n])
|
||||
return sources
|
||||
|
||||
|
||||
def forest_str(graph, with_labels=True, sources=None, write=None, ascii_only=False):
|
||||
"""Creates a nice utf8 representation of a forest
|
||||
|
||||
This function has been superseded by
|
||||
:func:`nx.readwrite.text.generate_network_text`, which should be used
|
||||
instead.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
graph : nx.DiGraph | nx.Graph
|
||||
Graph to represent (must be a tree, forest, or the empty graph)
|
||||
|
||||
with_labels : bool
|
||||
If True will use the "label" attribute of a node to display if it
|
||||
exists otherwise it will use the node value itself. Defaults to True.
|
||||
|
||||
sources : List
|
||||
Mainly relevant for undirected forests, specifies which nodes to list
|
||||
first. If unspecified the root nodes of each tree will be used for
|
||||
directed forests; for undirected forests this defaults to the nodes
|
||||
with the smallest degree.
|
||||
|
||||
write : callable
|
||||
Function to use to write to, if None new lines are appended to
|
||||
a list and returned. If set to the `print` function, lines will
|
||||
be written to stdout as they are generated. If specified,
|
||||
this function will return None. Defaults to None.
|
||||
|
||||
ascii_only : Boolean
|
||||
If True only ASCII characters are used to construct the visualization
|
||||
|
||||
Returns
|
||||
-------
|
||||
str | None :
|
||||
utf8 representation of the tree / forest
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> graph = nx.balanced_tree(r=2, h=3, create_using=nx.DiGraph)
|
||||
>>> print(nx.forest_str(graph))
|
||||
╙── 0
|
||||
├─╼ 1
|
||||
│ ├─╼ 3
|
||||
│ │ ├─╼ 7
|
||||
│ │ └─╼ 8
|
||||
│ └─╼ 4
|
||||
│ ├─╼ 9
|
||||
│ └─╼ 10
|
||||
└─╼ 2
|
||||
├─╼ 5
|
||||
│ ├─╼ 11
|
||||
│ └─╼ 12
|
||||
└─╼ 6
|
||||
├─╼ 13
|
||||
└─╼ 14
|
||||
|
||||
|
||||
>>> graph = nx.balanced_tree(r=1, h=2, create_using=nx.Graph)
|
||||
>>> print(nx.forest_str(graph))
|
||||
╙── 0
|
||||
└── 1
|
||||
└── 2
|
||||
|
||||
>>> print(nx.forest_str(graph, ascii_only=True))
|
||||
+-- 0
|
||||
L-- 1
|
||||
L-- 2
|
||||
"""
|
||||
msg = (
|
||||
"\nforest_str is deprecated as of version 3.1 and will be removed "
|
||||
"in version 3.3. Use generate_network_text or write_network_text "
|
||||
"instead.\n"
|
||||
)
|
||||
warnings.warn(msg, DeprecationWarning)
|
||||
|
||||
if len(graph.nodes) > 0:
|
||||
if not nx.is_forest(graph):
|
||||
raise nx.NetworkXNotImplemented("input must be a forest or the empty graph")
|
||||
|
||||
printbuf = []
|
||||
if write is None:
|
||||
_write = printbuf.append
|
||||
else:
|
||||
_write = write
|
||||
|
||||
write_network_text(
|
||||
graph,
|
||||
_write,
|
||||
with_labels=with_labels,
|
||||
sources=sources,
|
||||
ascii_only=ascii_only,
|
||||
end="",
|
||||
)
|
||||
|
||||
if write is None:
|
||||
# Only return a string if the custom write function was not specified
|
||||
return "\n".join(printbuf)
|
||||
Reference in New Issue
Block a user