112 lines
3.3 KiB
Python
112 lines
3.3 KiB
Python
from itertools import chain
|
|
from itertools import count
|
|
|
|
import easygraph as eg
|
|
|
|
|
|
__all__ = ["node_link_graph"]
|
|
|
|
|
|
_attrs = dict(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_graph(data, directed=False, multigraph=True, attrs=None):
|
|
"""Returns graph from node-link data format.
|
|
|
|
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')
|
|
|
|
Returns
|
|
-------
|
|
G : EasyGraph graph
|
|
A EasyGraph graph object
|
|
|
|
Examples
|
|
--------
|
|
>>> from easygraph.readwrite import json_graph
|
|
>>> G = eg.Graph([("A", "B")])
|
|
>>> data = json_graph.node_link_data(G)
|
|
>>> H = json_graph.node_link_graph(data)
|
|
|
|
Notes
|
|
-----
|
|
Attribute 'key' is only used for multigraphs.
|
|
|
|
See Also
|
|
--------
|
|
node_link_data, adjacency_data, tree_data
|
|
"""
|
|
# Allow 'attrs' to keep default values.
|
|
if attrs is None:
|
|
attrs = _attrs
|
|
else:
|
|
attrs.update({k: v for k, v in _attrs.items() if k not in attrs})
|
|
multigraph = data.get("multigraph", multigraph)
|
|
directed = data.get("directed", directed)
|
|
if multigraph:
|
|
graph = eg.MultiGraph()
|
|
else:
|
|
graph = eg.Graph()
|
|
if directed:
|
|
graph = graph.to_directed()
|
|
name = attrs["name"]
|
|
source = attrs["source"]
|
|
target = attrs["target"]
|
|
links = attrs["link"]
|
|
# Allow 'key' to be omitted from attrs if the graph is not a multigraph.
|
|
key = None if not multigraph else attrs["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[links]:
|
|
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
|