Mercurial > repos > shellac > guppy_basecaller
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)) |
