function.py 35 KB

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