comparison env/lib/python3.7/site-packages/networkx/classes/function.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 # Copyright (C) 2004-2019 by
2 # Aric Hagberg <hagberg@lanl.gov>
3 # Dan Schult <dschult@colgate.edu>
4 # Pieter Swart <swart@lanl.gov>
5 # All rights reserved.
6 # BSD license.
7 #
8 # Authors: Aric Hagberg <hagberg@lanl.gov>
9 # Pieter Swart <swart@lanl.gov>
10 # Dan Schult <dschult@colgate.edu>
11 """Functional interface to graph methods and assorted utilities.
12 """
13
14 from collections import Counter
15 from itertools import chain
16 try:
17 from itertools import zip_longest
18 except ImportError:
19 from itertools import izip_longest as zip_longest
20
21 import networkx as nx
22 from networkx.utils import pairwise, not_implemented_for
23
24 from networkx.classes.graphviews import subgraph_view, reverse_view
25
26 __all__ = ['nodes', 'edges', 'degree', 'degree_histogram', 'neighbors',
27 'number_of_nodes', 'number_of_edges', 'density',
28 'is_directed', 'info', 'freeze', 'is_frozen',
29 'subgraph', 'subgraph_view', 'induced_subgraph', 'reverse_view',
30 'edge_subgraph', 'restricted_view',
31 'to_directed', 'to_undirected',
32 'add_star', 'add_path', 'add_cycle',
33 'create_empty_copy', 'set_node_attributes',
34 'get_node_attributes', 'set_edge_attributes',
35 'get_edge_attributes', 'all_neighbors', 'non_neighbors',
36 'non_edges', 'common_neighbors', 'is_weighted',
37 'is_negatively_weighted', 'is_empty',
38 'selfloop_edges', 'nodes_with_selfloops', 'number_of_selfloops',
39 ]
40
41
42 def nodes(G):
43 """Returns an iterator over the graph nodes."""
44 return G.nodes()
45
46
47 def edges(G, nbunch=None):
48 """Returns an edge view of edges incident to nodes in nbunch.
49
50 Return all edges if nbunch is unspecified or nbunch=None.
51
52 For digraphs, edges=out_edges
53 """
54 return G.edges(nbunch)
55
56
57 def degree(G, nbunch=None, weight=None):
58 """Returns a degree view of single node or of nbunch of nodes.
59 If nbunch is omitted, then return degrees of *all* nodes.
60 """
61 return G.degree(nbunch, weight)
62
63
64 def neighbors(G, n):
65 """Returns a list of nodes connected to node n. """
66 return G.neighbors(n)
67
68
69 def number_of_nodes(G):
70 """Returns the number of nodes in the graph."""
71 return G.number_of_nodes()
72
73
74 def number_of_edges(G):
75 """Returns the number of edges in the graph. """
76 return G.number_of_edges()
77
78
79 def density(G):
80 r"""Returns the density of a graph.
81
82 The density for undirected graphs is
83
84 .. math::
85
86 d = \frac{2m}{n(n-1)},
87
88 and for directed graphs is
89
90 .. math::
91
92 d = \frac{m}{n(n-1)},
93
94 where `n` is the number of nodes and `m` is the number of edges in `G`.
95
96 Notes
97 -----
98 The density is 0 for a graph without edges and 1 for a complete graph.
99 The density of multigraphs can be higher than 1.
100
101 Self loops are counted in the total number of edges so graphs with self
102 loops can have density higher than 1.
103 """
104 n = number_of_nodes(G)
105 m = number_of_edges(G)
106 if m == 0 or n <= 1:
107 return 0
108 d = m / (n * (n - 1))
109 if not G.is_directed():
110 d *= 2
111 return d
112
113
114 def degree_histogram(G):
115 """Returns a list of the frequency of each degree value.
116
117 Parameters
118 ----------
119 G : Networkx graph
120 A graph
121
122 Returns
123 -------
124 hist : list
125 A list of frequencies of degrees.
126 The degree values are the index in the list.
127
128 Notes
129 -----
130 Note: the bins are width one, hence len(list) can be large
131 (Order(number_of_edges))
132 """
133 counts = Counter(d for n, d in G.degree())
134 return [counts.get(i, 0) for i in range(max(counts) + 1)]
135
136
137 def is_directed(G):
138 """ Return True if graph is directed."""
139 return G.is_directed()
140
141
142 def frozen(*args, **kwargs):
143 """Dummy method for raising errors when trying to modify frozen graphs"""
144 raise nx.NetworkXError("Frozen graph can't be modified")
145
146
147 def freeze(G):
148 """Modify graph to prevent further change by adding or removing
149 nodes or edges.
150
151 Node and edge data can still be modified.
152
153 Parameters
154 ----------
155 G : graph
156 A NetworkX graph
157
158 Examples
159 --------
160 >>> G = nx.path_graph(4)
161 >>> G = nx.freeze(G)
162 >>> try:
163 ... G.add_edge(4, 5)
164 ... except nx.NetworkXError as e:
165 ... print(str(e))
166 Frozen graph can't be modified
167
168 Notes
169 -----
170 To "unfreeze" a graph you must make a copy by creating a new graph object:
171
172 >>> graph = nx.path_graph(4)
173 >>> frozen_graph = nx.freeze(graph)
174 >>> unfrozen_graph = nx.Graph(frozen_graph)
175 >>> nx.is_frozen(unfrozen_graph)
176 False
177
178 See Also
179 --------
180 is_frozen
181 """
182 G.add_node = frozen
183 G.add_nodes_from = frozen
184 G.remove_node = frozen
185 G.remove_nodes_from = frozen
186 G.add_edge = frozen
187 G.add_edges_from = frozen
188 G.add_weighted_edges_from = frozen
189 G.remove_edge = frozen
190 G.remove_edges_from = frozen
191 G.clear = frozen
192 G.frozen = True
193 return G
194
195
196 def is_frozen(G):
197 """Returns True if graph is frozen.
198
199 Parameters
200 ----------
201 G : graph
202 A NetworkX graph
203
204 See Also
205 --------
206 freeze
207 """
208 try:
209 return G.frozen
210 except AttributeError:
211 return False
212
213
214 def add_star(G_to_add_to, nodes_for_star, **attr):
215 """Add a star to Graph G_to_add_to.
216
217 The first node in `nodes_for_star` is the middle of the star.
218 It is connected to all other nodes.
219
220 Parameters
221 ----------
222 G_to_add_to : graph
223 A NetworkX graph
224 nodes_for_star : iterable container
225 A container of nodes.
226 attr : keyword arguments, optional (default= no attributes)
227 Attributes to add to every edge in star.
228
229 See Also
230 --------
231 add_path, add_cycle
232
233 Examples
234 --------
235 >>> G = nx.Graph()
236 >>> nx.add_star(G, [0, 1, 2, 3])
237 >>> nx.add_star(G, [10, 11, 12], weight=2)
238 """
239 nlist = iter(nodes_for_star)
240 try:
241 v = next(nlist)
242 except StopIteration:
243 return
244 G_to_add_to.add_node(v)
245 edges = ((v, n) for n in nlist)
246 G_to_add_to.add_edges_from(edges, **attr)
247
248
249 def add_path(G_to_add_to, nodes_for_path, **attr):
250 """Add a path to the Graph G_to_add_to.
251
252 Parameters
253 ----------
254 G_to_add_to : graph
255 A NetworkX graph
256 nodes_for_path : iterable container
257 A container of nodes. A path will be constructed from
258 the nodes (in order) and added to the graph.
259 attr : keyword arguments, optional (default= no attributes)
260 Attributes to add to every edge in path.
261
262 See Also
263 --------
264 add_star, add_cycle
265
266 Examples
267 --------
268 >>> G = nx.Graph()
269 >>> nx.add_path(G, [0, 1, 2, 3])
270 >>> nx.add_path(G, [10, 11, 12], weight=7)
271 """
272 nlist = iter(nodes_for_path)
273 try:
274 first_node = next(nlist)
275 except StopIteration:
276 return
277 G_to_add_to.add_node(first_node)
278 G_to_add_to.add_edges_from(pairwise(chain((first_node,), nlist)), **attr)
279
280
281 def add_cycle(G_to_add_to, nodes_for_cycle, **attr):
282 """Add a cycle to the Graph G_to_add_to.
283
284 Parameters
285 ----------
286 G_to_add_to : graph
287 A NetworkX graph
288 nodes_for_cycle: iterable container
289 A container of nodes. A cycle will be constructed from
290 the nodes (in order) and added to the graph.
291 attr : keyword arguments, optional (default= no attributes)
292 Attributes to add to every edge in cycle.
293
294 See Also
295 --------
296 add_path, add_star
297
298 Examples
299 --------
300 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
301 >>> nx.add_cycle(G, [0, 1, 2, 3])
302 >>> nx.add_cycle(G, [10, 11, 12], weight=7)
303 """
304 nlist = iter(nodes_for_cycle)
305 try:
306 first_node = next(nlist)
307 except StopIteration:
308 return
309 G_to_add_to.add_node(first_node)
310 G_to_add_to.add_edges_from(pairwise(chain((first_node,), nlist), cyclic=True), **attr)
311
312
313 def subgraph(G, nbunch):
314 """Returns the subgraph induced on nodes in nbunch.
315
316 Parameters
317 ----------
318 G : graph
319 A NetworkX graph
320
321 nbunch : list, iterable
322 A container of nodes that will be iterated through once (thus
323 it should be an iterator or be iterable). Each element of the
324 container should be a valid node type: any hashable type except
325 None. If nbunch is None, return all edges data in the graph.
326 Nodes in nbunch that are not in the graph will be (quietly)
327 ignored.
328
329 Notes
330 -----
331 subgraph(G) calls G.subgraph()
332 """
333 return G.subgraph(nbunch)
334
335
336 def induced_subgraph(G, nbunch):
337 """Returns a SubGraph view of `G` showing only nodes in nbunch.
338
339 The induced subgraph of a graph on a set of nodes N is the
340 graph with nodes N and edges from G which have both ends in N.
341
342 Parameters
343 ----------
344 G : NetworkX Graph
345 nbunch : node, container of nodes or None (for all nodes)
346
347 Returns
348 -------
349 subgraph : SubGraph View
350 A read-only view of the subgraph in `G` induced by the nodes.
351 Changes to the graph `G` will be reflected in the view.
352
353 Notes
354 -----
355 To create a mutable subgraph with its own copies of nodes
356 edges and attributes use `subgraph.copy()` or `Graph(subgraph)`
357
358 For an inplace reduction of a graph to a subgraph you can remove nodes:
359 `G.remove_nodes_from(n in G if n not in set(nbunch))`
360
361 If you are going to compute subgraphs of your subgraphs you could
362 end up with a chain of views that can be very slow once the chain
363 has about 15 views in it. If they are all induced subgraphs, you
364 can short-cut the chain by making them all subgraphs of the original
365 graph. The graph class method `G.subgraph` does this when `G` is
366 a subgraph. In contrast, this function allows you to choose to build
367 chains or not, as you wish. The returned subgraph is a view on `G`.
368
369 Examples
370 --------
371 >>> import networkx as nx
372 >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc
373 >>> H = G.subgraph([0, 1, 2])
374 >>> list(H.edges)
375 [(0, 1), (1, 2)]
376 """
377 induced_nodes = nx.filters.show_nodes(G.nbunch_iter(nbunch))
378 return nx.graphviews.subgraph_view(G, induced_nodes)
379
380
381 def edge_subgraph(G, edges):
382 """Returns a view of the subgraph induced by the specified edges.
383
384 The induced subgraph contains each edge in `edges` and each
385 node incident to any of those edges.
386
387 Parameters
388 ----------
389 G : NetworkX Graph
390 edges : iterable
391 An iterable of edges. Edges not present in `G` are ignored.
392
393 Returns
394 -------
395 subgraph : SubGraph View
396 A read-only edge-induced subgraph of `G`.
397 Changes to `G` are reflected in the view.
398
399 Notes
400 -----
401 To create a mutable subgraph with its own copies of nodes
402 edges and attributes use `subgraph.copy()` or `Graph(subgraph)`
403
404 If you create a subgraph of a subgraph recursively you can end up
405 with a chain of subgraphs that becomes very slow with about 15
406 nested subgraph views. Luckily the edge_subgraph filter nests
407 nicely so you can use the original graph as G in this function
408 to avoid chains. We do not rule out chains programmatically so
409 that odd cases like an `edge_subgraph` of a `restricted_view`
410 can be created.
411
412 Examples
413 --------
414 >>> import networkx as nx
415 >>> G = nx.path_graph(5)
416 >>> H = G.edge_subgraph([(0, 1), (3, 4)])
417 >>> list(H.nodes)
418 [0, 1, 3, 4]
419 >>> list(H.edges)
420 [(0, 1), (3, 4)]
421 """
422 nxf = nx.filters
423 edges = set(edges)
424 nodes = set()
425 for e in edges:
426 nodes.update(e[:2])
427 induced_nodes = nxf.show_nodes(nodes)
428 if G.is_multigraph():
429 if G.is_directed():
430 induced_edges = nxf.show_multidiedges(edges)
431 else:
432 induced_edges = nxf.show_multiedges(edges)
433 else:
434 if G.is_directed():
435 induced_edges = nxf.show_diedges(edges)
436 else:
437 induced_edges = nxf.show_edges(edges)
438 return nx.graphviews.subgraph_view(G, induced_nodes, induced_edges)
439
440
441 def restricted_view(G, nodes, edges):
442 """Returns a view of `G` with hidden nodes and edges.
443
444 The resulting subgraph filters out node `nodes` and edges `edges`.
445 Filtered out nodes also filter out any of their edges.
446
447 Parameters
448 ----------
449 G : NetworkX Graph
450 nodes : iterable
451 An iterable of nodes. Nodes not present in `G` are ignored.
452 edges : iterable
453 An iterable of edges. Edges not present in `G` are ignored.
454
455 Returns
456 -------
457 subgraph : SubGraph View
458 A read-only restricted view of `G` filtering out nodes and edges.
459 Changes to `G` are reflected in the view.
460
461 Notes
462 -----
463 To create a mutable subgraph with its own copies of nodes
464 edges and attributes use `subgraph.copy()` or `Graph(subgraph)`
465
466 If you create a subgraph of a subgraph recursively you may end up
467 with a chain of subgraph views. Such chains can get quite slow
468 for lengths near 15. To avoid long chains, try to make your subgraph
469 based on the original graph. We do not rule out chains programmatically
470 so that odd cases like an `edge_subgraph` of a `restricted_view`
471 can be created.
472
473 Examples
474 --------
475 >>> import networkx as nx
476 >>> G = nx.path_graph(5)
477 >>> H = nx.restricted_view(G, [0], [(1, 2), (3, 4)])
478 >>> list(H.nodes)
479 [1, 2, 3, 4]
480 >>> list(H.edges)
481 [(2, 3)]
482 """
483 nxf = nx.filters
484 hide_nodes = nxf.hide_nodes(nodes)
485 if G.is_multigraph():
486 if G.is_directed():
487 hide_edges = nxf.hide_multidiedges(edges)
488 else:
489 hide_edges = nxf.hide_multiedges(edges)
490 else:
491 if G.is_directed():
492 hide_edges = nxf.hide_diedges(edges)
493 else:
494 hide_edges = nxf.hide_edges(edges)
495 return nx.graphviews.subgraph_view(G, hide_nodes, hide_edges)
496
497
498 def to_directed(graph):
499 """Returns a directed view of the graph `graph`.
500
501 Identical to graph.to_directed(as_view=True)
502 Note that graph.to_directed defaults to `as_view=False`
503 while this function always provides a view.
504 """
505 return graph.to_directed(as_view=True)
506
507
508 def to_undirected(graph):
509 """Returns an undirected view of the graph `graph`.
510
511 Identical to graph.to_undirected(as_view=True)
512 Note that graph.to_undirected defaults to `as_view=False`
513 while this function always provides a view.
514 """
515 return graph.to_undirected(as_view=True)
516
517
518 def create_empty_copy(G, with_data=True):
519 """Returns a copy of the graph G with all of the edges removed.
520
521 Parameters
522 ----------
523 G : graph
524 A NetworkX graph
525
526 with_data : bool (default=True)
527 Propagate Graph and Nodes data to the new graph.
528
529 See Also
530 -----
531 empty_graph
532
533 """
534 H = G.__class__()
535 H.add_nodes_from(G.nodes(data=with_data))
536 if with_data:
537 H.graph.update(G.graph)
538 return H
539
540
541 def info(G, n=None):
542 """Print short summary of information for the graph G or the node n.
543
544 Parameters
545 ----------
546 G : Networkx graph
547 A graph
548 n : node (any hashable)
549 A node in the graph G
550 """
551 info = '' # append this all to a string
552 if n is None:
553 info += "Name: %s\n" % G.name
554 type_name = [type(G).__name__]
555 info += "Type: %s\n" % ",".join(type_name)
556 info += "Number of nodes: %d\n" % G.number_of_nodes()
557 info += "Number of edges: %d\n" % G.number_of_edges()
558 nnodes = G.number_of_nodes()
559 if len(G) > 0:
560 if G.is_directed():
561 deg = sum(d for n, d in G.in_degree()) / float(nnodes)
562 info += "Average in degree: %8.4f\n" % deg
563 deg = sum(d for n, d in G.out_degree()) / float(nnodes)
564 info += "Average out degree: %8.4f" % deg
565 else:
566 s = sum(dict(G.degree()).values())
567 info += "Average degree: %8.4f" % (float(s) / float(nnodes))
568
569 else:
570 if n not in G:
571 raise nx.NetworkXError("node %s not in graph" % (n,))
572 info += "Node % s has the following properties:\n" % n
573 info += "Degree: %d\n" % G.degree(n)
574 info += "Neighbors: "
575 info += ' '.join(str(nbr) for nbr in G.neighbors(n))
576 return info
577
578
579 def set_node_attributes(G, values, name=None):
580 """Sets node attributes from a given value or dictionary of values.
581
582 .. Warning:: The call order of arguments `values` and `name`
583 switched between v1.x & v2.x.
584
585 Parameters
586 ----------
587 G : NetworkX Graph
588
589 values : scalar value, dict-like
590 What the node attribute should be set to. If `values` is
591 not a dictionary, then it is treated as a single attribute value
592 that is then applied to every node in `G`. This means that if
593 you provide a mutable object, like a list, updates to that object
594 will be reflected in the node attribute for every node.
595 The attribute name will be `name`.
596
597 If `values` is a dict or a dict of dict, it should be keyed
598 by node to either an attribute value or a dict of attribute key/value
599 pairs used to update the node's attributes.
600
601 name : string (optional, default=None)
602 Name of the node attribute to set if values is a scalar.
603
604 Examples
605 --------
606 After computing some property of the nodes of a graph, you may want
607 to assign a node attribute to store the value of that property for
608 each node::
609
610 >>> G = nx.path_graph(3)
611 >>> bb = nx.betweenness_centrality(G)
612 >>> isinstance(bb, dict)
613 True
614 >>> nx.set_node_attributes(G, bb, 'betweenness')
615 >>> G.nodes[1]['betweenness']
616 1.0
617
618 If you provide a list as the second argument, updates to the list
619 will be reflected in the node attribute for each node::
620
621 >>> G = nx.path_graph(3)
622 >>> labels = []
623 >>> nx.set_node_attributes(G, labels, 'labels')
624 >>> labels.append('foo')
625 >>> G.nodes[0]['labels']
626 ['foo']
627 >>> G.nodes[1]['labels']
628 ['foo']
629 >>> G.nodes[2]['labels']
630 ['foo']
631
632 If you provide a dictionary of dictionaries as the second argument,
633 the outer dictionary is assumed to be keyed by node to an inner
634 dictionary of node attributes for that node::
635
636 >>> G = nx.path_graph(3)
637 >>> attrs = {0: {'attr1': 20, 'attr2': 'nothing'}, 1: {'attr2': 3}}
638 >>> nx.set_node_attributes(G, attrs)
639 >>> G.nodes[0]['attr1']
640 20
641 >>> G.nodes[0]['attr2']
642 'nothing'
643 >>> G.nodes[1]['attr2']
644 3
645 >>> G.nodes[2]
646 {}
647
648 """
649 # Set node attributes based on type of `values`
650 if name is not None: # `values` must not be a dict of dict
651 try: # `values` is a dict
652 for n, v in values.items():
653 try:
654 G.nodes[n][name] = values[n]
655 except KeyError:
656 pass
657 except AttributeError: # `values` is a constant
658 for n in G:
659 G.nodes[n][name] = values
660 else: # `values` must be dict of dict
661 for n, d in values.items():
662 try:
663 G.nodes[n].update(d)
664 except KeyError:
665 pass
666
667
668 def get_node_attributes(G, name):
669 """Get node attributes from graph
670
671 Parameters
672 ----------
673 G : NetworkX Graph
674
675 name : string
676 Attribute name
677
678 Returns
679 -------
680 Dictionary of attributes keyed by node.
681
682 Examples
683 --------
684 >>> G = nx.Graph()
685 >>> G.add_nodes_from([1, 2, 3], color='red')
686 >>> color = nx.get_node_attributes(G, 'color')
687 >>> color[1]
688 'red'
689 """
690 return {n: d[name] for n, d in G.nodes.items() if name in d}
691
692
693 def set_edge_attributes(G, values, name=None):
694 """Sets edge attributes from a given value or dictionary of values.
695
696 .. Warning:: The call order of arguments `values` and `name`
697 switched between v1.x & v2.x.
698
699 Parameters
700 ----------
701 G : NetworkX Graph
702
703 values : scalar value, dict-like
704 What the edge attribute should be set to. If `values` is
705 not a dictionary, then it is treated as a single attribute value
706 that is then applied to every edge in `G`. This means that if
707 you provide a mutable object, like a list, updates to that object
708 will be reflected in the edge attribute for each edge. The attribute
709 name will be `name`.
710
711 If `values` is a dict or a dict of dict, it should be keyed
712 by edge tuple to either an attribute value or a dict of attribute
713 key/value pairs used to update the edge's attributes.
714 For multigraphs, the edge tuples must be of the form ``(u, v, key)``,
715 where `u` and `v` are nodes and `key` is the edge key.
716 For non-multigraphs, the keys must be tuples of the form ``(u, v)``.
717
718 name : string (optional, default=None)
719 Name of the edge attribute to set if values is a scalar.
720
721 Examples
722 --------
723 After computing some property of the edges of a graph, you may want
724 to assign a edge attribute to store the value of that property for
725 each edge::
726
727 >>> G = nx.path_graph(3)
728 >>> bb = nx.edge_betweenness_centrality(G, normalized=False)
729 >>> nx.set_edge_attributes(G, bb, 'betweenness')
730 >>> G.edges[1, 2]['betweenness']
731 2.0
732
733 If you provide a list as the second argument, updates to the list
734 will be reflected in the edge attribute for each edge::
735
736 >>> labels = []
737 >>> nx.set_edge_attributes(G, labels, 'labels')
738 >>> labels.append('foo')
739 >>> G.edges[0, 1]['labels']
740 ['foo']
741 >>> G.edges[1, 2]['labels']
742 ['foo']
743
744 If you provide a dictionary of dictionaries as the second argument,
745 the entire dictionary will be used to update edge attributes::
746
747 >>> G = nx.path_graph(3)
748 >>> attrs = {(0, 1): {'attr1': 20, 'attr2': 'nothing'},
749 ... (1, 2): {'attr2': 3}}
750 >>> nx.set_edge_attributes(G, attrs)
751 >>> G[0][1]['attr1']
752 20
753 >>> G[0][1]['attr2']
754 'nothing'
755 >>> G[1][2]['attr2']
756 3
757
758 """
759 if name is not None:
760 # `values` does not contain attribute names
761 try:
762 # if `values` is a dict using `.items()` => {edge: value}
763 if G.is_multigraph():
764 for (u, v, key), value in values.items():
765 try:
766 G[u][v][key][name] = value
767 except KeyError:
768 pass
769 else:
770 for (u, v), value in values.items():
771 try:
772 G[u][v][name] = value
773 except KeyError:
774 pass
775 except AttributeError:
776 # treat `values` as a constant
777 for u, v, data in G.edges(data=True):
778 data[name] = values
779 else:
780 # `values` consists of doct-of-dict {edge: {attr: value}} shape
781 if G.is_multigraph():
782 for (u, v, key), d in values.items():
783 try:
784 G[u][v][key].update(d)
785 except KeyError:
786 pass
787 else:
788 for (u, v), d in values.items():
789 try:
790 G[u][v].update(d)
791 except KeyError:
792 pass
793
794
795 def get_edge_attributes(G, name):
796 """Get edge attributes from graph
797
798 Parameters
799 ----------
800 G : NetworkX Graph
801
802 name : string
803 Attribute name
804
805 Returns
806 -------
807 Dictionary of attributes keyed by edge. For (di)graphs, the keys are
808 2-tuples of the form: (u, v). For multi(di)graphs, the keys are 3-tuples of
809 the form: (u, v, key).
810
811 Examples
812 --------
813 >>> G = nx.Graph()
814 >>> nx.add_path(G, [1, 2, 3], color='red')
815 >>> color = nx.get_edge_attributes(G, 'color')
816 >>> color[(1, 2)]
817 'red'
818 """
819 if G.is_multigraph():
820 edges = G.edges(keys=True, data=True)
821 else:
822 edges = G.edges(data=True)
823 return {x[:-1]: x[-1][name] for x in edges if name in x[-1]}
824
825
826 def all_neighbors(graph, node):
827 """Returns all of the neighbors of a node in the graph.
828
829 If the graph is directed returns predecessors as well as successors.
830
831 Parameters
832 ----------
833 graph : NetworkX graph
834 Graph to find neighbors.
835
836 node : node
837 The node whose neighbors will be returned.
838
839 Returns
840 -------
841 neighbors : iterator
842 Iterator of neighbors
843 """
844 if graph.is_directed():
845 values = chain(graph.predecessors(node), graph.successors(node))
846 else:
847 values = graph.neighbors(node)
848 return values
849
850
851 def non_neighbors(graph, node):
852 """Returns the non-neighbors of the node in the graph.
853
854 Parameters
855 ----------
856 graph : NetworkX graph
857 Graph to find neighbors.
858
859 node : node
860 The node whose neighbors will be returned.
861
862 Returns
863 -------
864 non_neighbors : iterator
865 Iterator of nodes in the graph that are not neighbors of the node.
866 """
867 nbors = set(neighbors(graph, node)) | {node}
868 return (nnode for nnode in graph if nnode not in nbors)
869
870
871 def non_edges(graph):
872 """Returns the non-existent edges in the graph.
873
874 Parameters
875 ----------
876 graph : NetworkX graph.
877 Graph to find non-existent edges.
878
879 Returns
880 -------
881 non_edges : iterator
882 Iterator of edges that are not in the graph.
883 """
884 if graph.is_directed():
885 for u in graph:
886 for v in non_neighbors(graph, u):
887 yield (u, v)
888 else:
889 nodes = set(graph)
890 while nodes:
891 u = nodes.pop()
892 for v in nodes - set(graph[u]):
893 yield (u, v)
894
895
896 @not_implemented_for('directed')
897 def common_neighbors(G, u, v):
898 """Returns the common neighbors of two nodes in a graph.
899
900 Parameters
901 ----------
902 G : graph
903 A NetworkX undirected graph.
904
905 u, v : nodes
906 Nodes in the graph.
907
908 Returns
909 -------
910 cnbors : iterator
911 Iterator of common neighbors of u and v in the graph.
912
913 Raises
914 ------
915 NetworkXError
916 If u or v is not a node in the graph.
917
918 Examples
919 --------
920 >>> G = nx.complete_graph(5)
921 >>> sorted(nx.common_neighbors(G, 0, 1))
922 [2, 3, 4]
923 """
924 if u not in G:
925 raise nx.NetworkXError('u is not in the graph.')
926 if v not in G:
927 raise nx.NetworkXError('v is not in the graph.')
928
929 # Return a generator explicitly instead of yielding so that the above
930 # checks are executed eagerly.
931 return (w for w in G[u] if w in G[v] and w not in (u, v))
932
933
934 def is_weighted(G, edge=None, weight='weight'):
935 """Returns True if `G` has weighted edges.
936
937 Parameters
938 ----------
939 G : graph
940 A NetworkX graph.
941
942 edge : tuple, optional
943 A 2-tuple specifying the only edge in `G` that will be tested. If
944 None, then every edge in `G` is tested.
945
946 weight: string, optional
947 The attribute name used to query for edge weights.
948
949 Returns
950 -------
951 bool
952 A boolean signifying if `G`, or the specified edge, is weighted.
953
954 Raises
955 ------
956 NetworkXError
957 If the specified edge does not exist.
958
959 Examples
960 --------
961 >>> G = nx.path_graph(4)
962 >>> nx.is_weighted(G)
963 False
964 >>> nx.is_weighted(G, (2, 3))
965 False
966
967 >>> G = nx.DiGraph()
968 >>> G.add_edge(1, 2, weight=1)
969 >>> nx.is_weighted(G)
970 True
971
972 """
973 if edge is not None:
974 data = G.get_edge_data(*edge)
975 if data is None:
976 msg = 'Edge {!r} does not exist.'.format(edge)
977 raise nx.NetworkXError(msg)
978 return weight in data
979
980 if is_empty(G):
981 # Special handling required since: all([]) == True
982 return False
983
984 return all(weight in data for u, v, data in G.edges(data=True))
985
986
987 def is_negatively_weighted(G, edge=None, weight='weight'):
988 """Returns True if `G` has negatively weighted edges.
989
990 Parameters
991 ----------
992 G : graph
993 A NetworkX graph.
994
995 edge : tuple, optional
996 A 2-tuple specifying the only edge in `G` that will be tested. If
997 None, then every edge in `G` is tested.
998
999 weight: string, optional
1000 The attribute name used to query for edge weights.
1001
1002 Returns
1003 -------
1004 bool
1005 A boolean signifying if `G`, or the specified edge, is negatively
1006 weighted.
1007
1008 Raises
1009 ------
1010 NetworkXError
1011 If the specified edge does not exist.
1012
1013 Examples
1014 --------
1015 >>> G = nx.Graph()
1016 >>> G.add_edges_from([(1, 3), (2, 4), (2, 6)])
1017 >>> G.add_edge(1, 2, weight=4)
1018 >>> nx.is_negatively_weighted(G, (1, 2))
1019 False
1020 >>> G[2][4]['weight'] = -2
1021 >>> nx.is_negatively_weighted(G)
1022 True
1023 >>> G = nx.DiGraph()
1024 >>> edges = [('0', '3', 3), ('0', '1', -5), ('1', '0', -2)]
1025 >>> G.add_weighted_edges_from(edges)
1026 >>> nx.is_negatively_weighted(G)
1027 True
1028
1029 """
1030 if edge is not None:
1031 data = G.get_edge_data(*edge)
1032 if data is None:
1033 msg = 'Edge {!r} does not exist.'.format(edge)
1034 raise nx.NetworkXError(msg)
1035 return weight in data and data[weight] < 0
1036
1037 return any(weight in data and data[weight] < 0
1038 for u, v, data in G.edges(data=True))
1039
1040
1041 def is_empty(G):
1042 """Returns True if `G` has no edges.
1043
1044 Parameters
1045 ----------
1046 G : graph
1047 A NetworkX graph.
1048
1049 Returns
1050 -------
1051 bool
1052 True if `G` has no edges, and False otherwise.
1053
1054 Notes
1055 -----
1056 An empty graph can have nodes but not edges. The empty graph with zero
1057 nodes is known as the null graph. This is an $O(n)$ operation where n
1058 is the number of nodes in the graph.
1059
1060 """
1061 return not any(G.adj.values())
1062
1063
1064 def nodes_with_selfloops(G):
1065 """Returns an iterator over nodes with self loops.
1066
1067 A node with a self loop has an edge with both ends adjacent
1068 to that node.
1069
1070 Returns
1071 -------
1072 nodelist : iterator
1073 A iterator over nodes with self loops.
1074
1075 See Also
1076 --------
1077 selfloop_edges, number_of_selfloops
1078
1079 Examples
1080 --------
1081 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
1082 >>> G.add_edge(1, 1)
1083 >>> G.add_edge(1, 2)
1084 >>> list(nx.nodes_with_selfloops(G))
1085 [1]
1086
1087 """
1088 return (n for n, nbrs in G.adj.items() if n in nbrs)
1089
1090
1091 def selfloop_edges(G, data=False, keys=False, default=None):
1092 """Returns an iterator over selfloop edges.
1093
1094 A selfloop edge has the same node at both ends.
1095
1096 Parameters
1097 ----------
1098 data : string or bool, optional (default=False)
1099 Return selfloop edges as two tuples (u, v) (data=False)
1100 or three-tuples (u, v, datadict) (data=True)
1101 or three-tuples (u, v, datavalue) (data='attrname')
1102 keys : bool, optional (default=False)
1103 If True, return edge keys with each edge.
1104 default : value, optional (default=None)
1105 Value used for edges that don't have the requested attribute.
1106 Only relevant if data is not True or False.
1107
1108 Returns
1109 -------
1110 edgeiter : iterator over edge tuples
1111 An iterator over all selfloop edges.
1112
1113 See Also
1114 --------
1115 nodes_with_selfloops, number_of_selfloops
1116
1117 Examples
1118 --------
1119 >>> G = nx.MultiGraph() # or Graph, DiGraph, MultiDiGraph, etc
1120 >>> ekey = G.add_edge(1, 1)
1121 >>> ekey = G.add_edge(1, 2)
1122 >>> list(nx.selfloop_edges(G))
1123 [(1, 1)]
1124 >>> list(nx.selfloop_edges(G, data=True))
1125 [(1, 1, {})]
1126 >>> list(nx.selfloop_edges(G, keys=True))
1127 [(1, 1, 0)]
1128 >>> list(nx.selfloop_edges(G, keys=True, data=True))
1129 [(1, 1, 0, {})]
1130 """
1131 if data is True:
1132 if G.is_multigraph():
1133 if keys is True:
1134 return ((n, n, k, d)
1135 for n, nbrs in G.adj.items()
1136 if n in nbrs for k, d in nbrs[n].items())
1137 else:
1138 return ((n, n, d)
1139 for n, nbrs in G.adj.items()
1140 if n in nbrs for d in nbrs[n].values())
1141 else:
1142 return ((n, n, nbrs[n]) for n, nbrs in G.adj.items() if n in nbrs)
1143 elif data is not False:
1144 if G.is_multigraph():
1145 if keys is True:
1146 return ((n, n, k, d.get(data, default))
1147 for n, nbrs in G.adj.items()
1148 if n in nbrs for k, d in nbrs[n].items())
1149 else:
1150 return ((n, n, d.get(data, default))
1151 for n, nbrs in G.adj.items()
1152 if n in nbrs for d in nbrs[n].values())
1153 else:
1154 return ((n, n, nbrs[n].get(data, default))
1155 for n, nbrs in G.adj.items() if n in nbrs)
1156 else:
1157 if G.is_multigraph():
1158 if keys is True:
1159 return ((n, n, k)
1160 for n, nbrs in G.adj.items()
1161 if n in nbrs for k in nbrs[n])
1162 else:
1163 return ((n, n)
1164 for n, nbrs in G.adj.items()
1165 if n in nbrs for d in nbrs[n].values())
1166 else:
1167 return ((n, n) for n, nbrs in G.adj.items() if n in nbrs)
1168
1169
1170 def number_of_selfloops(G):
1171 """Returns the number of selfloop edges.
1172
1173 A selfloop edge has the same node at both ends.
1174
1175 Returns
1176 -------
1177 nloops : int
1178 The number of selfloops.
1179
1180 See Also
1181 --------
1182 nodes_with_selfloops, selfloop_edges
1183
1184 Examples
1185 --------
1186 >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
1187 >>> G.add_edge(1, 1)
1188 >>> G.add_edge(1, 2)
1189 >>> nx.number_of_selfloops(G)
1190 1
1191 """
1192 return sum(1 for _ in nx.selfloop_edges(G))