123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- 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
|