Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/networkx/classes/graph.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 # Author: Aric Hagberg (hagberg@lanl.gov), | |
9 # Pieter Swart (swart@lanl.gov), | |
10 # Dan Schult(dschult@colgate.edu) | |
11 """Base class for undirected graphs. | |
12 | |
13 The Graph class allows any hashable object as a node | |
14 and can associate key/value attribute pairs with each undirected edge. | |
15 | |
16 Self-loops are allowed but multiple edges are not (see MultiGraph). | |
17 | |
18 For directed graphs see DiGraph and MultiDiGraph. | |
19 """ | |
20 import warnings | |
21 from copy import deepcopy | |
22 from collections.abc import Mapping | |
23 | |
24 import networkx as nx | |
25 from networkx.classes.coreviews import AtlasView, AdjacencyView | |
26 from networkx.classes.reportviews import NodeView, EdgeView, DegreeView | |
27 from networkx.exception import NetworkXError | |
28 import networkx.convert as convert | |
29 from networkx.utils import pairwise | |
30 | |
31 | |
32 class Graph(object): | |
33 """ | |
34 Base class for undirected graphs. | |
35 | |
36 A Graph stores nodes and edges with optional data, or attributes. | |
37 | |
38 Graphs hold undirected edges. Self loops are allowed but multiple | |
39 (parallel) edges are not. | |
40 | |
41 Nodes can be arbitrary (hashable) Python objects with optional | |
42 key/value attributes. By convention `None` is not used as a node. | |
43 | |
44 Edges are represented as links between nodes with optional | |
45 key/value attributes. | |
46 | |
47 Parameters | |
48 ---------- | |
49 incoming_graph_data : input graph (optional, default: None) | |
50 Data to initialize graph. If None (default) an empty | |
51 graph is created. The data can be any format that is supported | |
52 by the to_networkx_graph() function, currently including edge list, | |
53 dict of dicts, dict of lists, NetworkX graph, NumPy matrix | |
54 or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. | |
55 | |
56 attr : keyword arguments, optional (default= no attributes) | |
57 Attributes to add to graph as key=value pairs. | |
58 | |
59 See Also | |
60 -------- | |
61 DiGraph | |
62 MultiGraph | |
63 MultiDiGraph | |
64 OrderedGraph | |
65 | |
66 Examples | |
67 -------- | |
68 Create an empty graph structure (a "null graph") with no nodes and | |
69 no edges. | |
70 | |
71 >>> G = nx.Graph() | |
72 | |
73 G can be grown in several ways. | |
74 | |
75 **Nodes:** | |
76 | |
77 Add one node at a time: | |
78 | |
79 >>> G.add_node(1) | |
80 | |
81 Add the nodes from any container (a list, dict, set or | |
82 even the lines from a file or the nodes from another graph). | |
83 | |
84 >>> G.add_nodes_from([2, 3]) | |
85 >>> G.add_nodes_from(range(100, 110)) | |
86 >>> H = nx.path_graph(10) | |
87 >>> G.add_nodes_from(H) | |
88 | |
89 In addition to strings and integers any hashable Python object | |
90 (except None) can represent a node, e.g. a customized node object, | |
91 or even another Graph. | |
92 | |
93 >>> G.add_node(H) | |
94 | |
95 **Edges:** | |
96 | |
97 G can also be grown by adding edges. | |
98 | |
99 Add one edge, | |
100 | |
101 >>> G.add_edge(1, 2) | |
102 | |
103 a list of edges, | |
104 | |
105 >>> G.add_edges_from([(1, 2), (1, 3)]) | |
106 | |
107 or a collection of edges, | |
108 | |
109 >>> G.add_edges_from(H.edges) | |
110 | |
111 If some edges connect nodes not yet in the graph, the nodes | |
112 are added automatically. There are no errors when adding | |
113 nodes or edges that already exist. | |
114 | |
115 **Attributes:** | |
116 | |
117 Each graph, node, and edge can hold key/value attribute pairs | |
118 in an associated attribute dictionary (the keys must be hashable). | |
119 By default these are empty, but can be added or changed using | |
120 add_edge, add_node or direct manipulation of the attribute | |
121 dictionaries named graph, node and edge respectively. | |
122 | |
123 >>> G = nx.Graph(day="Friday") | |
124 >>> G.graph | |
125 {'day': 'Friday'} | |
126 | |
127 Add node attributes using add_node(), add_nodes_from() or G.nodes | |
128 | |
129 >>> G.add_node(1, time='5pm') | |
130 >>> G.add_nodes_from([3], time='2pm') | |
131 >>> G.nodes[1] | |
132 {'time': '5pm'} | |
133 >>> G.nodes[1]['room'] = 714 # node must exist already to use G.nodes | |
134 >>> del G.nodes[1]['room'] # remove attribute | |
135 >>> list(G.nodes(data=True)) | |
136 [(1, {'time': '5pm'}), (3, {'time': '2pm'})] | |
137 | |
138 Add edge attributes using add_edge(), add_edges_from(), subscript | |
139 notation, or G.edges. | |
140 | |
141 >>> G.add_edge(1, 2, weight=4.7 ) | |
142 >>> G.add_edges_from([(3, 4), (4, 5)], color='red') | |
143 >>> G.add_edges_from([(1, 2, {'color': 'blue'}), (2, 3, {'weight': 8})]) | |
144 >>> G[1][2]['weight'] = 4.7 | |
145 >>> G.edges[1, 2]['weight'] = 4 | |
146 | |
147 Warning: we protect the graph data structure by making `G.edges` a | |
148 read-only dict-like structure. However, you can assign to attributes | |
149 in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change | |
150 data attributes: `G.edges[1, 2]['weight'] = 4` | |
151 (For multigraphs: `MG.edges[u, v, key][name] = value`). | |
152 | |
153 **Shortcuts:** | |
154 | |
155 Many common graph features allow python syntax to speed reporting. | |
156 | |
157 >>> 1 in G # check if node in graph | |
158 True | |
159 >>> [n for n in G if n < 3] # iterate through nodes | |
160 [1, 2] | |
161 >>> len(G) # number of nodes in graph | |
162 5 | |
163 | |
164 Often the best way to traverse all edges of a graph is via the neighbors. | |
165 The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` | |
166 | |
167 >>> for n, nbrsdict in G.adjacency(): | |
168 ... for nbr, eattr in nbrsdict.items(): | |
169 ... if 'weight' in eattr: | |
170 ... # Do something useful with the edges | |
171 ... pass | |
172 | |
173 But the edges() method is often more convenient: | |
174 | |
175 >>> for u, v, weight in G.edges.data('weight'): | |
176 ... if weight is not None: | |
177 ... # Do something useful with the edges | |
178 ... pass | |
179 | |
180 **Reporting:** | |
181 | |
182 Simple graph information is obtained using object-attributes and methods. | |
183 Reporting typically provides views instead of containers to reduce memory | |
184 usage. The views update as the graph is updated similarly to dict-views. | |
185 The objects `nodes, `edges` and `adj` provide access to data attributes | |
186 via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration | |
187 (e.g. `nodes.items()`, `nodes.data('color')`, | |
188 `nodes.data('color', default='blue')` and similarly for `edges`) | |
189 Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. | |
190 | |
191 For details on these and other miscellaneous methods, see below. | |
192 | |
193 **Subclasses (Advanced):** | |
194 | |
195 The Graph class uses a dict-of-dict-of-dict data structure. | |
196 The outer dict (node_dict) holds adjacency information keyed by node. | |
197 The next dict (adjlist_dict) represents the adjacency information and holds | |
198 edge data keyed by neighbor. The inner dict (edge_attr_dict) represents | |
199 the edge data and holds edge attribute values keyed by attribute names. | |
200 | |
201 Each of these three dicts can be replaced in a subclass by a user defined | |
202 dict-like object. In general, the dict-like features should be | |
203 maintained but extra features can be added. To replace one of the | |
204 dicts create a new graph class by changing the class(!) variable | |
205 holding the factory for that dict-like structure. The variable names are | |
206 node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, | |
207 adjlist_outer_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory. | |
208 | |
209 node_dict_factory : function, (default: dict) | |
210 Factory function to be used to create the dict containing node | |
211 attributes, keyed by node id. | |
212 It should require no arguments and return a dict-like object | |
213 | |
214 node_attr_dict_factory: function, (default: dict) | |
215 Factory function to be used to create the node attribute | |
216 dict which holds attribute values keyed by attribute name. | |
217 It should require no arguments and return a dict-like object | |
218 | |
219 adjlist_outer_dict_factory : function, (default: dict) | |
220 Factory function to be used to create the outer-most dict | |
221 in the data structure that holds adjacency info keyed by node. | |
222 It should require no arguments and return a dict-like object. | |
223 | |
224 adjlist_inner_dict_factory : function, (default: dict) | |
225 Factory function to be used to create the adjacency list | |
226 dict which holds edge data keyed by neighbor. | |
227 It should require no arguments and return a dict-like object | |
228 | |
229 edge_attr_dict_factory : function, (default: dict) | |
230 Factory function to be used to create the edge attribute | |
231 dict which holds attribute values keyed by attribute name. | |
232 It should require no arguments and return a dict-like object. | |
233 | |
234 graph_attr_dict_factory : function, (default: dict) | |
235 Factory function to be used to create the graph attribute | |
236 dict which holds attribute values keyed by attribute name. | |
237 It should require no arguments and return a dict-like object. | |
238 | |
239 Typically, if your extension doesn't impact the data structure all | |
240 methods will inherit without issue except: `to_directed/to_undirected`. | |
241 By default these methods create a DiGraph/Graph class and you probably | |
242 want them to create your extension of a DiGraph/Graph. To facilitate | |
243 this we define two class variables that you can set in your subclass. | |
244 | |
245 to_directed_class : callable, (default: DiGraph or MultiDiGraph) | |
246 Class to create a new graph structure in the `to_directed` method. | |
247 If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. | |
248 | |
249 to_undirected_class : callable, (default: Graph or MultiGraph) | |
250 Class to create a new graph structure in the `to_undirected` method. | |
251 If `None`, a NetworkX class (Graph or MultiGraph) is used. | |
252 | |
253 Examples | |
254 -------- | |
255 | |
256 Create a low memory graph class that effectively disallows edge | |
257 attributes by using a single attribute dict for all edges. | |
258 This reduces the memory used, but you lose edge attributes. | |
259 | |
260 >>> class ThinGraph(nx.Graph): | |
261 ... all_edge_dict = {'weight': 1} | |
262 ... def single_edge_dict(self): | |
263 ... return self.all_edge_dict | |
264 ... edge_attr_dict_factory = single_edge_dict | |
265 >>> G = ThinGraph() | |
266 >>> G.add_edge(2, 1) | |
267 >>> G[2][1] | |
268 {'weight': 1} | |
269 >>> G.add_edge(2, 2) | |
270 >>> G[2][1] is G[2][2] | |
271 True | |
272 | |
273 Please see :mod:`~networkx.classes.ordered` for more examples of | |
274 creating graph subclasses by overwriting the base class `dict` with | |
275 a dictionary-like object. | |
276 """ | |
277 node_dict_factory = dict | |
278 node_attr_dict_factory = dict | |
279 adjlist_outer_dict_factory = dict | |
280 adjlist_inner_dict_factory = dict | |
281 edge_attr_dict_factory = dict | |
282 graph_attr_dict_factory = dict | |
283 | |
284 def to_directed_class(self): | |
285 """Returns the class to use for empty directed copies. | |
286 | |
287 If you subclass the base classes, use this to designate | |
288 what directed class to use for `to_directed()` copies. | |
289 """ | |
290 return nx.DiGraph | |
291 | |
292 def to_undirected_class(self): | |
293 """Returns the class to use for empty undirected copies. | |
294 | |
295 If you subclass the base classes, use this to designate | |
296 what directed class to use for `to_directed()` copies. | |
297 """ | |
298 return Graph | |
299 | |
300 def __init__(self, incoming_graph_data=None, **attr): | |
301 """Initialize a graph with edges, name, or graph attributes. | |
302 | |
303 Parameters | |
304 ---------- | |
305 incoming_graph_data : input graph (optional, default: None) | |
306 Data to initialize graph. If None (default) an empty | |
307 graph is created. The data can be an edge list, or any | |
308 NetworkX graph object. If the corresponding optional Python | |
309 packages are installed the data can also be a NumPy matrix | |
310 or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. | |
311 | |
312 attr : keyword arguments, optional (default= no attributes) | |
313 Attributes to add to graph as key=value pairs. | |
314 | |
315 See Also | |
316 -------- | |
317 convert | |
318 | |
319 Examples | |
320 -------- | |
321 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
322 >>> G = nx.Graph(name='my graph') | |
323 >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges | |
324 >>> G = nx.Graph(e) | |
325 | |
326 Arbitrary graph attribute pairs (key=value) may be assigned | |
327 | |
328 >>> G = nx.Graph(e, day="Friday") | |
329 >>> G.graph | |
330 {'day': 'Friday'} | |
331 | |
332 """ | |
333 self.graph_attr_dict_factory = self.graph_attr_dict_factory | |
334 self.node_dict_factory = self.node_dict_factory | |
335 self.node_attr_dict_factory = self.node_attr_dict_factory | |
336 self.adjlist_outer_dict_factory = self.adjlist_outer_dict_factory | |
337 self.adjlist_inner_dict_factory = self.adjlist_inner_dict_factory | |
338 self.edge_attr_dict_factory = self.edge_attr_dict_factory | |
339 | |
340 self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes | |
341 self._node = self.node_dict_factory() # empty node attribute dict | |
342 self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict | |
343 # attempt to load graph with data | |
344 if incoming_graph_data is not None: | |
345 convert.to_networkx_graph(incoming_graph_data, create_using=self) | |
346 # load graph attributes (must be after convert) | |
347 self.graph.update(attr) | |
348 | |
349 @property | |
350 def adj(self): | |
351 """Graph adjacency object holding the neighbors of each node. | |
352 | |
353 This object is a read-only dict-like structure with node keys | |
354 and neighbor-dict values. The neighbor-dict is keyed by neighbor | |
355 to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets | |
356 the color of the edge `(3, 2)` to `"blue"`. | |
357 | |
358 Iterating over G.adj behaves like a dict. Useful idioms include | |
359 `for nbr, datadict in G.adj[n].items():`. | |
360 | |
361 The neighbor information is also provided by subscripting the graph. | |
362 So `for nbr, foovalue in G[node].data('foo', default=1):` works. | |
363 | |
364 For directed graphs, `G.adj` holds outgoing (successor) info. | |
365 """ | |
366 return AdjacencyView(self._adj) | |
367 | |
368 @property | |
369 def name(self): | |
370 """String identifier of the graph. | |
371 | |
372 This graph attribute appears in the attribute dict G.graph | |
373 keyed by the string `"name"`. as well as an attribute (technically | |
374 a property) `G.name`. This is entirely user controlled. | |
375 """ | |
376 return self.graph.get('name', '') | |
377 | |
378 @name.setter | |
379 def name(self, s): | |
380 self.graph['name'] = s | |
381 | |
382 def __str__(self): | |
383 """Returns the graph name. | |
384 | |
385 Returns | |
386 ------- | |
387 name : string | |
388 The name of the graph. | |
389 | |
390 Examples | |
391 -------- | |
392 >>> G = nx.Graph(name='foo') | |
393 >>> str(G) | |
394 'foo' | |
395 """ | |
396 return self.name | |
397 | |
398 def __iter__(self): | |
399 """Iterate over the nodes. Use: 'for n in G'. | |
400 | |
401 Returns | |
402 ------- | |
403 niter : iterator | |
404 An iterator over all nodes in the graph. | |
405 | |
406 Examples | |
407 -------- | |
408 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
409 >>> [n for n in G] | |
410 [0, 1, 2, 3] | |
411 >>> list(G) | |
412 [0, 1, 2, 3] | |
413 """ | |
414 return iter(self._node) | |
415 | |
416 def __contains__(self, n): | |
417 """Returns True if n is a node, False otherwise. Use: 'n in G'. | |
418 | |
419 Examples | |
420 -------- | |
421 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
422 >>> 1 in G | |
423 True | |
424 """ | |
425 try: | |
426 return n in self._node | |
427 except TypeError: | |
428 return False | |
429 | |
430 def __len__(self): | |
431 """Returns the number of nodes in the graph. Use: 'len(G)'. | |
432 | |
433 Returns | |
434 ------- | |
435 nnodes : int | |
436 The number of nodes in the graph. | |
437 | |
438 See Also | |
439 -------- | |
440 number_of_nodes, order which are identical | |
441 | |
442 Examples | |
443 -------- | |
444 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
445 >>> len(G) | |
446 4 | |
447 | |
448 """ | |
449 return len(self._node) | |
450 | |
451 def __getitem__(self, n): | |
452 """Returns a dict of neighbors of node n. Use: 'G[n]'. | |
453 | |
454 Parameters | |
455 ---------- | |
456 n : node | |
457 A node in the graph. | |
458 | |
459 Returns | |
460 ------- | |
461 adj_dict : dictionary | |
462 The adjacency dictionary for nodes connected to n. | |
463 | |
464 Notes | |
465 ----- | |
466 G[n] is the same as G.adj[n] and similar to G.neighbors(n) | |
467 (which is an iterator over G.adj[n]) | |
468 | |
469 Examples | |
470 -------- | |
471 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
472 >>> G[0] | |
473 AtlasView({1: {}}) | |
474 """ | |
475 return self.adj[n] | |
476 | |
477 def add_node(self, node_for_adding, **attr): | |
478 """Add a single node `node_for_adding` and update node attributes. | |
479 | |
480 Parameters | |
481 ---------- | |
482 node_for_adding : node | |
483 A node can be any hashable Python object except None. | |
484 attr : keyword arguments, optional | |
485 Set or change node attributes using key=value. | |
486 | |
487 See Also | |
488 -------- | |
489 add_nodes_from | |
490 | |
491 Examples | |
492 -------- | |
493 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
494 >>> G.add_node(1) | |
495 >>> G.add_node('Hello') | |
496 >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) | |
497 >>> G.add_node(K3) | |
498 >>> G.number_of_nodes() | |
499 3 | |
500 | |
501 Use keywords set/change node attributes: | |
502 | |
503 >>> G.add_node(1, size=10) | |
504 >>> G.add_node(3, weight=0.4, UTM=('13S', 382871, 3972649)) | |
505 | |
506 Notes | |
507 ----- | |
508 A hashable object is one that can be used as a key in a Python | |
509 dictionary. This includes strings, numbers, tuples of strings | |
510 and numbers, etc. | |
511 | |
512 On many platforms hashable items also include mutables such as | |
513 NetworkX Graphs, though one should be careful that the hash | |
514 doesn't change on mutables. | |
515 """ | |
516 if node_for_adding not in self._node: | |
517 self._adj[node_for_adding] = self.adjlist_inner_dict_factory() | |
518 attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() | |
519 attr_dict.update(attr) | |
520 else: # update attr even if node already exists | |
521 self._node[node_for_adding].update(attr) | |
522 | |
523 def add_nodes_from(self, nodes_for_adding, **attr): | |
524 """Add multiple nodes. | |
525 | |
526 Parameters | |
527 ---------- | |
528 nodes_for_adding : iterable container | |
529 A container of nodes (list, dict, set, etc.). | |
530 OR | |
531 A container of (node, attribute dict) tuples. | |
532 Node attributes are updated using the attribute dict. | |
533 attr : keyword arguments, optional (default= no attributes) | |
534 Update attributes for all nodes in nodes. | |
535 Node attributes specified in nodes as a tuple take | |
536 precedence over attributes specified via keyword arguments. | |
537 | |
538 See Also | |
539 -------- | |
540 add_node | |
541 | |
542 Examples | |
543 -------- | |
544 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
545 >>> G.add_nodes_from('Hello') | |
546 >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) | |
547 >>> G.add_nodes_from(K3) | |
548 >>> sorted(G.nodes(), key=str) | |
549 [0, 1, 2, 'H', 'e', 'l', 'o'] | |
550 | |
551 Use keywords to update specific node attributes for every node. | |
552 | |
553 >>> G.add_nodes_from([1, 2], size=10) | |
554 >>> G.add_nodes_from([3, 4], weight=0.4) | |
555 | |
556 Use (node, attrdict) tuples to update attributes for specific nodes. | |
557 | |
558 >>> G.add_nodes_from([(1, dict(size=11)), (2, {'color':'blue'})]) | |
559 >>> G.nodes[1]['size'] | |
560 11 | |
561 >>> H = nx.Graph() | |
562 >>> H.add_nodes_from(G.nodes(data=True)) | |
563 >>> H.nodes[1]['size'] | |
564 11 | |
565 | |
566 """ | |
567 for n in nodes_for_adding: | |
568 # keep all this inside try/except because | |
569 # CPython throws TypeError on n not in self._node, | |
570 # while pre-2.7.5 ironpython throws on self._adj[n] | |
571 try: | |
572 if n not in self._node: | |
573 self._adj[n] = self.adjlist_inner_dict_factory() | |
574 attr_dict = self._node[n] = self.node_attr_dict_factory() | |
575 attr_dict.update(attr) | |
576 else: | |
577 self._node[n].update(attr) | |
578 except TypeError: | |
579 nn, ndict = n | |
580 if nn not in self._node: | |
581 self._adj[nn] = self.adjlist_inner_dict_factory() | |
582 newdict = attr.copy() | |
583 newdict.update(ndict) | |
584 attr_dict = self._node[nn] = self.node_attr_dict_factory() | |
585 attr_dict.update(newdict) | |
586 else: | |
587 olddict = self._node[nn] | |
588 olddict.update(attr) | |
589 olddict.update(ndict) | |
590 | |
591 def remove_node(self, n): | |
592 """Remove node n. | |
593 | |
594 Removes the node n and all adjacent edges. | |
595 Attempting to remove a non-existent node will raise an exception. | |
596 | |
597 Parameters | |
598 ---------- | |
599 n : node | |
600 A node in the graph | |
601 | |
602 Raises | |
603 ------- | |
604 NetworkXError | |
605 If n is not in the graph. | |
606 | |
607 See Also | |
608 -------- | |
609 remove_nodes_from | |
610 | |
611 Examples | |
612 -------- | |
613 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
614 >>> list(G.edges) | |
615 [(0, 1), (1, 2)] | |
616 >>> G.remove_node(1) | |
617 >>> list(G.edges) | |
618 [] | |
619 | |
620 """ | |
621 adj = self._adj | |
622 try: | |
623 nbrs = list(adj[n]) # list handles self-loops (allows mutation) | |
624 del self._node[n] | |
625 except KeyError: # NetworkXError if n not in self | |
626 raise NetworkXError("The node %s is not in the graph." % (n,)) | |
627 for u in nbrs: | |
628 del adj[u][n] # remove all edges n-u in graph | |
629 del adj[n] # now remove node | |
630 | |
631 def remove_nodes_from(self, nodes): | |
632 """Remove multiple nodes. | |
633 | |
634 Parameters | |
635 ---------- | |
636 nodes : iterable container | |
637 A container of nodes (list, dict, set, etc.). If a node | |
638 in the container is not in the graph it is silently | |
639 ignored. | |
640 | |
641 See Also | |
642 -------- | |
643 remove_node | |
644 | |
645 Examples | |
646 -------- | |
647 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
648 >>> e = list(G.nodes) | |
649 >>> e | |
650 [0, 1, 2] | |
651 >>> G.remove_nodes_from(e) | |
652 >>> list(G.nodes) | |
653 [] | |
654 | |
655 """ | |
656 adj = self._adj | |
657 for n in nodes: | |
658 try: | |
659 del self._node[n] | |
660 for u in list(adj[n]): # list handles self-loops | |
661 del adj[u][n] # (allows mutation of dict in loop) | |
662 del adj[n] | |
663 except KeyError: | |
664 pass | |
665 | |
666 @property | |
667 def nodes(self): | |
668 """A NodeView of the Graph as G.nodes or G.nodes(). | |
669 | |
670 Can be used as `G.nodes` for data lookup and for set-like operations. | |
671 Can also be used as `G.nodes(data='color', default=None)` to return a | |
672 NodeDataView which reports specific node data but no set operations. | |
673 It presents a dict-like interface as well with `G.nodes.items()` | |
674 iterating over `(node, nodedata)` 2-tuples and `G.nodes[3]['foo']` | |
675 providing the value of the `foo` attribute for node `3`. In addition, | |
676 a view `G.nodes.data('foo')` provides a dict-like interface to the | |
677 `foo` attribute of each node. `G.nodes.data('foo', default=1)` | |
678 provides a default for nodes that do not have attribute `foo`. | |
679 | |
680 Parameters | |
681 ---------- | |
682 data : string or bool, optional (default=False) | |
683 The node attribute returned in 2-tuple (n, ddict[data]). | |
684 If True, return entire node attribute dict as (n, ddict). | |
685 If False, return just the nodes n. | |
686 | |
687 default : value, optional (default=None) | |
688 Value used for nodes that don't have the requested attribute. | |
689 Only relevant if data is not True or False. | |
690 | |
691 Returns | |
692 ------- | |
693 NodeView | |
694 Allows set-like operations over the nodes as well as node | |
695 attribute dict lookup and calling to get a NodeDataView. | |
696 A NodeDataView iterates over `(n, data)` and has no set operations. | |
697 A NodeView iterates over `n` and includes set operations. | |
698 | |
699 When called, if data is False, an iterator over nodes. | |
700 Otherwise an iterator of 2-tuples (node, attribute value) | |
701 where the attribute is specified in `data`. | |
702 If data is True then the attribute becomes the | |
703 entire data dictionary. | |
704 | |
705 Notes | |
706 ----- | |
707 If your node data is not needed, it is simpler and equivalent | |
708 to use the expression ``for n in G``, or ``list(G)``. | |
709 | |
710 Examples | |
711 -------- | |
712 There are two simple ways of getting a list of all nodes in the graph: | |
713 | |
714 >>> G = nx.path_graph(3) | |
715 >>> list(G.nodes) | |
716 [0, 1, 2] | |
717 >>> list(G) | |
718 [0, 1, 2] | |
719 | |
720 To get the node data along with the nodes: | |
721 | |
722 >>> G.add_node(1, time='5pm') | |
723 >>> G.nodes[0]['foo'] = 'bar' | |
724 >>> list(G.nodes(data=True)) | |
725 [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] | |
726 >>> list(G.nodes.data()) | |
727 [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] | |
728 | |
729 >>> list(G.nodes(data='foo')) | |
730 [(0, 'bar'), (1, None), (2, None)] | |
731 >>> list(G.nodes.data('foo')) | |
732 [(0, 'bar'), (1, None), (2, None)] | |
733 | |
734 >>> list(G.nodes(data='time')) | |
735 [(0, None), (1, '5pm'), (2, None)] | |
736 >>> list(G.nodes.data('time')) | |
737 [(0, None), (1, '5pm'), (2, None)] | |
738 | |
739 >>> list(G.nodes(data='time', default='Not Available')) | |
740 [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] | |
741 >>> list(G.nodes.data('time', default='Not Available')) | |
742 [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] | |
743 | |
744 If some of your nodes have an attribute and the rest are assumed | |
745 to have a default attribute value you can create a dictionary | |
746 from node/attribute pairs using the `default` keyword argument | |
747 to guarantee the value is never None:: | |
748 | |
749 >>> G = nx.Graph() | |
750 >>> G.add_node(0) | |
751 >>> G.add_node(1, weight=2) | |
752 >>> G.add_node(2, weight=3) | |
753 >>> dict(G.nodes(data='weight', default=1)) | |
754 {0: 1, 1: 2, 2: 3} | |
755 | |
756 """ | |
757 nodes = NodeView(self) | |
758 # Lazy View creation: overload the (class) property on the instance | |
759 # Then future G.nodes use the existing View | |
760 # setattr doesn't work because attribute already exists | |
761 self.__dict__['nodes'] = nodes | |
762 return nodes | |
763 | |
764 def number_of_nodes(self): | |
765 """Returns the number of nodes in the graph. | |
766 | |
767 Returns | |
768 ------- | |
769 nnodes : int | |
770 The number of nodes in the graph. | |
771 | |
772 See Also | |
773 -------- | |
774 order, __len__ which are identical | |
775 | |
776 Examples | |
777 -------- | |
778 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
779 >>> G.number_of_nodes() | |
780 3 | |
781 """ | |
782 return len(self._node) | |
783 | |
784 def order(self): | |
785 """Returns the number of nodes in the graph. | |
786 | |
787 Returns | |
788 ------- | |
789 nnodes : int | |
790 The number of nodes in the graph. | |
791 | |
792 See Also | |
793 -------- | |
794 number_of_nodes, __len__ which are identical | |
795 | |
796 Examples | |
797 -------- | |
798 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
799 >>> G.order() | |
800 3 | |
801 """ | |
802 return len(self._node) | |
803 | |
804 def has_node(self, n): | |
805 """Returns True if the graph contains the node n. | |
806 | |
807 Identical to `n in G` | |
808 | |
809 Parameters | |
810 ---------- | |
811 n : node | |
812 | |
813 Examples | |
814 -------- | |
815 >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
816 >>> G.has_node(0) | |
817 True | |
818 | |
819 It is more readable and simpler to use | |
820 | |
821 >>> 0 in G | |
822 True | |
823 | |
824 """ | |
825 try: | |
826 return n in self._node | |
827 except TypeError: | |
828 return False | |
829 | |
830 def add_edge(self, u_of_edge, v_of_edge, **attr): | |
831 """Add an edge between u and v. | |
832 | |
833 The nodes u and v will be automatically added if they are | |
834 not already in the graph. | |
835 | |
836 Edge attributes can be specified with keywords or by directly | |
837 accessing the edge's attribute dictionary. See examples below. | |
838 | |
839 Parameters | |
840 ---------- | |
841 u, v : nodes | |
842 Nodes can be, for example, strings or numbers. | |
843 Nodes must be hashable (and not None) Python objects. | |
844 attr : keyword arguments, optional | |
845 Edge data (or labels or objects) can be assigned using | |
846 keyword arguments. | |
847 | |
848 See Also | |
849 -------- | |
850 add_edges_from : add a collection of edges | |
851 | |
852 Notes | |
853 ----- | |
854 Adding an edge that already exists updates the edge data. | |
855 | |
856 Many NetworkX algorithms designed for weighted graphs use | |
857 an edge attribute (by default `weight`) to hold a numerical value. | |
858 | |
859 Examples | |
860 -------- | |
861 The following all add the edge e=(1, 2) to graph G: | |
862 | |
863 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
864 >>> e = (1, 2) | |
865 >>> G.add_edge(1, 2) # explicit two-node form | |
866 >>> G.add_edge(*e) # single edge as tuple of two nodes | |
867 >>> G.add_edges_from([(1, 2)]) # add edges from iterable container | |
868 | |
869 Associate data to edges using keywords: | |
870 | |
871 >>> G.add_edge(1, 2, weight=3) | |
872 >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) | |
873 | |
874 For non-string attribute keys, use subscript notation. | |
875 | |
876 >>> G.add_edge(1, 2) | |
877 >>> G[1][2].update({0: 5}) | |
878 >>> G.edges[1, 2].update({0: 5}) | |
879 """ | |
880 u, v = u_of_edge, v_of_edge | |
881 # add nodes | |
882 if u not in self._node: | |
883 self._adj[u] = self.adjlist_inner_dict_factory() | |
884 self._node[u] = self.node_attr_dict_factory() | |
885 if v not in self._node: | |
886 self._adj[v] = self.adjlist_inner_dict_factory() | |
887 self._node[v] = self.node_attr_dict_factory() | |
888 # add the edge | |
889 datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) | |
890 datadict.update(attr) | |
891 self._adj[u][v] = datadict | |
892 self._adj[v][u] = datadict | |
893 | |
894 def add_edges_from(self, ebunch_to_add, **attr): | |
895 """Add all the edges in ebunch_to_add. | |
896 | |
897 Parameters | |
898 ---------- | |
899 ebunch_to_add : container of edges | |
900 Each edge given in the container will be added to the | |
901 graph. The edges must be given as as 2-tuples (u, v) or | |
902 3-tuples (u, v, d) where d is a dictionary containing edge data. | |
903 attr : keyword arguments, optional | |
904 Edge data (or labels or objects) can be assigned using | |
905 keyword arguments. | |
906 | |
907 See Also | |
908 -------- | |
909 add_edge : add a single edge | |
910 add_weighted_edges_from : convenient way to add weighted edges | |
911 | |
912 Notes | |
913 ----- | |
914 Adding the same edge twice has no effect but any edge data | |
915 will be updated when each duplicate edge is added. | |
916 | |
917 Edge attributes specified in an ebunch take precedence over | |
918 attributes specified via keyword arguments. | |
919 | |
920 Examples | |
921 -------- | |
922 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
923 >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples | |
924 >>> e = zip(range(0, 3), range(1, 4)) | |
925 >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 | |
926 | |
927 Associate data to edges | |
928 | |
929 >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) | |
930 >>> G.add_edges_from([(3, 4), (1, 4)], label='WN2898') | |
931 """ | |
932 for e in ebunch_to_add: | |
933 ne = len(e) | |
934 if ne == 3: | |
935 u, v, dd = e | |
936 elif ne == 2: | |
937 u, v = e | |
938 dd = {} # doesn't need edge_attr_dict_factory | |
939 else: | |
940 raise NetworkXError( | |
941 "Edge tuple %s must be a 2-tuple or 3-tuple." % (e,)) | |
942 if u not in self._node: | |
943 self._adj[u] = self.adjlist_inner_dict_factory() | |
944 self._node[u] = self.node_attr_dict_factory() | |
945 if v not in self._node: | |
946 self._adj[v] = self.adjlist_inner_dict_factory() | |
947 self._node[v] = self.node_attr_dict_factory() | |
948 datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) | |
949 datadict.update(attr) | |
950 datadict.update(dd) | |
951 self._adj[u][v] = datadict | |
952 self._adj[v][u] = datadict | |
953 | |
954 def add_weighted_edges_from(self, ebunch_to_add, weight='weight', **attr): | |
955 """Add weighted edges in `ebunch_to_add` with specified weight attr | |
956 | |
957 Parameters | |
958 ---------- | |
959 ebunch_to_add : container of edges | |
960 Each edge given in the list or container will be added | |
961 to the graph. The edges must be given as 3-tuples (u, v, w) | |
962 where w is a number. | |
963 weight : string, optional (default= 'weight') | |
964 The attribute name for the edge weights to be added. | |
965 attr : keyword arguments, optional (default= no attributes) | |
966 Edge attributes to add/update for all edges. | |
967 | |
968 See Also | |
969 -------- | |
970 add_edge : add a single edge | |
971 add_edges_from : add multiple edges | |
972 | |
973 Notes | |
974 ----- | |
975 Adding the same edge twice for Graph/DiGraph simply updates | |
976 the edge data. For MultiGraph/MultiDiGraph, duplicate edges | |
977 are stored. | |
978 | |
979 Examples | |
980 -------- | |
981 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
982 >>> G.add_weighted_edges_from([(0, 1, 3.0), (1, 2, 7.5)]) | |
983 """ | |
984 self.add_edges_from(((u, v, {weight: d}) for u, v, d in ebunch_to_add), | |
985 **attr) | |
986 | |
987 def remove_edge(self, u, v): | |
988 """Remove the edge between u and v. | |
989 | |
990 Parameters | |
991 ---------- | |
992 u, v : nodes | |
993 Remove the edge between nodes u and v. | |
994 | |
995 Raises | |
996 ------ | |
997 NetworkXError | |
998 If there is not an edge between u and v. | |
999 | |
1000 See Also | |
1001 -------- | |
1002 remove_edges_from : remove a collection of edges | |
1003 | |
1004 Examples | |
1005 -------- | |
1006 >>> G = nx.path_graph(4) # or DiGraph, etc | |
1007 >>> G.remove_edge(0, 1) | |
1008 >>> e = (1, 2) | |
1009 >>> G.remove_edge(*e) # unpacks e from an edge tuple | |
1010 >>> e = (2, 3, {'weight':7}) # an edge with attribute data | |
1011 >>> G.remove_edge(*e[:2]) # select first part of edge tuple | |
1012 """ | |
1013 try: | |
1014 del self._adj[u][v] | |
1015 if u != v: # self-loop needs only one entry removed | |
1016 del self._adj[v][u] | |
1017 except KeyError: | |
1018 raise NetworkXError("The edge %s-%s is not in the graph" % (u, v)) | |
1019 | |
1020 def remove_edges_from(self, ebunch): | |
1021 """Remove all edges specified in ebunch. | |
1022 | |
1023 Parameters | |
1024 ---------- | |
1025 ebunch: list or container of edge tuples | |
1026 Each edge given in the list or container will be removed | |
1027 from the graph. The edges can be: | |
1028 | |
1029 - 2-tuples (u, v) edge between u and v. | |
1030 - 3-tuples (u, v, k) where k is ignored. | |
1031 | |
1032 See Also | |
1033 -------- | |
1034 remove_edge : remove a single edge | |
1035 | |
1036 Notes | |
1037 ----- | |
1038 Will fail silently if an edge in ebunch is not in the graph. | |
1039 | |
1040 Examples | |
1041 -------- | |
1042 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1043 >>> ebunch=[(1, 2), (2, 3)] | |
1044 >>> G.remove_edges_from(ebunch) | |
1045 """ | |
1046 adj = self._adj | |
1047 for e in ebunch: | |
1048 u, v = e[:2] # ignore edge data if present | |
1049 if u in adj and v in adj[u]: | |
1050 del adj[u][v] | |
1051 if u != v: # self loop needs only one entry removed | |
1052 del adj[v][u] | |
1053 | |
1054 def update(self, edges=None, nodes=None): | |
1055 """Update the graph using nodes/edges/graphs as input. | |
1056 | |
1057 Like dict.update, this method takes a graph as input, adding the | |
1058 graph's nodes and edges to this graph. It can also take two inputs: | |
1059 edges and nodes. Finally it can take either edges or nodes. | |
1060 To specify only nodes the keyword `nodes` must be used. | |
1061 | |
1062 The collections of edges and nodes are treated similarly to | |
1063 the add_edges_from/add_nodes_from methods. When iterated, they | |
1064 should yield 2-tuples (u, v) or 3-tuples (u, v, datadict). | |
1065 | |
1066 Parameters | |
1067 ---------- | |
1068 edges : Graph object, collection of edges, or None | |
1069 The first parameter can be a graph or some edges. If it has | |
1070 attributes `nodes` and `edges`, then it is taken to be a | |
1071 Graph-like object and those attributes are used as collections | |
1072 of nodes and edges to be added to the graph. | |
1073 If the first parameter does not have those attributes, it is | |
1074 treated as a collection of edges and added to the graph. | |
1075 If the first argument is None, no edges are added. | |
1076 nodes : collection of nodes, or None | |
1077 The second parameter is treated as a collection of nodes | |
1078 to be added to the graph unless it is None. | |
1079 If `edges is None` and `nodes is None` an exception is raised. | |
1080 If the first parameter is a Graph, then `nodes` is ignored. | |
1081 | |
1082 Examples | |
1083 -------- | |
1084 >>> G = nx.path_graph(5) | |
1085 >>> G.update(nx.complete_graph(range(4,10))) | |
1086 >>> from itertools import combinations | |
1087 >>> edges = ((u, v, {'power': u * v}) | |
1088 ... for u, v in combinations(range(10, 20), 2) | |
1089 ... if u * v < 225) | |
1090 >>> nodes = [1000] # for singleton, use a container | |
1091 >>> G.update(edges, nodes) | |
1092 | |
1093 Notes | |
1094 ----- | |
1095 It you want to update the graph using an adjacency structure | |
1096 it is straightforward to obtain the edges/nodes from adjacency. | |
1097 The following examples provide common cases, your adjacency may | |
1098 be slightly different and require tweaks of these examples. | |
1099 | |
1100 >>> # dict-of-set/list/tuple | |
1101 >>> adj = {1: {2, 3}, 2: {1, 3}, 3: {1, 2}} | |
1102 >>> e = [(u, v) for u, nbrs in adj.items() for v in nbrs] | |
1103 >>> G.update(edges=e, nodes=adj) | |
1104 | |
1105 >>> DG = nx.DiGraph() | |
1106 >>> # dict-of-dict-of-attribute | |
1107 >>> adj = {1: {2: 1.3, 3: 0.7}, 2: {1: 1.4}, 3: {1: 0.7}} | |
1108 >>> e = [(u, v, {'weight': d}) for u, nbrs in adj.items() | |
1109 ... for v, d in nbrs.items()] | |
1110 >>> DG.update(edges=e, nodes=adj) | |
1111 | |
1112 >>> # dict-of-dict-of-dict | |
1113 >>> adj = {1: {2: {'weight': 1.3}, 3: {'color': 0.7, 'weight':1.2}}} | |
1114 >>> e = [(u, v, {'weight': d}) for u, nbrs in adj.items() | |
1115 ... for v, d in nbrs.items()] | |
1116 >>> DG.update(edges=e, nodes=adj) | |
1117 | |
1118 >>> # predecessor adjacency (dict-of-set) | |
1119 >>> pred = {1: {2, 3}, 2: {3}, 3: {3}} | |
1120 >>> e = [(v, u) for u, nbrs in pred.items() for v in nbrs] | |
1121 | |
1122 >>> # MultiGraph dict-of-dict-of-dict-of-attribute | |
1123 >>> MDG = nx.MultiDiGraph() | |
1124 >>> adj = {1: {2: {0: {'weight': 1.3}, 1: {'weight': 1.2}}}, | |
1125 ... 3: {2: {0: {'weight': 0.7}}}} | |
1126 >>> e = [(u, v, ekey, d) for u, nbrs in adj.items() | |
1127 ... for v, keydict in nbrs.items() | |
1128 ... for ekey, d in keydict.items()] | |
1129 >>> MDG.update(edges=e) | |
1130 | |
1131 See Also | |
1132 -------- | |
1133 add_edges_from: add multiple edges to a graph | |
1134 add_nodes_from: add multiple nodes to a graph | |
1135 """ | |
1136 if edges is not None: | |
1137 if nodes is not None: | |
1138 self.add_nodes_from(nodes) | |
1139 self.add_edges_from(edges) | |
1140 else: | |
1141 # check if edges is a Graph object | |
1142 try: | |
1143 graph_nodes = edges.nodes | |
1144 graph_edges = edges.edges | |
1145 except AttributeError: | |
1146 # edge not Graph-like | |
1147 self.add_edges_from(edges) | |
1148 else: # edges is Graph-like | |
1149 self.add_nodes_from(graph_nodes.data()) | |
1150 self.add_edges_from(graph_edges.data()) | |
1151 self.graph.update(edges.graph) | |
1152 elif nodes is not None: | |
1153 self.add_nodes_from(nodes) | |
1154 else: | |
1155 raise NetworkXError("update needs nodes or edges input") | |
1156 | |
1157 def has_edge(self, u, v): | |
1158 """Returns True if the edge (u, v) is in the graph. | |
1159 | |
1160 This is the same as `v in G[u]` without KeyError exceptions. | |
1161 | |
1162 Parameters | |
1163 ---------- | |
1164 u, v : nodes | |
1165 Nodes can be, for example, strings or numbers. | |
1166 Nodes must be hashable (and not None) Python objects. | |
1167 | |
1168 Returns | |
1169 ------- | |
1170 edge_ind : bool | |
1171 True if edge is in the graph, False otherwise. | |
1172 | |
1173 Examples | |
1174 -------- | |
1175 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1176 >>> G.has_edge(0, 1) # using two nodes | |
1177 True | |
1178 >>> e = (0, 1) | |
1179 >>> G.has_edge(*e) # e is a 2-tuple (u, v) | |
1180 True | |
1181 >>> e = (0, 1, {'weight':7}) | |
1182 >>> G.has_edge(*e[:2]) # e is a 3-tuple (u, v, data_dictionary) | |
1183 True | |
1184 | |
1185 The following syntax are equivalent: | |
1186 | |
1187 >>> G.has_edge(0, 1) | |
1188 True | |
1189 >>> 1 in G[0] # though this gives KeyError if 0 not in G | |
1190 True | |
1191 | |
1192 """ | |
1193 try: | |
1194 return v in self._adj[u] | |
1195 except KeyError: | |
1196 return False | |
1197 | |
1198 def neighbors(self, n): | |
1199 """Returns an iterator over all neighbors of node n. | |
1200 | |
1201 This is identical to `iter(G[n])` | |
1202 | |
1203 Parameters | |
1204 ---------- | |
1205 n : node | |
1206 A node in the graph | |
1207 | |
1208 Returns | |
1209 ------- | |
1210 neighbors : iterator | |
1211 An iterator over all neighbors of node n | |
1212 | |
1213 Raises | |
1214 ------ | |
1215 NetworkXError | |
1216 If the node n is not in the graph. | |
1217 | |
1218 Examples | |
1219 -------- | |
1220 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1221 >>> [n for n in G.neighbors(0)] | |
1222 [1] | |
1223 | |
1224 Notes | |
1225 ----- | |
1226 It is usually more convenient (and faster) to access the | |
1227 adjacency dictionary as ``G[n]``: | |
1228 | |
1229 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1230 >>> G.add_edge('a', 'b', weight=7) | |
1231 >>> G['a'] | |
1232 AtlasView({'b': {'weight': 7}}) | |
1233 >>> G = nx.path_graph(4) | |
1234 >>> [n for n in G[0]] | |
1235 [1] | |
1236 """ | |
1237 try: | |
1238 return iter(self._adj[n]) | |
1239 except KeyError: | |
1240 raise NetworkXError("The node %s is not in the graph." % (n,)) | |
1241 | |
1242 @property | |
1243 def edges(self): | |
1244 """An EdgeView of the Graph as G.edges or G.edges(). | |
1245 | |
1246 edges(self, nbunch=None, data=False, default=None) | |
1247 | |
1248 The EdgeView provides set-like operations on the edge-tuples | |
1249 as well as edge attribute lookup. When called, it also provides | |
1250 an EdgeDataView object which allows control of access to edge | |
1251 attributes (but does not provide set-like operations). | |
1252 Hence, `G.edges[u, v]['color']` provides the value of the color | |
1253 attribute for edge `(u, v)` while | |
1254 `for (u, v, c) in G.edges.data('color', default='red'):` | |
1255 iterates through all the edges yielding the color attribute | |
1256 with default `'red'` if no color attribute exists. | |
1257 | |
1258 Parameters | |
1259 ---------- | |
1260 nbunch : single node, container, or all nodes (default= all nodes) | |
1261 The view will only report edges incident to these nodes. | |
1262 data : string or bool, optional (default=False) | |
1263 The edge attribute returned in 3-tuple (u, v, ddict[data]). | |
1264 If True, return edge attribute dict in 3-tuple (u, v, ddict). | |
1265 If False, return 2-tuple (u, v). | |
1266 default : value, optional (default=None) | |
1267 Value used for edges that don't have the requested attribute. | |
1268 Only relevant if data is not True or False. | |
1269 | |
1270 Returns | |
1271 ------- | |
1272 edges : EdgeView | |
1273 A view of edge attributes, usually it iterates over (u, v) | |
1274 or (u, v, d) tuples of edges, but can also be used for | |
1275 attribute lookup as `edges[u, v]['foo']`. | |
1276 | |
1277 Notes | |
1278 ----- | |
1279 Nodes in nbunch that are not in the graph will be (quietly) ignored. | |
1280 For directed graphs this returns the out-edges. | |
1281 | |
1282 Examples | |
1283 -------- | |
1284 >>> G = nx.path_graph(3) # or MultiGraph, etc | |
1285 >>> G.add_edge(2, 3, weight=5) | |
1286 >>> [e for e in G.edges] | |
1287 [(0, 1), (1, 2), (2, 3)] | |
1288 >>> G.edges.data() # default data is {} (empty dict) | |
1289 EdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) | |
1290 >>> G.edges.data('weight', default=1) | |
1291 EdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) | |
1292 >>> G.edges([0, 3]) # only edges incident to these nodes | |
1293 EdgeDataView([(0, 1), (3, 2)]) | |
1294 >>> G.edges(0) # only edges incident to a single node (use G.adj[0]?) | |
1295 EdgeDataView([(0, 1)]) | |
1296 """ | |
1297 return EdgeView(self) | |
1298 | |
1299 def get_edge_data(self, u, v, default=None): | |
1300 """Returns the attribute dictionary associated with edge (u, v). | |
1301 | |
1302 This is identical to `G[u][v]` except the default is returned | |
1303 instead of an exception if the edge doesn't exist. | |
1304 | |
1305 Parameters | |
1306 ---------- | |
1307 u, v : nodes | |
1308 default: any Python object (default=None) | |
1309 Value to return if the edge (u, v) is not found. | |
1310 | |
1311 Returns | |
1312 ------- | |
1313 edge_dict : dictionary | |
1314 The edge attribute dictionary. | |
1315 | |
1316 Examples | |
1317 -------- | |
1318 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1319 >>> G[0][1] | |
1320 {} | |
1321 | |
1322 Warning: Assigning to `G[u][v]` is not permitted. | |
1323 But it is safe to assign attributes `G[u][v]['foo']` | |
1324 | |
1325 >>> G[0][1]['weight'] = 7 | |
1326 >>> G[0][1]['weight'] | |
1327 7 | |
1328 >>> G[1][0]['weight'] | |
1329 7 | |
1330 | |
1331 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1332 >>> G.get_edge_data(0, 1) # default edge data is {} | |
1333 {} | |
1334 >>> e = (0, 1) | |
1335 >>> G.get_edge_data(*e) # tuple form | |
1336 {} | |
1337 >>> G.get_edge_data('a', 'b', default=0) # edge not in graph, return 0 | |
1338 0 | |
1339 """ | |
1340 try: | |
1341 return self._adj[u][v] | |
1342 except KeyError: | |
1343 return default | |
1344 | |
1345 def adjacency(self): | |
1346 """Returns an iterator over (node, adjacency dict) tuples for all nodes. | |
1347 | |
1348 For directed graphs, only outgoing neighbors/adjacencies are included. | |
1349 | |
1350 Returns | |
1351 ------- | |
1352 adj_iter : iterator | |
1353 An iterator over (node, adjacency dictionary) for all nodes in | |
1354 the graph. | |
1355 | |
1356 Examples | |
1357 -------- | |
1358 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1359 >>> [(n, nbrdict) for n, nbrdict in G.adjacency()] | |
1360 [(0, {1: {}}), (1, {0: {}, 2: {}}), (2, {1: {}, 3: {}}), (3, {2: {}})] | |
1361 | |
1362 """ | |
1363 return iter(self._adj.items()) | |
1364 | |
1365 @property | |
1366 def degree(self): | |
1367 """A DegreeView for the Graph as G.degree or G.degree(). | |
1368 | |
1369 The node degree is the number of edges adjacent to the node. | |
1370 The weighted node degree is the sum of the edge weights for | |
1371 edges incident to that node. | |
1372 | |
1373 This object provides an iterator for (node, degree) as well as | |
1374 lookup for the degree for a single node. | |
1375 | |
1376 Parameters | |
1377 ---------- | |
1378 nbunch : single node, container, or all nodes (default= all nodes) | |
1379 The view will only report edges incident to these nodes. | |
1380 | |
1381 weight : string or None, optional (default=None) | |
1382 The name of an edge attribute that holds the numerical value used | |
1383 as a weight. If None, then each edge has weight 1. | |
1384 The degree is the sum of the edge weights adjacent to the node. | |
1385 | |
1386 Returns | |
1387 ------- | |
1388 If a single node is requested | |
1389 deg : int | |
1390 Degree of the node | |
1391 | |
1392 OR if multiple nodes are requested | |
1393 nd_view : A DegreeView object capable of iterating (node, degree) pairs | |
1394 | |
1395 Examples | |
1396 -------- | |
1397 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1398 >>> G.degree[0] # node 0 has degree 1 | |
1399 1 | |
1400 >>> list(G.degree([0, 1, 2])) | |
1401 [(0, 1), (1, 2), (2, 2)] | |
1402 """ | |
1403 return DegreeView(self) | |
1404 | |
1405 def clear(self): | |
1406 """Remove all nodes and edges from the graph. | |
1407 | |
1408 This also removes the name, and all graph, node, and edge attributes. | |
1409 | |
1410 Examples | |
1411 -------- | |
1412 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1413 >>> G.clear() | |
1414 >>> list(G.nodes) | |
1415 [] | |
1416 >>> list(G.edges) | |
1417 [] | |
1418 | |
1419 """ | |
1420 self._adj.clear() | |
1421 self._node.clear() | |
1422 self.graph.clear() | |
1423 | |
1424 def is_multigraph(self): | |
1425 """Returns True if graph is a multigraph, False otherwise.""" | |
1426 return False | |
1427 | |
1428 def is_directed(self): | |
1429 """Returns True if graph is directed, False otherwise.""" | |
1430 return False | |
1431 | |
1432 def copy(self, as_view=False): | |
1433 """Returns a copy of the graph. | |
1434 | |
1435 The copy method by default returns an independent shallow copy | |
1436 of the graph and attributes. That is, if an attribute is a | |
1437 container, that container is shared by the original an the copy. | |
1438 Use Python's `copy.deepcopy` for new containers. | |
1439 | |
1440 If `as_view` is True then a view is returned instead of a copy. | |
1441 | |
1442 Notes | |
1443 ----- | |
1444 All copies reproduce the graph structure, but data attributes | |
1445 may be handled in different ways. There are four types of copies | |
1446 of a graph that people might want. | |
1447 | |
1448 Deepcopy -- A "deepcopy" copies the graph structure as well as | |
1449 all data attributes and any objects they might contain. | |
1450 The entire graph object is new so that changes in the copy | |
1451 do not affect the original object. (see Python's copy.deepcopy) | |
1452 | |
1453 Data Reference (Shallow) -- For a shallow copy the graph structure | |
1454 is copied but the edge, node and graph attribute dicts are | |
1455 references to those in the original graph. This saves | |
1456 time and memory but could cause confusion if you change an attribute | |
1457 in one graph and it changes the attribute in the other. | |
1458 NetworkX does not provide this level of shallow copy. | |
1459 | |
1460 Independent Shallow -- This copy creates new independent attribute | |
1461 dicts and then does a shallow copy of the attributes. That is, any | |
1462 attributes that are containers are shared between the new graph | |
1463 and the original. This is exactly what `dict.copy()` provides. | |
1464 You can obtain this style copy using: | |
1465 | |
1466 >>> G = nx.path_graph(5) | |
1467 >>> H = G.copy() | |
1468 >>> H = G.copy(as_view=False) | |
1469 >>> H = nx.Graph(G) | |
1470 >>> H = G.__class__(G) | |
1471 | |
1472 Fresh Data -- For fresh data, the graph structure is copied while | |
1473 new empty data attribute dicts are created. The resulting graph | |
1474 is independent of the original and it has no edge, node or graph | |
1475 attributes. Fresh copies are not enabled. Instead use: | |
1476 | |
1477 >>> H = G.__class__() | |
1478 >>> H.add_nodes_from(G) | |
1479 >>> H.add_edges_from(G.edges) | |
1480 | |
1481 View -- Inspired by dict-views, graph-views act like read-only | |
1482 versions of the original graph, providing a copy of the original | |
1483 structure without requiring any memory for copying the information. | |
1484 | |
1485 See the Python copy module for more information on shallow | |
1486 and deep copies, https://docs.python.org/2/library/copy.html. | |
1487 | |
1488 Parameters | |
1489 ---------- | |
1490 as_view : bool, optional (default=False) | |
1491 If True, the returned graph-view provides a read-only view | |
1492 of the original graph without actually copying any data. | |
1493 | |
1494 Returns | |
1495 ------- | |
1496 G : Graph | |
1497 A copy of the graph. | |
1498 | |
1499 See Also | |
1500 -------- | |
1501 to_directed: return a directed copy of the graph. | |
1502 | |
1503 Examples | |
1504 -------- | |
1505 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1506 >>> H = G.copy() | |
1507 | |
1508 """ | |
1509 if as_view is True: | |
1510 return nx.graphviews.generic_graph_view(self) | |
1511 G = self.__class__() | |
1512 G.graph.update(self.graph) | |
1513 G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) | |
1514 G.add_edges_from((u, v, datadict.copy()) | |
1515 for u, nbrs in self._adj.items() | |
1516 for v, datadict in nbrs.items()) | |
1517 return G | |
1518 | |
1519 def to_directed(self, as_view=False): | |
1520 """Returns a directed representation of the graph. | |
1521 | |
1522 Returns | |
1523 ------- | |
1524 G : DiGraph | |
1525 A directed graph with the same name, same nodes, and with | |
1526 each edge (u, v, data) replaced by two directed edges | |
1527 (u, v, data) and (v, u, data). | |
1528 | |
1529 Notes | |
1530 ----- | |
1531 This returns a "deepcopy" of the edge, node, and | |
1532 graph attributes which attempts to completely copy | |
1533 all of the data and references. | |
1534 | |
1535 This is in contrast to the similar D=DiGraph(G) which returns a | |
1536 shallow copy of the data. | |
1537 | |
1538 See the Python copy module for more information on shallow | |
1539 and deep copies, https://docs.python.org/2/library/copy.html. | |
1540 | |
1541 Warning: If you have subclassed Graph to use dict-like objects | |
1542 in the data structure, those changes do not transfer to the | |
1543 DiGraph created by this method. | |
1544 | |
1545 Examples | |
1546 -------- | |
1547 >>> G = nx.Graph() # or MultiGraph, etc | |
1548 >>> G.add_edge(0, 1) | |
1549 >>> H = G.to_directed() | |
1550 >>> list(H.edges) | |
1551 [(0, 1), (1, 0)] | |
1552 | |
1553 If already directed, return a (deep) copy | |
1554 | |
1555 >>> G = nx.DiGraph() # or MultiDiGraph, etc | |
1556 >>> G.add_edge(0, 1) | |
1557 >>> H = G.to_directed() | |
1558 >>> list(H.edges) | |
1559 [(0, 1)] | |
1560 """ | |
1561 graph_class = self.to_directed_class() | |
1562 if as_view is True: | |
1563 return nx.graphviews.generic_graph_view(self, graph_class) | |
1564 # deepcopy when not a view | |
1565 G = graph_class() | |
1566 G.graph.update(deepcopy(self.graph)) | |
1567 G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) | |
1568 G.add_edges_from((u, v, deepcopy(data)) | |
1569 for u, nbrs in self._adj.items() | |
1570 for v, data in nbrs.items()) | |
1571 return G | |
1572 | |
1573 def to_undirected(self, as_view=False): | |
1574 """Returns an undirected copy of the graph. | |
1575 | |
1576 Parameters | |
1577 ---------- | |
1578 as_view : bool (optional, default=False) | |
1579 If True return a view of the original undirected graph. | |
1580 | |
1581 Returns | |
1582 ------- | |
1583 G : Graph/MultiGraph | |
1584 A deepcopy of the graph. | |
1585 | |
1586 See Also | |
1587 -------- | |
1588 Graph, copy, add_edge, add_edges_from | |
1589 | |
1590 Notes | |
1591 ----- | |
1592 This returns a "deepcopy" of the edge, node, and | |
1593 graph attributes which attempts to completely copy | |
1594 all of the data and references. | |
1595 | |
1596 This is in contrast to the similar `G = nx.DiGraph(D)` which returns a | |
1597 shallow copy of the data. | |
1598 | |
1599 See the Python copy module for more information on shallow | |
1600 and deep copies, https://docs.python.org/2/library/copy.html. | |
1601 | |
1602 Warning: If you have subclassed DiGraph to use dict-like objects | |
1603 in the data structure, those changes do not transfer to the | |
1604 Graph created by this method. | |
1605 | |
1606 Examples | |
1607 -------- | |
1608 >>> G = nx.path_graph(2) # or MultiGraph, etc | |
1609 >>> H = G.to_directed() | |
1610 >>> list(H.edges) | |
1611 [(0, 1), (1, 0)] | |
1612 >>> G2 = H.to_undirected() | |
1613 >>> list(G2.edges) | |
1614 [(0, 1)] | |
1615 """ | |
1616 graph_class = self.to_undirected_class() | |
1617 if as_view is True: | |
1618 return nx.graphviews.generic_graph_view(self, graph_class) | |
1619 # deepcopy when not a view | |
1620 G = graph_class() | |
1621 G.graph.update(deepcopy(self.graph)) | |
1622 G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) | |
1623 G.add_edges_from((u, v, deepcopy(d)) | |
1624 for u, nbrs in self._adj.items() | |
1625 for v, d in nbrs.items()) | |
1626 return G | |
1627 | |
1628 def subgraph(self, nodes): | |
1629 """Returns a SubGraph view of the subgraph induced on `nodes`. | |
1630 | |
1631 The induced subgraph of the graph contains the nodes in `nodes` | |
1632 and the edges between those nodes. | |
1633 | |
1634 Parameters | |
1635 ---------- | |
1636 nodes : list, iterable | |
1637 A container of nodes which will be iterated through once. | |
1638 | |
1639 Returns | |
1640 ------- | |
1641 G : SubGraph View | |
1642 A subgraph view of the graph. The graph structure cannot be | |
1643 changed but node/edge attributes can and are shared with the | |
1644 original graph. | |
1645 | |
1646 Notes | |
1647 ----- | |
1648 The graph, edge and node attributes are shared with the original graph. | |
1649 Changes to the graph structure is ruled out by the view, but changes | |
1650 to attributes are reflected in the original graph. | |
1651 | |
1652 To create a subgraph with its own copy of the edge/node attributes use: | |
1653 G.subgraph(nodes).copy() | |
1654 | |
1655 For an inplace reduction of a graph to a subgraph you can remove nodes: | |
1656 G.remove_nodes_from([n for n in G if n not in set(nodes)]) | |
1657 | |
1658 Subgraph views are sometimes NOT what you want. In most cases where | |
1659 you want to do more than simply look at the induced edges, it makes | |
1660 more sense to just create the subgraph as its own graph with code like: | |
1661 | |
1662 :: | |
1663 | |
1664 # Create a subgraph SG based on a (possibly multigraph) G | |
1665 SG = G.__class__() | |
1666 SG.add_nodes_from((n, G.nodes[n]) for n in largest_wcc) | |
1667 if SG.is_multigraph: | |
1668 SG.add_edges_from((n, nbr, key, d) | |
1669 for n, nbrs in G.adj.items() if n in largest_wcc | |
1670 for nbr, keydict in nbrs.items() if nbr in largest_wcc | |
1671 for key, d in keydict.items()) | |
1672 else: | |
1673 SG.add_edges_from((n, nbr, d) | |
1674 for n, nbrs in G.adj.items() if n in largest_wcc | |
1675 for nbr, d in nbrs.items() if nbr in largest_wcc) | |
1676 SG.graph.update(G.graph) | |
1677 | |
1678 Examples | |
1679 -------- | |
1680 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1681 >>> H = G.subgraph([0, 1, 2]) | |
1682 >>> list(H.edges) | |
1683 [(0, 1), (1, 2)] | |
1684 """ | |
1685 induced_nodes = nx.filters.show_nodes(self.nbunch_iter(nodes)) | |
1686 # if already a subgraph, don't make a chain | |
1687 subgraph = nx.graphviews.subgraph_view | |
1688 if hasattr(self, '_NODE_OK'): | |
1689 return subgraph(self._graph, induced_nodes, self._EDGE_OK) | |
1690 return subgraph(self, induced_nodes) | |
1691 | |
1692 def edge_subgraph(self, edges): | |
1693 """Returns the subgraph induced by the specified edges. | |
1694 | |
1695 The induced subgraph contains each edge in `edges` and each | |
1696 node incident to any one of those edges. | |
1697 | |
1698 Parameters | |
1699 ---------- | |
1700 edges : iterable | |
1701 An iterable of edges in this graph. | |
1702 | |
1703 Returns | |
1704 ------- | |
1705 G : Graph | |
1706 An edge-induced subgraph of this graph with the same edge | |
1707 attributes. | |
1708 | |
1709 Notes | |
1710 ----- | |
1711 The graph, edge, and node attributes in the returned subgraph | |
1712 view are references to the corresponding attributes in the original | |
1713 graph. The view is read-only. | |
1714 | |
1715 To create a full graph version of the subgraph with its own copy | |
1716 of the edge or node attributes, use:: | |
1717 | |
1718 >>> G.edge_subgraph(edges).copy() # doctest: +SKIP | |
1719 | |
1720 Examples | |
1721 -------- | |
1722 >>> G = nx.path_graph(5) | |
1723 >>> H = G.edge_subgraph([(0, 1), (3, 4)]) | |
1724 >>> list(H.nodes) | |
1725 [0, 1, 3, 4] | |
1726 >>> list(H.edges) | |
1727 [(0, 1), (3, 4)] | |
1728 | |
1729 """ | |
1730 return nx.edge_subgraph(self, edges) | |
1731 | |
1732 def size(self, weight=None): | |
1733 """Returns the number of edges or total of all edge weights. | |
1734 | |
1735 Parameters | |
1736 ---------- | |
1737 weight : string or None, optional (default=None) | |
1738 The edge attribute that holds the numerical value used | |
1739 as a weight. If None, then each edge has weight 1. | |
1740 | |
1741 Returns | |
1742 ------- | |
1743 size : numeric | |
1744 The number of edges or | |
1745 (if weight keyword is provided) the total weight sum. | |
1746 | |
1747 If weight is None, returns an int. Otherwise a float | |
1748 (or more general numeric if the weights are more general). | |
1749 | |
1750 See Also | |
1751 -------- | |
1752 number_of_edges | |
1753 | |
1754 Examples | |
1755 -------- | |
1756 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1757 >>> G.size() | |
1758 3 | |
1759 | |
1760 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc | |
1761 >>> G.add_edge('a', 'b', weight=2) | |
1762 >>> G.add_edge('b', 'c', weight=4) | |
1763 >>> G.size() | |
1764 2 | |
1765 >>> G.size(weight='weight') | |
1766 6.0 | |
1767 """ | |
1768 s = sum(d for v, d in self.degree(weight=weight)) | |
1769 # If `weight` is None, the sum of the degrees is guaranteed to be | |
1770 # even, so we can perform integer division and hence return an | |
1771 # integer. Otherwise, the sum of the weighted degrees is not | |
1772 # guaranteed to be an integer, so we perform "real" division. | |
1773 return s // 2 if weight is None else s / 2 | |
1774 | |
1775 def number_of_edges(self, u=None, v=None): | |
1776 """Returns the number of edges between two nodes. | |
1777 | |
1778 Parameters | |
1779 ---------- | |
1780 u, v : nodes, optional (default=all edges) | |
1781 If u and v are specified, return the number of edges between | |
1782 u and v. Otherwise return the total number of all edges. | |
1783 | |
1784 Returns | |
1785 ------- | |
1786 nedges : int | |
1787 The number of edges in the graph. If nodes `u` and `v` are | |
1788 specified return the number of edges between those nodes. If | |
1789 the graph is directed, this only returns the number of edges | |
1790 from `u` to `v`. | |
1791 | |
1792 See Also | |
1793 -------- | |
1794 size | |
1795 | |
1796 Examples | |
1797 -------- | |
1798 For undirected graphs, this method counts the total number of | |
1799 edges in the graph: | |
1800 | |
1801 >>> G = nx.path_graph(4) | |
1802 >>> G.number_of_edges() | |
1803 3 | |
1804 | |
1805 If you specify two nodes, this counts the total number of edges | |
1806 joining the two nodes: | |
1807 | |
1808 >>> G.number_of_edges(0, 1) | |
1809 1 | |
1810 | |
1811 For directed graphs, this method can count the total number of | |
1812 directed edges from `u` to `v`: | |
1813 | |
1814 >>> G = nx.DiGraph() | |
1815 >>> G.add_edge(0, 1) | |
1816 >>> G.add_edge(1, 0) | |
1817 >>> G.number_of_edges(0, 1) | |
1818 1 | |
1819 | |
1820 """ | |
1821 if u is None: | |
1822 return int(self.size()) | |
1823 if v in self._adj[u]: | |
1824 return 1 | |
1825 return 0 | |
1826 | |
1827 def nbunch_iter(self, nbunch=None): | |
1828 """Returns an iterator over nodes contained in nbunch that are | |
1829 also in the graph. | |
1830 | |
1831 The nodes in nbunch are checked for membership in the graph | |
1832 and if not are silently ignored. | |
1833 | |
1834 Parameters | |
1835 ---------- | |
1836 nbunch : single node, container, or all nodes (default= all nodes) | |
1837 The view will only report edges incident to these nodes. | |
1838 | |
1839 Returns | |
1840 ------- | |
1841 niter : iterator | |
1842 An iterator over nodes in nbunch that are also in the graph. | |
1843 If nbunch is None, iterate over all nodes in the graph. | |
1844 | |
1845 Raises | |
1846 ------ | |
1847 NetworkXError | |
1848 If nbunch is not a node or or sequence of nodes. | |
1849 If a node in nbunch is not hashable. | |
1850 | |
1851 See Also | |
1852 -------- | |
1853 Graph.__iter__ | |
1854 | |
1855 Notes | |
1856 ----- | |
1857 When nbunch is an iterator, the returned iterator yields values | |
1858 directly from nbunch, becoming exhausted when nbunch is exhausted. | |
1859 | |
1860 To test whether nbunch is a single node, one can use | |
1861 "if nbunch in self:", even after processing with this routine. | |
1862 | |
1863 If nbunch is not a node or a (possibly empty) sequence/iterator | |
1864 or None, a :exc:`NetworkXError` is raised. Also, if any object in | |
1865 nbunch is not hashable, a :exc:`NetworkXError` is raised. | |
1866 """ | |
1867 if nbunch is None: # include all nodes via iterator | |
1868 bunch = iter(self._adj) | |
1869 elif nbunch in self: # if nbunch is a single node | |
1870 bunch = iter([nbunch]) | |
1871 else: # if nbunch is a sequence of nodes | |
1872 def bunch_iter(nlist, adj): | |
1873 try: | |
1874 for n in nlist: | |
1875 if n in adj: | |
1876 yield n | |
1877 except TypeError as e: | |
1878 message = e.args[0] | |
1879 # capture error for non-sequence/iterator nbunch. | |
1880 if 'iter' in message: | |
1881 msg = "nbunch is not a node or a sequence of nodes." | |
1882 raise NetworkXError(msg) | |
1883 # capture error for unhashable node. | |
1884 elif 'hashable' in message: | |
1885 msg = "Node {} in sequence nbunch is not a valid node." | |
1886 raise NetworkXError(msg.format(n)) | |
1887 else: | |
1888 raise | |
1889 bunch = bunch_iter(nbunch, self._adj) | |
1890 return bunch |