| | """Functions to convert NetworkX graphs to and from other formats. |
| | |
| | The preferred way of converting data to a NetworkX graph is through the |
| | graph constructor. The constructor calls the to_networkx_graph() function |
| | which attempts to guess the input type and convert it automatically. |
| | |
| | Examples |
| | -------- |
| | Create a graph with a single edge from a dictionary of dictionaries |
| | |
| | >>> d = {0: {1: 1}} # dict-of-dicts single edge (0,1) |
| | >>> G = nx.Graph(d) |
| | |
| | See Also |
| | -------- |
| | nx_agraph, nx_pydot |
| | """ |
| | import warnings |
| | from collections.abc import Collection, Generator, Iterator |
| |
|
| | import networkx as nx |
| |
|
| | __all__ = [ |
| | "to_networkx_graph", |
| | "from_dict_of_dicts", |
| | "to_dict_of_dicts", |
| | "from_dict_of_lists", |
| | "to_dict_of_lists", |
| | "from_edgelist", |
| | "to_edgelist", |
| | ] |
| |
|
| |
|
| | def to_networkx_graph(data, create_using=None, multigraph_input=False): |
| | """Make a NetworkX graph from a known data structure. |
| | |
| | The preferred way to call this is automatically |
| | from the class constructor |
| | |
| | >>> d = {0: {1: {"weight": 1}}} # dict-of-dicts single edge (0,1) |
| | >>> G = nx.Graph(d) |
| | |
| | instead of the equivalent |
| | |
| | >>> G = nx.from_dict_of_dicts(d) |
| | |
| | Parameters |
| | ---------- |
| | data : object to be converted |
| | |
| | Current known types are: |
| | any NetworkX graph |
| | dict-of-dicts |
| | dict-of-lists |
| | container (e.g. set, list, tuple) of edges |
| | iterator (e.g. itertools.chain) that produces edges |
| | generator of edges |
| | Pandas DataFrame (row per edge) |
| | 2D numpy array |
| | scipy sparse array |
| | pygraphviz agraph |
| | |
| | create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| | Graph type to create. If graph instance, then cleared before populated. |
| | |
| | multigraph_input : bool (default False) |
| | If True and data is a dict_of_dicts, |
| | try to create a multigraph assuming dict_of_dict_of_lists. |
| | If data and create_using are both multigraphs then create |
| | a multigraph from a multigraph. |
| | |
| | """ |
| | |
| | if hasattr(data, "adj"): |
| | try: |
| | result = from_dict_of_dicts( |
| | data.adj, |
| | create_using=create_using, |
| | multigraph_input=data.is_multigraph(), |
| | ) |
| | |
| | result.graph.update(data.graph) |
| | |
| | |
| | |
| | |
| | for n, dd in data.nodes.items(): |
| | result._node[n].update(dd) |
| | return result |
| | except Exception as err: |
| | raise nx.NetworkXError("Input is not a correct NetworkX graph.") from err |
| |
|
| | |
| | if hasattr(data, "is_strict"): |
| | try: |
| | return nx.nx_agraph.from_agraph(data, create_using=create_using) |
| | except Exception as err: |
| | raise nx.NetworkXError("Input is not a correct pygraphviz graph.") from err |
| |
|
| | |
| | if isinstance(data, dict): |
| | try: |
| | return from_dict_of_dicts( |
| | data, create_using=create_using, multigraph_input=multigraph_input |
| | ) |
| | except Exception as err1: |
| | if multigraph_input is True: |
| | raise nx.NetworkXError( |
| | f"converting multigraph_input raised:\n{type(err1)}: {err1}" |
| | ) |
| | try: |
| | return from_dict_of_lists(data, create_using=create_using) |
| | except Exception as err2: |
| | raise TypeError("Input is not known type.") from err2 |
| |
|
| | |
| | try: |
| | import pandas as pd |
| |
|
| | if isinstance(data, pd.DataFrame): |
| | if data.shape[0] == data.shape[1]: |
| | try: |
| | return nx.from_pandas_adjacency(data, create_using=create_using) |
| | except Exception as err: |
| | msg = "Input is not a correct Pandas DataFrame adjacency matrix." |
| | raise nx.NetworkXError(msg) from err |
| | else: |
| | try: |
| | return nx.from_pandas_edgelist( |
| | data, edge_attr=True, create_using=create_using |
| | ) |
| | except Exception as err: |
| | msg = "Input is not a correct Pandas DataFrame edge-list." |
| | raise nx.NetworkXError(msg) from err |
| | except ImportError: |
| | warnings.warn("pandas not found, skipping conversion test.", ImportWarning) |
| |
|
| | |
| | try: |
| | import numpy as np |
| |
|
| | if isinstance(data, np.ndarray): |
| | try: |
| | return nx.from_numpy_array(data, create_using=create_using) |
| | except Exception as err: |
| | raise nx.NetworkXError( |
| | f"Failed to interpret array as an adjacency matrix." |
| | ) from err |
| | except ImportError: |
| | warnings.warn("numpy not found, skipping conversion test.", ImportWarning) |
| |
|
| | |
| | try: |
| | import scipy |
| |
|
| | if hasattr(data, "format"): |
| | try: |
| | return nx.from_scipy_sparse_array(data, create_using=create_using) |
| | except Exception as err: |
| | raise nx.NetworkXError( |
| | "Input is not a correct scipy sparse array type." |
| | ) from err |
| | except ImportError: |
| | warnings.warn("scipy not found, skipping conversion test.", ImportWarning) |
| |
|
| | |
| | |
| | |
| |
|
| | if isinstance(data, Collection | Generator | Iterator): |
| | try: |
| | return from_edgelist(data, create_using=create_using) |
| | except Exception as err: |
| | raise nx.NetworkXError("Input is not a valid edge list") from err |
| |
|
| | raise nx.NetworkXError("Input is not a known data type for conversion.") |
| |
|
| |
|
| | @nx._dispatchable |
| | def to_dict_of_lists(G, nodelist=None): |
| | """Returns adjacency representation of graph as a dictionary of lists. |
| | |
| | Parameters |
| | ---------- |
| | G : graph |
| | A NetworkX graph |
| | |
| | nodelist : list |
| | Use only nodes specified in nodelist |
| | |
| | Notes |
| | ----- |
| | Completely ignores edge data for MultiGraph and MultiDiGraph. |
| | |
| | """ |
| | if nodelist is None: |
| | nodelist = G |
| |
|
| | d = {} |
| | for n in nodelist: |
| | d[n] = [nbr for nbr in G.neighbors(n) if nbr in nodelist] |
| | return d |
| |
|
| |
|
| | @nx._dispatchable(graphs=None, returns_graph=True) |
| | def from_dict_of_lists(d, create_using=None): |
| | """Returns a graph from a dictionary of lists. |
| | |
| | Parameters |
| | ---------- |
| | d : dictionary of lists |
| | A dictionary of lists adjacency representation. |
| | |
| | create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| | Graph type to create. If graph instance, then cleared before populated. |
| | |
| | Examples |
| | -------- |
| | >>> dol = {0: [1]} # single edge (0,1) |
| | >>> G = nx.from_dict_of_lists(dol) |
| | |
| | or |
| | |
| | >>> G = nx.Graph(dol) # use Graph constructor |
| | |
| | """ |
| | G = nx.empty_graph(0, create_using) |
| | G.add_nodes_from(d) |
| | if G.is_multigraph() and not G.is_directed(): |
| | |
| | |
| | |
| | seen = {} |
| | for node, nbrlist in d.items(): |
| | for nbr in nbrlist: |
| | if nbr not in seen: |
| | G.add_edge(node, nbr) |
| | seen[node] = 1 |
| | else: |
| | G.add_edges_from( |
| | ((node, nbr) for node, nbrlist in d.items() for nbr in nbrlist) |
| | ) |
| | return G |
| |
|
| |
|
| | def to_dict_of_dicts(G, nodelist=None, edge_data=None): |
| | """Returns adjacency representation of graph as a dictionary of dictionaries. |
| | |
| | Parameters |
| | ---------- |
| | G : graph |
| | A NetworkX graph |
| | |
| | nodelist : list |
| | Use only nodes specified in nodelist |
| | |
| | edge_data : scalar, optional |
| | If provided, the value of the dictionary will be set to `edge_data` for |
| | all edges. Usual values could be `1` or `True`. If `edge_data` is |
| | `None` (the default), the edgedata in `G` is used, resulting in a |
| | dict-of-dict-of-dicts. If `G` is a MultiGraph, the result will be a |
| | dict-of-dict-of-dict-of-dicts. See Notes for an approach to customize |
| | handling edge data. `edge_data` should *not* be a container. |
| | |
| | Returns |
| | ------- |
| | dod : dict |
| | A nested dictionary representation of `G`. Note that the level of |
| | nesting depends on the type of `G` and the value of `edge_data` |
| | (see Examples). |
| | |
| | See Also |
| | -------- |
| | from_dict_of_dicts, to_dict_of_lists |
| | |
| | Notes |
| | ----- |
| | For a more custom approach to handling edge data, try:: |
| | |
| | dod = { |
| | n: {nbr: custom(n, nbr, dd) for nbr, dd in nbrdict.items()} |
| | for n, nbrdict in G.adj.items() |
| | } |
| | |
| | where `custom` returns the desired edge data for each edge between `n` and |
| | `nbr`, given existing edge data `dd`. |
| | |
| | Examples |
| | -------- |
| | >>> G = nx.path_graph(3) |
| | >>> nx.to_dict_of_dicts(G) |
| | {0: {1: {}}, 1: {0: {}, 2: {}}, 2: {1: {}}} |
| | |
| | Edge data is preserved by default (``edge_data=None``), resulting |
| | in dict-of-dict-of-dicts where the innermost dictionary contains the |
| | edge data: |
| | |
| | >>> G = nx.Graph() |
| | >>> G.add_edges_from( |
| | ... [ |
| | ... (0, 1, {"weight": 1.0}), |
| | ... (1, 2, {"weight": 2.0}), |
| | ... (2, 0, {"weight": 1.0}), |
| | ... ] |
| | ... ) |
| | >>> d = nx.to_dict_of_dicts(G) |
| | >>> d # doctest: +SKIP |
| | {0: {1: {'weight': 1.0}, 2: {'weight': 1.0}}, |
| | 1: {0: {'weight': 1.0}, 2: {'weight': 2.0}}, |
| | 2: {1: {'weight': 2.0}, 0: {'weight': 1.0}}} |
| | >>> d[1][2]["weight"] |
| | 2.0 |
| | |
| | If `edge_data` is not `None`, edge data in the original graph (if any) is |
| | replaced: |
| | |
| | >>> d = nx.to_dict_of_dicts(G, edge_data=1) |
| | >>> d |
| | {0: {1: 1, 2: 1}, 1: {0: 1, 2: 1}, 2: {1: 1, 0: 1}} |
| | >>> d[1][2] |
| | 1 |
| | |
| | This also applies to MultiGraphs: edge data is preserved by default: |
| | |
| | >>> G = nx.MultiGraph() |
| | >>> G.add_edge(0, 1, key="a", weight=1.0) |
| | 'a' |
| | >>> G.add_edge(0, 1, key="b", weight=5.0) |
| | 'b' |
| | >>> d = nx.to_dict_of_dicts(G) |
| | >>> d # doctest: +SKIP |
| | {0: {1: {'a': {'weight': 1.0}, 'b': {'weight': 5.0}}}, |
| | 1: {0: {'a': {'weight': 1.0}, 'b': {'weight': 5.0}}}} |
| | >>> d[0][1]["b"]["weight"] |
| | 5.0 |
| | |
| | But multi edge data is lost if `edge_data` is not `None`: |
| | |
| | >>> d = nx.to_dict_of_dicts(G, edge_data=10) |
| | >>> d |
| | {0: {1: 10}, 1: {0: 10}} |
| | """ |
| | dod = {} |
| | if nodelist is None: |
| | if edge_data is None: |
| | for u, nbrdict in G.adjacency(): |
| | dod[u] = nbrdict.copy() |
| | else: |
| | for u, nbrdict in G.adjacency(): |
| | dod[u] = dod.fromkeys(nbrdict, edge_data) |
| | else: |
| | if edge_data is None: |
| | for u in nodelist: |
| | dod[u] = {} |
| | for v, data in ((v, data) for v, data in G[u].items() if v in nodelist): |
| | dod[u][v] = data |
| | else: |
| | for u in nodelist: |
| | dod[u] = {} |
| | for v in (v for v in G[u] if v in nodelist): |
| | dod[u][v] = edge_data |
| | return dod |
| |
|
| |
|
| | @nx._dispatchable(graphs=None, returns_graph=True) |
| | def from_dict_of_dicts(d, create_using=None, multigraph_input=False): |
| | """Returns a graph from a dictionary of dictionaries. |
| | |
| | Parameters |
| | ---------- |
| | d : dictionary of dictionaries |
| | A dictionary of dictionaries adjacency representation. |
| | |
| | create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| | Graph type to create. If graph instance, then cleared before populated. |
| | |
| | multigraph_input : bool (default False) |
| | When True, the dict `d` is assumed |
| | to be a dict-of-dict-of-dict-of-dict structure keyed by |
| | node to neighbor to edge keys to edge data for multi-edges. |
| | Otherwise this routine assumes dict-of-dict-of-dict keyed by |
| | node to neighbor to edge data. |
| | |
| | Examples |
| | -------- |
| | >>> dod = {0: {1: {"weight": 1}}} # single edge (0,1) |
| | >>> G = nx.from_dict_of_dicts(dod) |
| | |
| | or |
| | |
| | >>> G = nx.Graph(dod) # use Graph constructor |
| | |
| | """ |
| | G = nx.empty_graph(0, create_using) |
| | G.add_nodes_from(d) |
| | |
| | if multigraph_input: |
| | if G.is_directed(): |
| | if G.is_multigraph(): |
| | G.add_edges_from( |
| | (u, v, key, data) |
| | for u, nbrs in d.items() |
| | for v, datadict in nbrs.items() |
| | for key, data in datadict.items() |
| | ) |
| | else: |
| | G.add_edges_from( |
| | (u, v, data) |
| | for u, nbrs in d.items() |
| | for v, datadict in nbrs.items() |
| | for key, data in datadict.items() |
| | ) |
| | else: |
| | if G.is_multigraph(): |
| | seen = set() |
| | for u, nbrs in d.items(): |
| | for v, datadict in nbrs.items(): |
| | if (u, v) not in seen: |
| | G.add_edges_from( |
| | (u, v, key, data) for key, data in datadict.items() |
| | ) |
| | seen.add((v, u)) |
| | else: |
| | seen = set() |
| | for u, nbrs in d.items(): |
| | for v, datadict in nbrs.items(): |
| | if (u, v) not in seen: |
| | G.add_edges_from( |
| | (u, v, data) for key, data in datadict.items() |
| | ) |
| | seen.add((v, u)) |
| |
|
| | else: |
| | if G.is_multigraph() and not G.is_directed(): |
| | |
| | |
| | |
| | seen = set() |
| | for u, nbrs in d.items(): |
| | for v, data in nbrs.items(): |
| | if (u, v) not in seen: |
| | G.add_edge(u, v, key=0) |
| | G[u][v][0].update(data) |
| | seen.add((v, u)) |
| | else: |
| | G.add_edges_from( |
| | ((u, v, data) for u, nbrs in d.items() for v, data in nbrs.items()) |
| | ) |
| | return G |
| |
|
| |
|
| | @nx._dispatchable(preserve_edge_attrs=True) |
| | def to_edgelist(G, nodelist=None): |
| | """Returns a list of edges in the graph. |
| | |
| | Parameters |
| | ---------- |
| | G : graph |
| | A NetworkX graph |
| | |
| | nodelist : list |
| | Use only nodes specified in nodelist |
| | |
| | """ |
| | if nodelist is None: |
| | return G.edges(data=True) |
| | return G.edges(nodelist, data=True) |
| |
|
| |
|
| | @nx._dispatchable(graphs=None, returns_graph=True) |
| | def from_edgelist(edgelist, create_using=None): |
| | """Returns a graph from a list of edges. |
| | |
| | Parameters |
| | ---------- |
| | edgelist : list or iterator |
| | Edge tuples |
| | |
| | create_using : NetworkX graph constructor, optional (default=nx.Graph) |
| | Graph type to create. If graph instance, then cleared before populated. |
| | |
| | Examples |
| | -------- |
| | >>> edgelist = [(0, 1)] # single edge (0,1) |
| | >>> G = nx.from_edgelist(edgelist) |
| | |
| | or |
| | |
| | >>> G = nx.Graph(edgelist) # use Graph constructor |
| | |
| | """ |
| | G = nx.empty_graph(0, create_using) |
| | G.add_edges_from(edgelist) |
| | return G |
| |
|