Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/networkx/classes/digraph.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 # Copyright (C) 2004-2019 by | |
2 # Aric Hagberg <hagberg@lanl.gov> | |
3 # Dan Schult <dschult@colgate.edu> | |
4 # Pieter Swart <swart@lanl.gov> | |
5 # All rights reserved. | |
6 # BSD license. | |
7 # | |
8 # Authors: Aric Hagberg <hagberg@lanl.gov> | |
9 # Dan Schult <dschult@colgate.edu> | |
10 # Pieter Swart <swart@lanl.gov> | |
11 """Base class for directed graphs.""" | |
12 from copy import deepcopy | |
13 | |
14 import networkx as nx | |
15 from networkx.classes.graph import Graph | |
16 from networkx.classes.coreviews import AdjacencyView | |
17 from networkx.classes.reportviews import OutEdgeView, InEdgeView, \ | |
18 DiDegreeView, InDegreeView, OutDegreeView | |
19 from networkx.exception import NetworkXError | |
20 import networkx.convert as convert | |
21 | |
22 | |
23 class DiGraph(Graph): | |
24 """ | |
25 Base class for directed graphs. | |
26 | |
27 A DiGraph stores nodes and edges with optional data, or attributes. | |
28 | |
29 DiGraphs hold directed edges. Self loops are allowed but multiple | |
30 (parallel) edges are not. | |
31 | |
32 Nodes can be arbitrary (hashable) Python objects with optional | |
33 key/value attributes. By convention `None` is not used as a node. | |
34 | |
35 Edges are represented as links between nodes with optional | |
36 key/value attributes. | |
37 | |
38 Parameters | |
39 ---------- | |
40 incoming_graph_data : input graph (optional, default: None) | |
41 Data to initialize graph. If None (default) an empty | |
42 graph is created. The data can be any format that is supported | |
43 by the to_networkx_graph() function, currently including edge list, | |
44 dict of dicts, dict of lists, NetworkX graph, NumPy matrix | |
45 or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. | |
46 | |
47 attr : keyword arguments, optional (default= no attributes) | |
48 Attributes to add to graph as key=value pairs. | |
49 | |
50 See Also | |
51 -------- | |
52 Graph | |
53 MultiGraph | |
54 MultiDiGraph | |
55 OrderedDiGraph | |
56 | |
57 Examples | |
58 -------- | |
59 Create an empty graph structure (a "null graph") with no nodes and | |
60 no edges. | |
61 | |
62 >>> G = nx.DiGraph() | |
63 | |
64 G can be grown in several ways. | |
65 | |
66 **Nodes:** | |
67 | |
68 Add one node at a time: | |
69 | |
70 >>> G.add_node(1) | |
71 | |
72 Add the nodes from any container (a list, dict, set or | |
73 even the lines from a file or the nodes from another graph). | |
74 | |
75 >>> G.add_nodes_from([2, 3]) | |
76 >>> G.add_nodes_from(range(100, 110)) | |
77 >>> H = nx.path_graph(10) | |
78 >>> G.add_nodes_from(H) | |
79 | |
80 In addition to strings and integers any hashable Python object | |
81 (except None) can represent a node, e.g. a customized node object, | |
82 or even another Graph. | |
83 | |
84 >>> G.add_node(H) | |
85 | |
86 **Edges:** | |
87 | |
88 G can also be grown by adding edges. | |
89 | |
90 Add one edge, | |
91 | |
92 >>> G.add_edge(1, 2) | |
93 | |
94 a list of edges, | |
95 | |
96 >>> G.add_edges_from([(1, 2), (1, 3)]) | |
97 | |
98 or a collection of edges, | |
99 | |
100 >>> G.add_edges_from(H.edges) | |
101 | |
102 If some edges connect nodes not yet in the graph, the nodes | |
103 are added automatically. There are no errors when adding | |
104 nodes or edges that already exist. | |
105 | |
106 **Attributes:** | |
107 | |
108 Each graph, node, and edge can hold key/value attribute pairs | |
109 in an associated attribute dictionary (the keys must be hashable). | |
110 By default these are empty, but can be added or changed using | |
111 add_edge, add_node or direct manipulation of the attribute | |
112 dictionaries named graph, node and edge respectively. | |
113 | |
114 >>> G = nx.DiGraph(day="Friday") | |
115 >>> G.graph | |
116 {'day': 'Friday'} | |
117 | |
118 Add node attributes using add_node(), add_nodes_from() or G.nodes | |
119 | |
120 >>> G.add_node(1, time='5pm') | |
121 >>> G.add_nodes_from([3], time='2pm') | |
122 >>> G.nodes[1] | |
123 {'time': '5pm'} | |
124 >>> G.nodes[1]['room'] = 714 | |
125 >>> del G.nodes[1]['room'] # remove attribute | |
126 >>> list(G.nodes(data=True)) | |
127 [(1, {'time': '5pm'}), (3, {'time': '2pm'})] | |
128 | |
129 Add edge attributes using add_edge(), add_edges_from(), subscript | |
130 notation, or G.edges. | |
131 | |
132 >>> G.add_edge(1, 2, weight=4.7 ) | |
133 >>> G.add_edges_from([(3, 4), (4, 5)], color='red') | |
134 >>> G.add_edges_from([(1, 2, {'color':'blue'}), (2, 3, {'weight':8})]) | |
135 >>> G[1][2]['weight'] = 4.7 | |
136 >>> G.edges[1, 2]['weight'] = 4 | |
137 | |
138 Warning: we protect the graph data structure by making `G.edges[1, 2]` a | |
139 read-only dict-like structure. However, you can assign to attributes | |
140 in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change | |
141 data attributes: `G.edges[1, 2]['weight'] = 4` | |
142 (For multigraphs: `MG.edges[u, v, key][name] = value`). | |
143 | |
144 **Shortcuts:** | |
145 | |
146 Many common graph features allow python syntax to speed reporting. | |
147 | |
148 >>> 1 in G # check if node in graph | |
149 True | |
150 >>> [n for n in G if n < 3] # iterate through nodes | |
151 [1, 2] | |
152 >>> len(G) # number of nodes in graph | |
153 5 | |
154 | |
155 Often the best way to traverse all edges of a graph is via the neighbors. | |
156 The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` | |
157 | |
158 >>> for n, nbrsdict in G.adjacency(): | |
159 ... for nbr, eattr in nbrsdict.items(): | |
160 ... if 'weight' in eattr: | |
161 ... # Do something useful with the edges | |
162 ... pass | |
163 | |
164 But the edges reporting object is often more convenient: | |
165 | |
166 >>> for u, v, weight in G.edges(data='weight'): | |
167 ... if weight is not None: | |
168 ... # Do something useful with the edges | |
169 ... pass | |
170 | |
171 **Reporting:** | |
172 | |
173 Simple graph information is obtained using object-attributes and methods. | |
174 Reporting usually provides views instead of containers to reduce memory | |
175 usage. The views update as the graph is updated similarly to dict-views. | |
176 The objects `nodes, `edges` and `adj` provide access to data attributes | |
177 via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration | |
178 (e.g. `nodes.items()`, `nodes.data('color')`, | |
179 `nodes.data('color', default='blue')` and similarly for `edges`) | |
180 Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. | |
181 | |
182 For details on these and other miscellaneous methods, see below. | |
183 | |
184 **Subclasses (Advanced):** | |
185 | |
186 The Graph class uses a dict-of-dict-of-dict data structure. | |
187 The outer dict (node_dict) holds adjacency information keyed by node. | |
188 The next dict (adjlist_dict) represents the adjacency information and holds | |
189 edge data keyed by neighbor. The inner dict (edge_attr_dict) represents | |
190 the edge data and holds edge attribute values keyed by attribute names. | |
191 | |
192 Each of these three dicts can be replaced in a subclass by a user defined | |
193 dict-like object. In general, the dict-like features should be | |
194 maintained but extra features can be added. To replace one of the | |
195 dicts create a new graph class by changing the class(!) variable | |
196 holding the factory for that dict-like structure. The variable names are | |
197 node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, | |
198 adjlist_outer_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory. | |
199 | |
200 node_dict_factory : function, (default: dict) | |
201 Factory function to be used to create the dict containing node | |
202 attributes, keyed by node id. | |
203 It should require no arguments and return a dict-like object | |
204 | |
205 node_attr_dict_factory: function, (default: dict) | |
206 Factory function to be used to create the node attribute | |
207 dict which holds attribute values keyed by attribute name. | |
208 It should require no arguments and return a dict-like object | |
209 | |
210 adjlist_outer_dict_factory : function, (default: dict) | |
211 Factory function to be used to create the outer-most dict | |
212 in the data structure that holds adjacency info keyed by node. | |
213 It should require no arguments and return a dict-like object. | |
214 | |
215 adjlist_inner_dict_factory : function, optional (default: dict) | |
216 Factory function to be used to create the adjacency list | |
217 dict which holds edge data keyed by neighbor. | |
218 It should require no arguments and return a dict-like object | |
219 | |
220 edge_attr_dict_factory : function, optional (default: dict) | |
221 Factory function to be used to create the edge attribute | |
222 dict which holds attribute values keyed by attribute name. | |
223 It should require no arguments and return a dict-like object. | |
224 | |
225 graph_attr_dict_factory : function, (default: dict) | |
226 Factory function to be used to create the graph attribute | |
227 dict which holds attribute values keyed by attribute name. | |
228 It should require no arguments and return a dict-like object. | |
229 | |
230 Typically, if your extension doesn't impact the data structure all | |
231 methods will inherited without issue except: `to_directed/to_undirected`. | |
232 By default these methods create a DiGraph/Graph class and you probably | |
233 want them to create your extension of a DiGraph/Graph. To facilitate | |
234 this we define two class variables that you can set in your subclass. | |
235 | |
236 to_directed_class : callable, (default: DiGraph or MultiDiGraph) | |
237 Class to create a new graph structure in the `to_directed` method. | |
238 If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. | |
239 | |
240 to_undirected_class : callable, (default: Graph or MultiGraph) | |
241 Class to create a new graph structure in the `to_undirected` method. | |
242 If `None`, a NetworkX class (Graph or MultiGraph) is used. | |
243 | |
244 Examples | |
245 -------- | |
246 | |
247 Create a low memory graph class that effectively disallows edge | |
248 attributes by using a single attribute dict for all edges. | |
249 This reduces the memory used, but you lose edge attributes. | |
250 | |
251 >>> class ThinGraph(nx.Graph): | |
252 ... all_edge_dict = {'weight': 1} | |
253 ... def single_edge_dict(self): | |
254 ... return self.all_edge_dict | |
255 ... edge_attr_dict_factory = single_edge_dict | |
256 >>> G = ThinGraph() | |
257 >>> G.add_edge(2, 1) | |
258 >>> G[2][1] | |
259 {'weight': 1} | |
260 >>> G.add_edge(2, 2) | |
261 >>> G[2][1] is G[2][2] | |
262 True | |
263 | |
264 | |
265 Please see :mod:`~networkx.classes.ordered` for more examples of | |
266 creating graph subclasses by overwriting the base class `dict` with | |
267 a dictionary-like object. | |
268 """ | |
269 | |
270 def __init__(self, incoming_graph_data=None, **attr): | |
271 """Initialize a graph with edges, name, or graph attributes. | |
272 | |
273 Parameters | |
274 ---------- | |
275 incoming_graph_data : input graph (optional, default: None) | |
276 Data to initialize graph. If None (default) an empty | |
277 graph is created. The data can be an edge list, or any | |
278 NetworkX graph object. If the corresponding optional Python | |
279 packages are installed the data can also be a NumPy matrix | |
280 or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. | |
281 | |
282 attr : keyword arguments, optional (default= no attributes) | |
283 Attributes to add to graph as key=value pairs. | |
284 | |
285 See Also | |
286 -------- | |
287 convert | |
288 | |
289 Examples | |
290 -------- | |
291 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
292 >>> G = nx.Graph(name='my graph') | |
293 >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges | |
294 >>> G = nx.Graph(e) | |
295 | |
296 Arbitrary graph attribute pairs (key=value) may be assigned | |
297 | |
298 >>> G = nx.Graph(e, day="Friday") | |
299 >>> G.graph | |
300 {'day': 'Friday'} | |
301 | |
302 """ | |
303 self.graph_attr_dict_factory = self.graph_attr_dict_factory | |
304 self.node_dict_factory = self.node_dict_factory | |
305 self.node_attr_dict_factory = self.node_attr_dict_factory | |
306 self.adjlist_outer_dict_factory = self.adjlist_outer_dict_factory | |
307 self.adjlist_inner_dict_factory = self.adjlist_inner_dict_factory | |
308 self.edge_attr_dict_factory = self.edge_attr_dict_factory | |
309 | |
310 self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes | |
311 self._node = self.node_dict_factory() # dictionary for node attr | |
312 # We store two adjacency lists: | |
313 # the predecessors of node n are stored in the dict self._pred | |
314 # the successors of node n are stored in the dict self._succ=self._adj | |
315 self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict | |
316 self._pred = self.adjlist_outer_dict_factory() # predecessor | |
317 self._succ = self._adj # successor | |
318 | |
319 # attempt to load graph with data | |
320 if incoming_graph_data is not None: | |
321 convert.to_networkx_graph(incoming_graph_data, create_using=self) | |
322 # load graph attributes (must be after convert) | |
323 self.graph.update(attr) | |
324 | |
325 @property | |
326 def adj(self): | |
327 """Graph adjacency object holding the neighbors of each node. | |
328 | |
329 This object is a read-only dict-like structure with node keys | |
330 and neighbor-dict values. The neighbor-dict is keyed by neighbor | |
331 to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets | |
332 the color of the edge `(3, 2)` to `"blue"`. | |
333 | |
334 Iterating over G.adj behaves like a dict. Useful idioms include | |
335 `for nbr, datadict in G.adj[n].items():`. | |
336 | |
337 The neighbor information is also provided by subscripting the graph. | |
338 So `for nbr, foovalue in G[node].data('foo', default=1):` works. | |
339 | |
340 For directed graphs, `G.adj` holds outgoing (successor) info. | |
341 """ | |
342 return AdjacencyView(self._succ) | |
343 | |
344 @property | |
345 def succ(self): | |
346 """Graph adjacency object holding the successors of each node. | |
347 | |
348 This object is a read-only dict-like structure with node keys | |
349 and neighbor-dict values. The neighbor-dict is keyed by neighbor | |
350 to the edge-data-dict. So `G.succ[3][2]['color'] = 'blue'` sets | |
351 the color of the edge `(3, 2)` to `"blue"`. | |
352 | |
353 Iterating over G.succ behaves like a dict. Useful idioms include | |
354 `for nbr, datadict in G.succ[n].items():`. A data-view not provided | |
355 by dicts also exists: `for nbr, foovalue in G.succ[node].data('foo'):` | |
356 and a default can be set via a `default` argument to the `data` method. | |
357 | |
358 The neighbor information is also provided by subscripting the graph. | |
359 So `for nbr, foovalue in G[node].data('foo', default=1):` works. | |
360 | |
361 For directed graphs, `G.adj` is identical to `G.succ`. | |
362 """ | |
363 return AdjacencyView(self._succ) | |
364 | |
365 @property | |
366 def pred(self): | |
367 """Graph adjacency object holding the predecessors of each node. | |
368 | |
369 This object is a read-only dict-like structure with node keys | |
370 and neighbor-dict values. The neighbor-dict is keyed by neighbor | |
371 to the edge-data-dict. So `G.pred[2][3]['color'] = 'blue'` sets | |
372 the color of the edge `(3, 2)` to `"blue"`. | |
373 | |
374 Iterating over G.pred behaves like a dict. Useful idioms include | |
375 `for nbr, datadict in G.pred[n].items():`. A data-view not provided | |
376 by dicts also exists: `for nbr, foovalue in G.pred[node].data('foo'):` | |
377 A default can be set via a `default` argument to the `data` method. | |
378 """ | |
379 return AdjacencyView(self._pred) | |
380 | |
381 def add_node(self, node_for_adding, **attr): | |
382 """Add a single node `node_for_adding` and update node attributes. | |
383 | |
384 Parameters | |
385 ---------- | |
386 node_for_adding : node | |
387 A node can be any hashable Python object except None. | |
388 attr : keyword arguments, optional | |
389 Set or change node attributes using key=value. | |
390 | |
391 See Also | |
392 -------- | |
393 add_nodes_from | |
394 | |
395 Examples | |
396 -------- | |
397 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
398 >>> G.add_node(1) | |
399 >>> G.add_node('Hello') | |
400 >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) | |
401 >>> G.add_node(K3) | |
402 >>> G.number_of_nodes() | |
403 3 | |
404 | |
405 Use keywords set/change node attributes: | |
406 | |
407 >>> G.add_node(1, size=10) | |
408 >>> G.add_node(3, weight=0.4, UTM=('13S', 382871, 3972649)) | |
409 | |
410 Notes | |
411 ----- | |
412 A hashable object is one that can be used as a key in a Python | |
413 dictionary. This includes strings, numbers, tuples of strings | |
414 and numbers, etc. | |
415 | |
416 On many platforms hashable items also include mutables such as | |
417 NetworkX Graphs, though one should be careful that the hash | |
418 doesn't change on mutables. | |
419 """ | |
420 if node_for_adding not in self._succ: | |
421 self._succ[node_for_adding] = self.adjlist_inner_dict_factory() | |
422 self._pred[node_for_adding] = self.adjlist_inner_dict_factory() | |
423 attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() | |
424 attr_dict.update(attr) | |
425 else: # update attr even if node already exists | |
426 self._node[node_for_adding].update(attr) | |
427 | |
428 def add_nodes_from(self, nodes_for_adding, **attr): | |
429 """Add multiple nodes. | |
430 | |
431 Parameters | |
432 ---------- | |
433 nodes_for_adding : iterable container | |
434 A container of nodes (list, dict, set, etc.). | |
435 OR | |
436 A container of (node, attribute dict) tuples. | |
437 Node attributes are updated using the attribute dict. | |
438 attr : keyword arguments, optional (default= no attributes) | |
439 Update attributes for all nodes in nodes. | |
440 Node attributes specified in nodes as a tuple take | |
441 precedence over attributes specified via keyword arguments. | |
442 | |
443 See Also | |
444 -------- | |
445 add_node | |
446 | |
447 Examples | |
448 -------- | |
449 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
450 >>> G.add_nodes_from('Hello') | |
451 >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) | |
452 >>> G.add_nodes_from(K3) | |
453 >>> sorted(G.nodes(), key=str) | |
454 [0, 1, 2, 'H', 'e', 'l', 'o'] | |
455 | |
456 Use keywords to update specific node attributes for every node. | |
457 | |
458 >>> G.add_nodes_from([1, 2], size=10) | |
459 >>> G.add_nodes_from([3, 4], weight=0.4) | |
460 | |
461 Use (node, attrdict) tuples to update attributes for specific nodes. | |
462 | |
463 >>> G.add_nodes_from([(1, dict(size=11)), (2, {'color':'blue'})]) | |
464 >>> G.nodes[1]['size'] | |
465 11 | |
466 >>> H = nx.Graph() | |
467 >>> H.add_nodes_from(G.nodes(data=True)) | |
468 >>> H.nodes[1]['size'] | |
469 11 | |
470 | |
471 """ | |
472 for n in nodes_for_adding: | |
473 # keep all this inside try/except because | |
474 # CPython throws TypeError on n not in self._succ, | |
475 # while pre-2.7.5 ironpython throws on self._succ[n] | |
476 try: | |
477 if n not in self._succ: | |
478 self._succ[n] = self.adjlist_inner_dict_factory() | |
479 self._pred[n] = self.adjlist_inner_dict_factory() | |
480 attr_dict = self._node[n] = self.node_attr_dict_factory() | |
481 attr_dict.update(attr) | |
482 else: | |
483 self._node[n].update(attr) | |
484 except TypeError: | |
485 nn, ndict = n | |
486 if nn not in self._succ: | |
487 self._succ[nn] = self.adjlist_inner_dict_factory() | |
488 self._pred[nn] = self.adjlist_inner_dict_factory() | |
489 newdict = attr.copy() | |
490 newdict.update(ndict) | |
491 attr_dict = self._node[nn] = self.node_attr_dict_factory() | |
492 attr_dict.update(newdict) | |
493 else: | |
494 olddict = self._node[nn] | |
495 olddict.update(attr) | |
496 olddict.update(ndict) | |
497 | |
498 def remove_node(self, n): | |
499 """Remove node n. | |
500 | |
501 Removes the node n and all adjacent edges. | |
502 Attempting to remove a non-existent node will raise an exception. | |
503 | |
504 Parameters | |
505 ---------- | |
506 n : node | |
507 A node in the graph | |
508 | |
509 Raises | |
510 ------- | |
511 NetworkXError | |
512 If n is not in the graph. | |
513 | |
514 See Also | |
515 -------- | |
516 remove_nodes_from | |
517 | |
518 Examples | |
519 -------- | |
520 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
521 >>> list(G.edges) | |
522 [(0, 1), (1, 2)] | |
523 >>> G.remove_node(1) | |
524 >>> list(G.edges) | |
525 [] | |
526 | |
527 """ | |
528 try: | |
529 nbrs = self._succ[n] | |
530 del self._node[n] | |
531 except KeyError: # NetworkXError if n not in self | |
532 raise NetworkXError("The node %s is not in the digraph." % (n,)) | |
533 for u in nbrs: | |
534 del self._pred[u][n] # remove all edges n-u in digraph | |
535 del self._succ[n] # remove node from succ | |
536 for u in self._pred[n]: | |
537 del self._succ[u][n] # remove all edges n-u in digraph | |
538 del self._pred[n] # remove node from pred | |
539 | |
540 def remove_nodes_from(self, nodes): | |
541 """Remove multiple nodes. | |
542 | |
543 Parameters | |
544 ---------- | |
545 nodes : iterable container | |
546 A container of nodes (list, dict, set, etc.). If a node | |
547 in the container is not in the graph it is silently ignored. | |
548 | |
549 See Also | |
550 -------- | |
551 remove_node | |
552 | |
553 Examples | |
554 -------- | |
555 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
556 >>> e = list(G.nodes) | |
557 >>> e | |
558 [0, 1, 2] | |
559 >>> G.remove_nodes_from(e) | |
560 >>> list(G.nodes) | |
561 [] | |
562 | |
563 """ | |
564 for n in nodes: | |
565 try: | |
566 succs = self._succ[n] | |
567 del self._node[n] | |
568 for u in succs: | |
569 del self._pred[u][n] # remove all edges n-u in digraph | |
570 del self._succ[n] # now remove node | |
571 for u in self._pred[n]: | |
572 del self._succ[u][n] # remove all edges n-u in digraph | |
573 del self._pred[n] # now remove node | |
574 except KeyError: | |
575 pass # silent failure on remove | |
576 | |
577 def add_edge(self, u_of_edge, v_of_edge, **attr): | |
578 """Add an edge between u and v. | |
579 | |
580 The nodes u and v will be automatically added if they are | |
581 not already in the graph. | |
582 | |
583 Edge attributes can be specified with keywords or by directly | |
584 accessing the edge's attribute dictionary. See examples below. | |
585 | |
586 Parameters | |
587 ---------- | |
588 u, v : nodes | |
589 Nodes can be, for example, strings or numbers. | |
590 Nodes must be hashable (and not None) Python objects. | |
591 attr : keyword arguments, optional | |
592 Edge data (or labels or objects) can be assigned using | |
593 keyword arguments. | |
594 | |
595 See Also | |
596 -------- | |
597 add_edges_from : add a collection of edges | |
598 | |
599 Notes | |
600 ----- | |
601 Adding an edge that already exists updates the edge data. | |
602 | |
603 Many NetworkX algorithms designed for weighted graphs use | |
604 an edge attribute (by default `weight`) to hold a numerical value. | |
605 | |
606 Examples | |
607 -------- | |
608 The following all add the edge e=(1, 2) to graph G: | |
609 | |
610 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
611 >>> e = (1, 2) | |
612 >>> G.add_edge(1, 2) # explicit two-node form | |
613 >>> G.add_edge(*e) # single edge as tuple of two nodes | |
614 >>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container | |
615 | |
616 Associate data to edges using keywords: | |
617 | |
618 >>> G.add_edge(1, 2, weight=3) | |
619 >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) | |
620 | |
621 For non-string attribute keys, use subscript notation. | |
622 | |
623 >>> G.add_edge(1, 2) | |
624 >>> G[1][2].update({0: 5}) | |
625 >>> G.edges[1, 2].update({0: 5}) | |
626 """ | |
627 u, v = u_of_edge, v_of_edge | |
628 # add nodes | |
629 if u not in self._succ: | |
630 self._succ[u] = self.adjlist_inner_dict_factory() | |
631 self._pred[u] = self.adjlist_inner_dict_factory() | |
632 self._node[u] = self.node_attr_dict_factory() | |
633 if v not in self._succ: | |
634 self._succ[v] = self.adjlist_inner_dict_factory() | |
635 self._pred[v] = self.adjlist_inner_dict_factory() | |
636 self._node[v] = self.node_attr_dict_factory() | |
637 # add the edge | |
638 datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) | |
639 datadict.update(attr) | |
640 self._succ[u][v] = datadict | |
641 self._pred[v][u] = datadict | |
642 | |
643 def add_edges_from(self, ebunch_to_add, **attr): | |
644 """Add all the edges in ebunch_to_add. | |
645 | |
646 Parameters | |
647 ---------- | |
648 ebunch_to_add : container of edges | |
649 Each edge given in the container will be added to the | |
650 graph. The edges must be given as 2-tuples (u, v) or | |
651 3-tuples (u, v, d) where d is a dictionary containing edge data. | |
652 attr : keyword arguments, optional | |
653 Edge data (or labels or objects) can be assigned using | |
654 keyword arguments. | |
655 | |
656 See Also | |
657 -------- | |
658 add_edge : add a single edge | |
659 add_weighted_edges_from : convenient way to add weighted edges | |
660 | |
661 Notes | |
662 ----- | |
663 Adding the same edge twice has no effect but any edge data | |
664 will be updated when each duplicate edge is added. | |
665 | |
666 Edge attributes specified in an ebunch take precedence over | |
667 attributes specified via keyword arguments. | |
668 | |
669 Examples | |
670 -------- | |
671 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
672 >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples | |
673 >>> e = zip(range(0, 3), range(1, 4)) | |
674 >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 | |
675 | |
676 Associate data to edges | |
677 | |
678 >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) | |
679 >>> G.add_edges_from([(3, 4), (1, 4)], label='WN2898') | |
680 """ | |
681 for e in ebunch_to_add: | |
682 ne = len(e) | |
683 if ne == 3: | |
684 u, v, dd = e | |
685 elif ne == 2: | |
686 u, v = e | |
687 dd = {} | |
688 else: | |
689 raise NetworkXError( | |
690 "Edge tuple %s must be a 2-tuple or 3-tuple." % (e,)) | |
691 if u not in self._succ: | |
692 self._succ[u] = self.adjlist_inner_dict_factory() | |
693 self._pred[u] = self.adjlist_inner_dict_factory() | |
694 self._node[u] = self.node_attr_dict_factory() | |
695 if v not in self._succ: | |
696 self._succ[v] = self.adjlist_inner_dict_factory() | |
697 self._pred[v] = self.adjlist_inner_dict_factory() | |
698 self._node[v] = self.node_attr_dict_factory() | |
699 datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) | |
700 datadict.update(attr) | |
701 datadict.update(dd) | |
702 self._succ[u][v] = datadict | |
703 self._pred[v][u] = datadict | |
704 | |
705 def remove_edge(self, u, v): | |
706 """Remove the edge between u and v. | |
707 | |
708 Parameters | |
709 ---------- | |
710 u, v : nodes | |
711 Remove the edge between nodes u and v. | |
712 | |
713 Raises | |
714 ------ | |
715 NetworkXError | |
716 If there is not an edge between u and v. | |
717 | |
718 See Also | |
719 -------- | |
720 remove_edges_from : remove a collection of edges | |
721 | |
722 Examples | |
723 -------- | |
724 >>> G = nx.Graph() # or DiGraph, etc | |
725 >>> nx.add_path(G, [0, 1, 2, 3]) | |
726 >>> G.remove_edge(0, 1) | |
727 >>> e = (1, 2) | |
728 >>> G.remove_edge(*e) # unpacks e from an edge tuple | |
729 >>> e = (2, 3, {'weight':7}) # an edge with attribute data | |
730 >>> G.remove_edge(*e[:2]) # select first part of edge tuple | |
731 """ | |
732 try: | |
733 del self._succ[u][v] | |
734 del self._pred[v][u] | |
735 except KeyError: | |
736 raise NetworkXError("The edge %s-%s not in graph." % (u, v)) | |
737 | |
738 def remove_edges_from(self, ebunch): | |
739 """Remove all edges specified in ebunch. | |
740 | |
741 Parameters | |
742 ---------- | |
743 ebunch: list or container of edge tuples | |
744 Each edge given in the list or container will be removed | |
745 from the graph. The edges can be: | |
746 | |
747 - 2-tuples (u, v) edge between u and v. | |
748 - 3-tuples (u, v, k) where k is ignored. | |
749 | |
750 See Also | |
751 -------- | |
752 remove_edge : remove a single edge | |
753 | |
754 Notes | |
755 ----- | |
756 Will fail silently if an edge in ebunch is not in the graph. | |
757 | |
758 Examples | |
759 -------- | |
760 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
761 >>> ebunch = [(1, 2), (2, 3)] | |
762 >>> G.remove_edges_from(ebunch) | |
763 """ | |
764 for e in ebunch: | |
765 u, v = e[:2] # ignore edge data | |
766 if u in self._succ and v in self._succ[u]: | |
767 del self._succ[u][v] | |
768 del self._pred[v][u] | |
769 | |
770 def has_successor(self, u, v): | |
771 """Returns True if node u has successor v. | |
772 | |
773 This is true if graph has the edge u->v. | |
774 """ | |
775 return (u in self._succ and v in self._succ[u]) | |
776 | |
777 def has_predecessor(self, u, v): | |
778 """Returns True if node u has predecessor v. | |
779 | |
780 This is true if graph has the edge u<-v. | |
781 """ | |
782 return (u in self._pred and v in self._pred[u]) | |
783 | |
784 def successors(self, n): | |
785 """Returns an iterator over successor nodes of n. | |
786 | |
787 A successor of n is a node m such that there exists a directed | |
788 edge from n to m. | |
789 | |
790 Parameters | |
791 ---------- | |
792 n : node | |
793 A node in the graph | |
794 | |
795 Raises | |
796 ------- | |
797 NetworkXError | |
798 If n is not in the graph. | |
799 | |
800 See Also | |
801 -------- | |
802 predecessors | |
803 | |
804 Notes | |
805 ----- | |
806 neighbors() and successors() are the same. | |
807 """ | |
808 try: | |
809 return iter(self._succ[n]) | |
810 except KeyError: | |
811 raise NetworkXError("The node %s is not in the digraph." % (n,)) | |
812 | |
813 # digraph definitions | |
814 neighbors = successors | |
815 | |
816 def predecessors(self, n): | |
817 """Returns an iterator over predecessor nodes of n. | |
818 | |
819 A predecessor of n is a node m such that there exists a directed | |
820 edge from m to n. | |
821 | |
822 Parameters | |
823 ---------- | |
824 n : node | |
825 A node in the graph | |
826 | |
827 Raises | |
828 ------- | |
829 NetworkXError | |
830 If n is not in the graph. | |
831 | |
832 See Also | |
833 -------- | |
834 successors | |
835 """ | |
836 try: | |
837 return iter(self._pred[n]) | |
838 except KeyError: | |
839 raise NetworkXError("The node %s is not in the digraph." % (n,)) | |
840 | |
841 @property | |
842 def edges(self): | |
843 """An OutEdgeView of the DiGraph as G.edges or G.edges(). | |
844 | |
845 edges(self, nbunch=None, data=False, default=None) | |
846 | |
847 The OutEdgeView provides set-like operations on the edge-tuples | |
848 as well as edge attribute lookup. When called, it also provides | |
849 an EdgeDataView object which allows control of access to edge | |
850 attributes (but does not provide set-like operations). | |
851 Hence, `G.edges[u, v]['color']` provides the value of the color | |
852 attribute for edge `(u, v)` while | |
853 `for (u, v, c) in G.edges.data('color', default='red'):` | |
854 iterates through all the edges yielding the color attribute | |
855 with default `'red'` if no color attribute exists. | |
856 | |
857 Parameters | |
858 ---------- | |
859 nbunch : single node, container, or all nodes (default= all nodes) | |
860 The view will only report edges incident to these nodes. | |
861 data : string or bool, optional (default=False) | |
862 The edge attribute returned in 3-tuple (u, v, ddict[data]). | |
863 If True, return edge attribute dict in 3-tuple (u, v, ddict). | |
864 If False, return 2-tuple (u, v). | |
865 default : value, optional (default=None) | |
866 Value used for edges that don't have the requested attribute. | |
867 Only relevant if data is not True or False. | |
868 | |
869 Returns | |
870 ------- | |
871 edges : OutEdgeView | |
872 A view of edge attributes, usually it iterates over (u, v) | |
873 or (u, v, d) tuples of edges, but can also be used for | |
874 attribute lookup as `edges[u, v]['foo']`. | |
875 | |
876 See Also | |
877 -------- | |
878 in_edges, out_edges | |
879 | |
880 Notes | |
881 ----- | |
882 Nodes in nbunch that are not in the graph will be (quietly) ignored. | |
883 For directed graphs this returns the out-edges. | |
884 | |
885 Examples | |
886 -------- | |
887 >>> G = nx.DiGraph() # or MultiDiGraph, etc | |
888 >>> nx.add_path(G, [0, 1, 2]) | |
889 >>> G.add_edge(2, 3, weight=5) | |
890 >>> [e for e in G.edges] | |
891 [(0, 1), (1, 2), (2, 3)] | |
892 >>> G.edges.data() # default data is {} (empty dict) | |
893 OutEdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) | |
894 >>> G.edges.data('weight', default=1) | |
895 OutEdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) | |
896 >>> G.edges([0, 2]) # only edges incident to these nodes | |
897 OutEdgeDataView([(0, 1), (2, 3)]) | |
898 >>> G.edges(0) # only edges incident to a single node (use G.adj[0]?) | |
899 OutEdgeDataView([(0, 1)]) | |
900 | |
901 """ | |
902 return OutEdgeView(self) | |
903 | |
904 # alias out_edges to edges | |
905 out_edges = edges | |
906 | |
907 @property | |
908 def in_edges(self): | |
909 """An InEdgeView of the Graph as G.in_edges or G.in_edges(). | |
910 | |
911 in_edges(self, nbunch=None, data=False, default=None): | |
912 | |
913 Parameters | |
914 ---------- | |
915 nbunch : single node, container, or all nodes (default= all nodes) | |
916 The view will only report edges incident to these nodes. | |
917 data : string or bool, optional (default=False) | |
918 The edge attribute returned in 3-tuple (u, v, ddict[data]). | |
919 If True, return edge attribute dict in 3-tuple (u, v, ddict). | |
920 If False, return 2-tuple (u, v). | |
921 default : value, optional (default=None) | |
922 Value used for edges that don't have the requested attribute. | |
923 Only relevant if data is not True or False. | |
924 | |
925 Returns | |
926 ------- | |
927 in_edges : InEdgeView | |
928 A view of edge attributes, usually it iterates over (u, v) | |
929 or (u, v, d) tuples of edges, but can also be used for | |
930 attribute lookup as `edges[u, v]['foo']`. | |
931 | |
932 See Also | |
933 -------- | |
934 edges | |
935 """ | |
936 return InEdgeView(self) | |
937 | |
938 @property | |
939 def degree(self): | |
940 """A DegreeView for the Graph as G.degree or G.degree(). | |
941 | |
942 The node degree is the number of edges adjacent to the node. | |
943 The weighted node degree is the sum of the edge weights for | |
944 edges incident to that node. | |
945 | |
946 This object provides an iterator for (node, degree) as well as | |
947 lookup for the degree for a single node. | |
948 | |
949 Parameters | |
950 ---------- | |
951 nbunch : single node, container, or all nodes (default= all nodes) | |
952 The view will only report edges incident to these nodes. | |
953 | |
954 weight : string or None, optional (default=None) | |
955 The name of an edge attribute that holds the numerical value used | |
956 as a weight. If None, then each edge has weight 1. | |
957 The degree is the sum of the edge weights adjacent to the node. | |
958 | |
959 Returns | |
960 ------- | |
961 If a single node is requested | |
962 deg : int | |
963 Degree of the node | |
964 | |
965 OR if multiple nodes are requested | |
966 nd_iter : iterator | |
967 The iterator returns two-tuples of (node, degree). | |
968 | |
969 See Also | |
970 -------- | |
971 in_degree, out_degree | |
972 | |
973 Examples | |
974 -------- | |
975 >>> G = nx.DiGraph() # or MultiDiGraph | |
976 >>> nx.add_path(G, [0, 1, 2, 3]) | |
977 >>> G.degree(0) # node 0 with degree 1 | |
978 1 | |
979 >>> list(G.degree([0, 1, 2])) | |
980 [(0, 1), (1, 2), (2, 2)] | |
981 | |
982 """ | |
983 return DiDegreeView(self) | |
984 | |
985 @property | |
986 def in_degree(self): | |
987 """An InDegreeView for (node, in_degree) or in_degree for single node. | |
988 | |
989 The node in_degree is the number of edges pointing to the node. | |
990 The weighted node degree is the sum of the edge weights for | |
991 edges incident to that node. | |
992 | |
993 This object provides an iteration over (node, in_degree) as well as | |
994 lookup for the degree for a single node. | |
995 | |
996 Parameters | |
997 ---------- | |
998 nbunch : single node, container, or all nodes (default= all nodes) | |
999 The view will only report edges incident to these nodes. | |
1000 | |
1001 weight : string or None, optional (default=None) | |
1002 The name of an edge attribute that holds the numerical value used | |
1003 as a weight. If None, then each edge has weight 1. | |
1004 The degree is the sum of the edge weights adjacent to the node. | |
1005 | |
1006 Returns | |
1007 ------- | |
1008 If a single node is requested | |
1009 deg : int | |
1010 In-degree of the node | |
1011 | |
1012 OR if multiple nodes are requested | |
1013 nd_iter : iterator | |
1014 The iterator returns two-tuples of (node, in-degree). | |
1015 | |
1016 See Also | |
1017 -------- | |
1018 degree, out_degree | |
1019 | |
1020 Examples | |
1021 -------- | |
1022 >>> G = nx.DiGraph() | |
1023 >>> nx.add_path(G, [0, 1, 2, 3]) | |
1024 >>> G.in_degree(0) # node 0 with degree 0 | |
1025 0 | |
1026 >>> list(G.in_degree([0, 1, 2])) | |
1027 [(0, 0), (1, 1), (2, 1)] | |
1028 | |
1029 """ | |
1030 return InDegreeView(self) | |
1031 | |
1032 @property | |
1033 def out_degree(self): | |
1034 """An OutDegreeView for (node, out_degree) | |
1035 | |
1036 The node out_degree is the number of edges pointing out of the node. | |
1037 The weighted node degree is the sum of the edge weights for | |
1038 edges incident to that node. | |
1039 | |
1040 This object provides an iterator over (node, out_degree) as well as | |
1041 lookup for the degree for a single node. | |
1042 | |
1043 Parameters | |
1044 ---------- | |
1045 nbunch : single node, container, or all nodes (default= all nodes) | |
1046 The view will only report edges incident to these nodes. | |
1047 | |
1048 weight : string or None, optional (default=None) | |
1049 The name of an edge attribute that holds the numerical value used | |
1050 as a weight. If None, then each edge has weight 1. | |
1051 The degree is the sum of the edge weights adjacent to the node. | |
1052 | |
1053 Returns | |
1054 ------- | |
1055 If a single node is requested | |
1056 deg : int | |
1057 Out-degree of the node | |
1058 | |
1059 OR if multiple nodes are requested | |
1060 nd_iter : iterator | |
1061 The iterator returns two-tuples of (node, out-degree). | |
1062 | |
1063 See Also | |
1064 -------- | |
1065 degree, in_degree | |
1066 | |
1067 Examples | |
1068 -------- | |
1069 >>> G = nx.DiGraph() | |
1070 >>> nx.add_path(G, [0, 1, 2, 3]) | |
1071 >>> G.out_degree(0) # node 0 with degree 1 | |
1072 1 | |
1073 >>> list(G.out_degree([0, 1, 2])) | |
1074 [(0, 1), (1, 1), (2, 1)] | |
1075 | |
1076 """ | |
1077 return OutDegreeView(self) | |
1078 | |
1079 def clear(self): | |
1080 """Remove all nodes and edges from the graph. | |
1081 | |
1082 This also removes the name, and all graph, node, and edge attributes. | |
1083 | |
1084 Examples | |
1085 -------- | |
1086 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1087 >>> G.clear() | |
1088 >>> list(G.nodes) | |
1089 [] | |
1090 >>> list(G.edges) | |
1091 [] | |
1092 """ | |
1093 self._succ.clear() | |
1094 self._pred.clear() | |
1095 self._node.clear() | |
1096 self.graph.clear() | |
1097 | |
1098 def is_multigraph(self): | |
1099 """Returns True if graph is a multigraph, False otherwise.""" | |
1100 return False | |
1101 | |
1102 def is_directed(self): | |
1103 """Returns True if graph is directed, False otherwise.""" | |
1104 return True | |
1105 | |
1106 def to_undirected(self, reciprocal=False, as_view=False): | |
1107 """Returns an undirected representation of the digraph. | |
1108 | |
1109 Parameters | |
1110 ---------- | |
1111 reciprocal : bool (optional) | |
1112 If True only keep edges that appear in both directions | |
1113 in the original digraph. | |
1114 as_view : bool (optional, default=False) | |
1115 If True return an undirected view of the original directed graph. | |
1116 | |
1117 Returns | |
1118 ------- | |
1119 G : Graph | |
1120 An undirected graph with the same name and nodes and | |
1121 with edge (u, v, data) if either (u, v, data) or (v, u, data) | |
1122 is in the digraph. If both edges exist in digraph and | |
1123 their edge data is different, only one edge is created | |
1124 with an arbitrary choice of which edge data to use. | |
1125 You must check and correct for this manually if desired. | |
1126 | |
1127 See Also | |
1128 -------- | |
1129 Graph, copy, add_edge, add_edges_from | |
1130 | |
1131 Notes | |
1132 ----- | |
1133 If edges in both directions (u, v) and (v, u) exist in the | |
1134 graph, attributes for the new undirected edge will be a combination of | |
1135 the attributes of the directed edges. The edge data is updated | |
1136 in the (arbitrary) order that the edges are encountered. For | |
1137 more customized control of the edge attributes use add_edge(). | |
1138 | |
1139 This returns a "deepcopy" of the edge, node, and | |
1140 graph attributes which attempts to completely copy | |
1141 all of the data and references. | |
1142 | |
1143 This is in contrast to the similar G=DiGraph(D) which returns a | |
1144 shallow copy of the data. | |
1145 | |
1146 See the Python copy module for more information on shallow | |
1147 and deep copies, https://docs.python.org/2/library/copy.html. | |
1148 | |
1149 Warning: If you have subclassed DiGraph to use dict-like objects | |
1150 in the data structure, those changes do not transfer to the | |
1151 Graph created by this method. | |
1152 | |
1153 Examples | |
1154 -------- | |
1155 >>> G = nx.path_graph(2) # or MultiGraph, etc | |
1156 >>> H = G.to_directed() | |
1157 >>> list(H.edges) | |
1158 [(0, 1), (1, 0)] | |
1159 >>> G2 = H.to_undirected() | |
1160 >>> list(G2.edges) | |
1161 [(0, 1)] | |
1162 """ | |
1163 graph_class = self.to_undirected_class() | |
1164 if as_view is True: | |
1165 return nx.graphviews.generic_graph_view(self, Graph) | |
1166 # deepcopy when not a view | |
1167 G = Graph() | |
1168 G.graph.update(deepcopy(self.graph)) | |
1169 G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) | |
1170 if reciprocal is True: | |
1171 G.add_edges_from((u, v, deepcopy(d)) | |
1172 for u, nbrs in self._adj.items() | |
1173 for v, d in nbrs.items() | |
1174 if v in self._pred[u]) | |
1175 else: | |
1176 G.add_edges_from((u, v, deepcopy(d)) | |
1177 for u, nbrs in self._adj.items() | |
1178 for v, d in nbrs.items()) | |
1179 return G | |
1180 | |
1181 def reverse(self, copy=True): | |
1182 """Returns the reverse of the graph. | |
1183 | |
1184 The reverse is a graph with the same nodes and edges | |
1185 but with the directions of the edges reversed. | |
1186 | |
1187 Parameters | |
1188 ---------- | |
1189 copy : bool optional (default=True) | |
1190 If True, return a new DiGraph holding the reversed edges. | |
1191 If False, the reverse graph is created using a view of | |
1192 the original graph. | |
1193 """ | |
1194 if copy: | |
1195 H = self.__class__() | |
1196 H.graph.update(deepcopy(self.graph)) | |
1197 H.add_nodes_from((n, deepcopy(d)) for n, d in self.nodes.items()) | |
1198 H.add_edges_from((v, u, deepcopy(d)) for u, v, d | |
1199 in self.edges(data=True)) | |
1200 return H | |
1201 return nx.graphviews.reverse_view(self) |