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