comparison env/lib/python3.9/site-packages/networkx/convert.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """Functions to convert NetworkX graphs to and from other formats.
2
3 The preferred way of converting data to a NetworkX graph is through the
4 graph constructor. The constructor calls the to_networkx_graph() function
5 which attempts to guess the input type and convert it automatically.
6
7 Examples
8 --------
9 Create a graph with a single edge from a dictionary of dictionaries
10
11 >>> d = {0: {1: 1}} # dict-of-dicts single edge (0,1)
12 >>> G = nx.Graph(d)
13
14 See Also
15 --------
16 nx_agraph, nx_pydot
17 """
18 import warnings
19 import networkx as nx
20 from collections.abc import Collection, Generator, Iterator
21
22 __all__ = [
23 "to_networkx_graph",
24 "from_dict_of_dicts",
25 "to_dict_of_dicts",
26 "from_dict_of_lists",
27 "to_dict_of_lists",
28 "from_edgelist",
29 "to_edgelist",
30 ]
31
32
33 def to_networkx_graph(data, create_using=None, multigraph_input=False):
34 """Make a NetworkX graph from a known data structure.
35
36 The preferred way to call this is automatically
37 from the class constructor
38
39 >>> d = {0: {1: {"weight": 1}}} # dict-of-dicts single edge (0,1)
40 >>> G = nx.Graph(d)
41
42 instead of the equivalent
43
44 >>> G = nx.from_dict_of_dicts(d)
45
46 Parameters
47 ----------
48 data : object to be converted
49
50 Current known types are:
51 any NetworkX graph
52 dict-of-dicts
53 dict-of-lists
54 container (e.g. set, list, tuple) of edges
55 iterator (e.g. itertools.chain) that produces edges
56 generator of edges
57 Pandas DataFrame (row per edge)
58 numpy matrix
59 numpy ndarray
60 scipy sparse matrix
61 pygraphviz agraph
62
63 create_using : NetworkX graph constructor, optional (default=nx.Graph)
64 Graph type to create. If graph instance, then cleared before populated.
65
66 multigraph_input : bool (default False)
67 If True and data is a dict_of_dicts,
68 try to create a multigraph assuming dict_of_dict_of_lists.
69 If data and create_using are both multigraphs then create
70 a multigraph from a multigraph.
71
72 """
73 # NX graph
74 if hasattr(data, "adj"):
75 try:
76 result = from_dict_of_dicts(
77 data.adj,
78 create_using=create_using,
79 multigraph_input=data.is_multigraph(),
80 )
81 if hasattr(data, "graph"): # data.graph should be dict-like
82 result.graph.update(data.graph)
83 if hasattr(data, "nodes"): # data.nodes should be dict-like
84 # result.add_node_from(data.nodes.items()) possible but
85 # for custom node_attr_dict_factory which may be hashable
86 # will be unexpected behavior
87 for n, dd in data.nodes.items():
88 result._node[n].update(dd)
89 return result
90 except Exception as e:
91 raise nx.NetworkXError("Input is not a correct NetworkX graph.") from e
92
93 # pygraphviz agraph
94 if hasattr(data, "is_strict"):
95 try:
96 return nx.nx_agraph.from_agraph(data, create_using=create_using)
97 except Exception as e:
98 raise nx.NetworkXError("Input is not a correct pygraphviz graph.") from e
99
100 # dict of dicts/lists
101 if isinstance(data, dict):
102 try:
103 return from_dict_of_dicts(
104 data, create_using=create_using, multigraph_input=multigraph_input
105 )
106 except:
107 try:
108 return from_dict_of_lists(data, create_using=create_using)
109 except Exception as e:
110 raise TypeError("Input is not known type.") from e
111
112 # Pandas DataFrame
113 try:
114 import pandas as pd
115
116 if isinstance(data, pd.DataFrame):
117 if data.shape[0] == data.shape[1]:
118 try:
119 return nx.from_pandas_adjacency(data, create_using=create_using)
120 except Exception as e:
121 msg = "Input is not a correct Pandas DataFrame adjacency matrix."
122 raise nx.NetworkXError(msg) from e
123 else:
124 try:
125 return nx.from_pandas_edgelist(
126 data, edge_attr=True, create_using=create_using
127 )
128 except Exception as e:
129 msg = "Input is not a correct Pandas DataFrame edge-list."
130 raise nx.NetworkXError(msg) from e
131 except ImportError:
132 msg = "pandas not found, skipping conversion test."
133 warnings.warn(msg, ImportWarning)
134
135 # numpy matrix or ndarray
136 try:
137 import numpy
138
139 if isinstance(data, (numpy.matrix, numpy.ndarray)):
140 try:
141 return nx.from_numpy_matrix(data, create_using=create_using)
142 except Exception as e:
143 raise nx.NetworkXError(
144 "Input is not a correct numpy matrix or array."
145 ) from e
146 except ImportError:
147 warnings.warn("numpy not found, skipping conversion test.", ImportWarning)
148
149 # scipy sparse matrix - any format
150 try:
151 import scipy
152
153 if hasattr(data, "format"):
154 try:
155 return nx.from_scipy_sparse_matrix(data, create_using=create_using)
156 except Exception as e:
157 raise nx.NetworkXError(
158 "Input is not a correct scipy sparse matrix type."
159 ) from e
160 except ImportError:
161 warnings.warn("scipy not found, skipping conversion test.", ImportWarning)
162
163 # Note: most general check - should remain last in order of execution
164 # Includes containers (e.g. list, set, dict, etc.), generators, and
165 # iterators (e.g. itertools.chain) of edges
166
167 if isinstance(data, (Collection, Generator, Iterator)):
168 try:
169 return from_edgelist(data, create_using=create_using)
170 except Exception as e:
171 raise nx.NetworkXError("Input is not a valid edge list") from e
172
173 raise nx.NetworkXError("Input is not a known data type for conversion.")
174
175
176 def to_dict_of_lists(G, nodelist=None):
177 """Returns adjacency representation of graph as a dictionary of lists.
178
179 Parameters
180 ----------
181 G : graph
182 A NetworkX graph
183
184 nodelist : list
185 Use only nodes specified in nodelist
186
187 Notes
188 -----
189 Completely ignores edge data for MultiGraph and MultiDiGraph.
190
191 """
192 if nodelist is None:
193 nodelist = G
194
195 d = {}
196 for n in nodelist:
197 d[n] = [nbr for nbr in G.neighbors(n) if nbr in nodelist]
198 return d
199
200
201 def from_dict_of_lists(d, create_using=None):
202 """Returns a graph from a dictionary of lists.
203
204 Parameters
205 ----------
206 d : dictionary of lists
207 A dictionary of lists adjacency representation.
208
209 create_using : NetworkX graph constructor, optional (default=nx.Graph)
210 Graph type to create. If graph instance, then cleared before populated.
211
212 Examples
213 --------
214 >>> dol = {0: [1]} # single edge (0,1)
215 >>> G = nx.from_dict_of_lists(dol)
216
217 or
218
219 >>> G = nx.Graph(dol) # use Graph constructor
220
221 """
222 G = nx.empty_graph(0, create_using)
223 G.add_nodes_from(d)
224 if G.is_multigraph() and not G.is_directed():
225 # a dict_of_lists can't show multiedges. BUT for undirected graphs,
226 # each edge shows up twice in the dict_of_lists.
227 # So we need to treat this case separately.
228 seen = {}
229 for node, nbrlist in d.items():
230 for nbr in nbrlist:
231 if nbr not in seen:
232 G.add_edge(node, nbr)
233 seen[node] = 1 # don't allow reverse edge to show up
234 else:
235 G.add_edges_from(
236 ((node, nbr) for node, nbrlist in d.items() for nbr in nbrlist)
237 )
238 return G
239
240
241 def to_dict_of_dicts(G, nodelist=None, edge_data=None):
242 """Returns adjacency representation of graph as a dictionary of dictionaries.
243
244 Parameters
245 ----------
246 G : graph
247 A NetworkX graph
248
249 nodelist : list
250 Use only nodes specified in nodelist
251
252 edge_data : list, optional
253 If provided, the value of the dictionary will be
254 set to edge_data for all edges. This is useful to make
255 an adjacency matrix type representation with 1 as the edge data.
256 If edgedata is None, the edgedata in G is used to fill the values.
257 If G is a multigraph, the edgedata is a dict for each pair (u,v).
258 """
259 dod = {}
260 if nodelist is None:
261 if edge_data is None:
262 for u, nbrdict in G.adjacency():
263 dod[u] = nbrdict.copy()
264 else: # edge_data is not None
265 for u, nbrdict in G.adjacency():
266 dod[u] = dod.fromkeys(nbrdict, edge_data)
267 else: # nodelist is not None
268 if edge_data is None:
269 for u in nodelist:
270 dod[u] = {}
271 for v, data in ((v, data) for v, data in G[u].items() if v in nodelist):
272 dod[u][v] = data
273 else: # nodelist and edge_data are not None
274 for u in nodelist:
275 dod[u] = {}
276 for v in (v for v in G[u] if v in nodelist):
277 dod[u][v] = edge_data
278 return dod
279
280
281 def from_dict_of_dicts(d, create_using=None, multigraph_input=False):
282 """Returns a graph from a dictionary of dictionaries.
283
284 Parameters
285 ----------
286 d : dictionary of dictionaries
287 A dictionary of dictionaries adjacency representation.
288
289 create_using : NetworkX graph constructor, optional (default=nx.Graph)
290 Graph type to create. If graph instance, then cleared before populated.
291
292 multigraph_input : bool (default False)
293 When True, the values of the inner dict are assumed
294 to be containers of edge data for multiple edges.
295 Otherwise this routine assumes the edge data are singletons.
296
297 Examples
298 --------
299 >>> dod = {0: {1: {"weight": 1}}} # single edge (0,1)
300 >>> G = nx.from_dict_of_dicts(dod)
301
302 or
303
304 >>> G = nx.Graph(dod) # use Graph constructor
305
306 """
307 G = nx.empty_graph(0, create_using)
308 G.add_nodes_from(d)
309 # is dict a MultiGraph or MultiDiGraph?
310 if multigraph_input:
311 # make a copy of the list of edge data (but not the edge data)
312 if G.is_directed():
313 if G.is_multigraph():
314 G.add_edges_from(
315 (u, v, key, data)
316 for u, nbrs in d.items()
317 for v, datadict in nbrs.items()
318 for key, data in datadict.items()
319 )
320 else:
321 G.add_edges_from(
322 (u, v, data)
323 for u, nbrs in d.items()
324 for v, datadict in nbrs.items()
325 for key, data in datadict.items()
326 )
327 else: # Undirected
328 if G.is_multigraph():
329 seen = set() # don't add both directions of undirected graph
330 for u, nbrs in d.items():
331 for v, datadict in nbrs.items():
332 if (u, v) not in seen:
333 G.add_edges_from(
334 (u, v, key, data) for key, data in datadict.items()
335 )
336 seen.add((v, u))
337 else:
338 seen = set() # don't add both directions of undirected graph
339 for u, nbrs in d.items():
340 for v, datadict in nbrs.items():
341 if (u, v) not in seen:
342 G.add_edges_from(
343 (u, v, data) for key, data in datadict.items()
344 )
345 seen.add((v, u))
346
347 else: # not a multigraph to multigraph transfer
348 if G.is_multigraph() and not G.is_directed():
349 # d can have both representations u-v, v-u in dict. Only add one.
350 # We don't need this check for digraphs since we add both directions,
351 # or for Graph() since it is done implicitly (parallel edges not allowed)
352 seen = set()
353 for u, nbrs in d.items():
354 for v, data in nbrs.items():
355 if (u, v) not in seen:
356 G.add_edge(u, v, key=0)
357 G[u][v][0].update(data)
358 seen.add((v, u))
359 else:
360 G.add_edges_from(
361 ((u, v, data) for u, nbrs in d.items() for v, data in nbrs.items())
362 )
363 return G
364
365
366 def to_edgelist(G, nodelist=None):
367 """Returns a list of edges in the graph.
368
369 Parameters
370 ----------
371 G : graph
372 A NetworkX graph
373
374 nodelist : list
375 Use only nodes specified in nodelist
376
377 """
378 if nodelist is None:
379 return G.edges(data=True)
380 return G.edges(nodelist, data=True)
381
382
383 def from_edgelist(edgelist, create_using=None):
384 """Returns a graph from a list of edges.
385
386 Parameters
387 ----------
388 edgelist : list or iterator
389 Edge tuples
390
391 create_using : NetworkX graph constructor, optional (default=nx.Graph)
392 Graph type to create. If graph instance, then cleared before populated.
393
394 Examples
395 --------
396 >>> edgelist = [(0, 1)] # single edge (0,1)
397 >>> G = nx.from_edgelist(edgelist)
398
399 or
400
401 >>> G = nx.Graph(edgelist) # use Graph constructor
402
403 """
404 G = nx.empty_graph(0, create_using)
405 G.add_edges_from(edgelist)
406 return G