1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294 |
- """Functional interface to graph methods and assorted utilities.
- """
- from collections import Counter
- from itertools import chain
- import networkx as nx
- from networkx.classes.graphviews import reverse_view, subgraph_view
- from networkx.utils import not_implemented_for, pairwise
- __all__ = [
- "nodes",
- "edges",
- "degree",
- "degree_histogram",
- "neighbors",
- "number_of_nodes",
- "number_of_edges",
- "density",
- "is_directed",
- "freeze",
- "is_frozen",
- "subgraph",
- "subgraph_view",
- "induced_subgraph",
- "reverse_view",
- "edge_subgraph",
- "restricted_view",
- "to_directed",
- "to_undirected",
- "add_star",
- "add_path",
- "add_cycle",
- "create_empty_copy",
- "set_node_attributes",
- "get_node_attributes",
- "set_edge_attributes",
- "get_edge_attributes",
- "all_neighbors",
- "non_neighbors",
- "non_edges",
- "common_neighbors",
- "is_weighted",
- "is_negatively_weighted",
- "is_empty",
- "selfloop_edges",
- "nodes_with_selfloops",
- "number_of_selfloops",
- "path_weight",
- "is_path",
- ]
- def nodes(G):
- """Returns an iterator over the graph nodes."""
- return G.nodes()
- def edges(G, nbunch=None):
- """Returns an edge view of edges incident to nodes in nbunch.
- Return all edges if nbunch is unspecified or nbunch=None.
- For digraphs, edges=out_edges
- """
- return G.edges(nbunch)
- def degree(G, nbunch=None, weight=None):
- """Returns a degree view of single node or of nbunch of nodes.
- If nbunch is omitted, then return degrees of *all* nodes.
- """
- return G.degree(nbunch, weight)
- def neighbors(G, n):
- """Returns a list of nodes connected to node n."""
- return G.neighbors(n)
- def number_of_nodes(G):
- """Returns the number of nodes in the graph."""
- return G.number_of_nodes()
- def number_of_edges(G):
- """Returns the number of edges in the graph."""
- return G.number_of_edges()
- def density(G):
- r"""Returns the density of a graph.
- The density for undirected graphs is
- .. math::
- d = \frac{2m}{n(n-1)},
- and for directed graphs is
- .. math::
- d = \frac{m}{n(n-1)},
- where `n` is the number of nodes and `m` is the number of edges in `G`.
- Notes
- -----
- The density is 0 for a graph without edges and 1 for a complete graph.
- The density of multigraphs can be higher than 1.
- Self loops are counted in the total number of edges so graphs with self
- loops can have density higher than 1.
- """
- n = number_of_nodes(G)
- m = number_of_edges(G)
- if m == 0 or n <= 1:
- return 0
- d = m / (n * (n - 1))
- if not G.is_directed():
- d *= 2
- return d
- def degree_histogram(G):
- """Returns a list of the frequency of each degree value.
- Parameters
- ----------
- G : Networkx graph
- A graph
- Returns
- -------
- hist : list
- A list of frequencies of degrees.
- The degree values are the index in the list.
- Notes
- -----
- Note: the bins are width one, hence len(list) can be large
- (Order(number_of_edges))
- """
- counts = Counter(d for n, d in G.degree())
- return [counts.get(i, 0) for i in range(max(counts) + 1)]
- def is_directed(G):
- """Return True if graph is directed."""
- return G.is_directed()
- def frozen(*args, **kwargs):
- """Dummy method for raising errors when trying to modify frozen graphs"""
- raise nx.NetworkXError("Frozen graph can't be modified")
- def freeze(G):
- """Modify graph to prevent further change by adding or removing
- nodes or edges.
- Node and edge data can still be modified.
- Parameters
- ----------
- G : graph
- A NetworkX graph
- Examples
- --------
- >>> G = nx.path_graph(4)
- >>> G = nx.freeze(G)
- >>> try:
- ... G.add_edge(4, 5)
- ... except nx.NetworkXError as err:
- ... print(str(err))
- Frozen graph can't be modified
- Notes
- -----
- To "unfreeze" a graph you must make a copy by creating a new graph object:
- >>> graph = nx.path_graph(4)
- >>> frozen_graph = nx.freeze(graph)
- >>> unfrozen_graph = nx.Graph(frozen_graph)
- >>> nx.is_frozen(unfrozen_graph)
- False
- See Also
- --------
- is_frozen
- """
- G.add_node = frozen
- G.add_nodes_from = frozen
- G.remove_node = frozen
- G.remove_nodes_from = frozen
- G.add_edge = frozen
- G.add_edges_from = frozen
- G.add_weighted_edges_from = frozen
- G.remove_edge = frozen
- G.remove_edges_from = frozen
- G.clear = frozen
- G.clear_edges = frozen
- G.frozen = True
- return G
- def is_frozen(G):
- """Returns True if graph is frozen.
- Parameters
- ----------
- G : graph
- A NetworkX graph
- See Also
- --------
- freeze
- """
- try:
- return G.frozen
- except AttributeError:
- return False
- def add_star(G_to_add_to, nodes_for_star, **attr):
- """Add a star to Graph G_to_add_to.
- The first node in `nodes_for_star` is the middle of the star.
- It is connected to all other nodes.
- Parameters
- ----------
- G_to_add_to : graph
- A NetworkX graph
- nodes_for_star : iterable container
- A container of nodes.
- attr : keyword arguments, optional (default= no attributes)
- Attributes to add to every edge in star.
- See Also
- --------
- add_path, add_cycle
- Examples
- --------
- >>> G = nx.Graph()
- >>> nx.add_star(G, [0, 1, 2, 3])
- >>> nx.add_star(G, [10, 11, 12], weight=2)
- """
- nlist = iter(nodes_for_star)
- try:
- v = next(nlist)
- except StopIteration:
- return
- G_to_add_to.add_node(v)
- edges = ((v, n) for n in nlist)
- G_to_add_to.add_edges_from(edges, **attr)
- def add_path(G_to_add_to, nodes_for_path, **attr):
- """Add a path to the Graph G_to_add_to.
- Parameters
- ----------
- G_to_add_to : graph
- A NetworkX graph
- nodes_for_path : iterable container
- A container of nodes. A path will be constructed from
- the nodes (in order) and added to the graph.
- attr : keyword arguments, optional (default= no attributes)
- Attributes to add to every edge in path.
- See Also
- --------
- add_star, add_cycle
- Examples
- --------
- >>> G = nx.Graph()
- >>> nx.add_path(G, [0, 1, 2, 3])
- >>> nx.add_path(G, [10, 11, 12], weight=7)
- """
- nlist = iter(nodes_for_path)
- try:
- first_node = next(nlist)
- except StopIteration:
- return
- G_to_add_to.add_node(first_node)
- G_to_add_to.add_edges_from(pairwise(chain((first_node,), nlist)), **attr)
- def add_cycle(G_to_add_to, nodes_for_cycle, **attr):
- """Add a cycle to the Graph G_to_add_to.
- Parameters
- ----------
- G_to_add_to : graph
- A NetworkX graph
- nodes_for_cycle: iterable container
- A container of nodes. A cycle will be constructed from
- the nodes (in order) and added to the graph.
- attr : keyword arguments, optional (default= no attributes)
- Attributes to add to every edge in cycle.
- See Also
- --------
- add_path, add_star
- Examples
- --------
- >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
- >>> nx.add_cycle(G, [0, 1, 2, 3])
- >>> nx.add_cycle(G, [10, 11, 12], weight=7)
- """
- nlist = iter(nodes_for_cycle)
- try:
- first_node = next(nlist)
- except StopIteration:
- return
- G_to_add_to.add_node(first_node)
- G_to_add_to.add_edges_from(
- pairwise(chain((first_node,), nlist), cyclic=True), **attr
- )
- def subgraph(G, nbunch):
- """Returns the subgraph induced on nodes in nbunch.
- Parameters
- ----------
- G : graph
- A NetworkX graph
- nbunch : list, iterable
- A container of nodes that will be iterated through once (thus
- it should be an iterator or be iterable). Each element of the
- container should be a valid node type: any hashable type except
- None. If nbunch is None, return all edges data in the graph.
- Nodes in nbunch that are not in the graph will be (quietly)
- ignored.
- Notes
- -----
- subgraph(G) calls G.subgraph()
- """
- return G.subgraph(nbunch)
- def induced_subgraph(G, nbunch):
- """Returns a SubGraph view of `G` showing only nodes in nbunch.
- The induced subgraph of a graph on a set of nodes N is the
- graph with nodes N and edges from G which have both ends in N.
- Parameters
- ----------
- G : NetworkX Graph
- nbunch : node, container of nodes or None (for all nodes)
- Returns
- -------
- subgraph : SubGraph View
- A read-only view of the subgraph in `G` induced by the nodes.
- Changes to the graph `G` will be reflected in the view.
- Notes
- -----
- To create a mutable subgraph with its own copies of nodes
- edges and attributes use `subgraph.copy()` or `Graph(subgraph)`
- For an inplace reduction of a graph to a subgraph you can remove nodes:
- `G.remove_nodes_from(n in G if n not in set(nbunch))`
- If you are going to compute subgraphs of your subgraphs you could
- end up with a chain of views that can be very slow once the chain
- has about 15 views in it. If they are all induced subgraphs, you
- can short-cut the chain by making them all subgraphs of the original
- graph. The graph class method `G.subgraph` does this when `G` is
- a subgraph. In contrast, this function allows you to choose to build
- chains or not, as you wish. The returned subgraph is a view on `G`.
- Examples
- --------
- >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc
- >>> H = nx.induced_subgraph(G, [0, 1, 3])
- >>> list(H.edges)
- [(0, 1)]
- >>> list(H.nodes)
- [0, 1, 3]
- """
- induced_nodes = nx.filters.show_nodes(G.nbunch_iter(nbunch))
- return nx.graphviews.subgraph_view(G, induced_nodes)
- def edge_subgraph(G, edges):
- """Returns a view of the subgraph induced by the specified edges.
- The induced subgraph contains each edge in `edges` and each
- node incident to any of those edges.
- Parameters
- ----------
- G : NetworkX Graph
- edges : iterable
- An iterable of edges. Edges not present in `G` are ignored.
- Returns
- -------
- subgraph : SubGraph View
- A read-only edge-induced subgraph of `G`.
- Changes to `G` are reflected in the view.
- Notes
- -----
- To create a mutable subgraph with its own copies of nodes
- edges and attributes use `subgraph.copy()` or `Graph(subgraph)`
- If you create a subgraph of a subgraph recursively you can end up
- with a chain of subgraphs that becomes very slow with about 15
- nested subgraph views. Luckily the edge_subgraph filter nests
- nicely so you can use the original graph as G in this function
- to avoid chains. We do not rule out chains programmatically so
- that odd cases like an `edge_subgraph` of a `restricted_view`
- can be created.
- Examples
- --------
- >>> G = nx.path_graph(5)
- >>> H = G.edge_subgraph([(0, 1), (3, 4)])
- >>> list(H.nodes)
- [0, 1, 3, 4]
- >>> list(H.edges)
- [(0, 1), (3, 4)]
- """
- nxf = nx.filters
- edges = set(edges)
- nodes = set()
- for e in edges:
- nodes.update(e[:2])
- induced_nodes = nxf.show_nodes(nodes)
- if G.is_multigraph():
- if G.is_directed():
- induced_edges = nxf.show_multidiedges(edges)
- else:
- induced_edges = nxf.show_multiedges(edges)
- else:
- if G.is_directed():
- induced_edges = nxf.show_diedges(edges)
- else:
- induced_edges = nxf.show_edges(edges)
- return nx.graphviews.subgraph_view(G, induced_nodes, induced_edges)
- def restricted_view(G, nodes, edges):
- """Returns a view of `G` with hidden nodes and edges.
- The resulting subgraph filters out node `nodes` and edges `edges`.
- Filtered out nodes also filter out any of their edges.
- Parameters
- ----------
- G : NetworkX Graph
- nodes : iterable
- An iterable of nodes. Nodes not present in `G` are ignored.
- edges : iterable
- An iterable of edges. Edges not present in `G` are ignored.
- Returns
- -------
- subgraph : SubGraph View
- A read-only restricted view of `G` filtering out nodes and edges.
- Changes to `G` are reflected in the view.
- Notes
- -----
- To create a mutable subgraph with its own copies of nodes
- edges and attributes use `subgraph.copy()` or `Graph(subgraph)`
- If you create a subgraph of a subgraph recursively you may end up
- with a chain of subgraph views. Such chains can get quite slow
- for lengths near 15. To avoid long chains, try to make your subgraph
- based on the original graph. We do not rule out chains programmatically
- so that odd cases like an `edge_subgraph` of a `restricted_view`
- can be created.
- Examples
- --------
- >>> G = nx.path_graph(5)
- >>> H = nx.restricted_view(G, [0], [(1, 2), (3, 4)])
- >>> list(H.nodes)
- [1, 2, 3, 4]
- >>> list(H.edges)
- [(2, 3)]
- """
- nxf = nx.filters
- hide_nodes = nxf.hide_nodes(nodes)
- if G.is_multigraph():
- if G.is_directed():
- hide_edges = nxf.hide_multidiedges(edges)
- else:
- hide_edges = nxf.hide_multiedges(edges)
- else:
- if G.is_directed():
- hide_edges = nxf.hide_diedges(edges)
- else:
- hide_edges = nxf.hide_edges(edges)
- return nx.graphviews.subgraph_view(G, hide_nodes, hide_edges)
- def to_directed(graph):
- """Returns a directed view of the graph `graph`.
- Identical to graph.to_directed(as_view=True)
- Note that graph.to_directed defaults to `as_view=False`
- while this function always provides a view.
- """
- return graph.to_directed(as_view=True)
- def to_undirected(graph):
- """Returns an undirected view of the graph `graph`.
- Identical to graph.to_undirected(as_view=True)
- Note that graph.to_undirected defaults to `as_view=False`
- while this function always provides a view.
- """
- return graph.to_undirected(as_view=True)
- def create_empty_copy(G, with_data=True):
- """Returns a copy of the graph G with all of the edges removed.
- Parameters
- ----------
- G : graph
- A NetworkX graph
- with_data : bool (default=True)
- Propagate Graph and Nodes data to the new graph.
- See Also
- --------
- empty_graph
- """
- H = G.__class__()
- H.add_nodes_from(G.nodes(data=with_data))
- if with_data:
- H.graph.update(G.graph)
- return H
- def set_node_attributes(G, values, name=None):
- """Sets node attributes from a given value or dictionary of values.
- .. Warning:: The call order of arguments `values` and `name`
- switched between v1.x & v2.x.
- Parameters
- ----------
- G : NetworkX Graph
- values : scalar value, dict-like
- What the node attribute should be set to. If `values` is
- not a dictionary, then it is treated as a single attribute value
- that is then applied to every node in `G`. This means that if
- you provide a mutable object, like a list, updates to that object
- will be reflected in the node attribute for every node.
- The attribute name will be `name`.
- If `values` is a dict or a dict of dict, it should be keyed
- by node to either an attribute value or a dict of attribute key/value
- pairs used to update the node's attributes.
- name : string (optional, default=None)
- Name of the node attribute to set if values is a scalar.
- Examples
- --------
- After computing some property of the nodes of a graph, you may want
- to assign a node attribute to store the value of that property for
- each node::
- >>> G = nx.path_graph(3)
- >>> bb = nx.betweenness_centrality(G)
- >>> isinstance(bb, dict)
- True
- >>> nx.set_node_attributes(G, bb, "betweenness")
- >>> G.nodes[1]["betweenness"]
- 1.0
- If you provide a list as the second argument, updates to the list
- will be reflected in the node attribute for each node::
- >>> G = nx.path_graph(3)
- >>> labels = []
- >>> nx.set_node_attributes(G, labels, "labels")
- >>> labels.append("foo")
- >>> G.nodes[0]["labels"]
- ['foo']
- >>> G.nodes[1]["labels"]
- ['foo']
- >>> G.nodes[2]["labels"]
- ['foo']
- If you provide a dictionary of dictionaries as the second argument,
- the outer dictionary is assumed to be keyed by node to an inner
- dictionary of node attributes for that node::
- >>> G = nx.path_graph(3)
- >>> attrs = {0: {"attr1": 20, "attr2": "nothing"}, 1: {"attr2": 3}}
- >>> nx.set_node_attributes(G, attrs)
- >>> G.nodes[0]["attr1"]
- 20
- >>> G.nodes[0]["attr2"]
- 'nothing'
- >>> G.nodes[1]["attr2"]
- 3
- >>> G.nodes[2]
- {}
- Note that if the dictionary contains nodes that are not in `G`, the
- values are silently ignored::
- >>> G = nx.Graph()
- >>> G.add_node(0)
- >>> nx.set_node_attributes(G, {0: "red", 1: "blue"}, name="color")
- >>> G.nodes[0]["color"]
- 'red'
- >>> 1 in G.nodes
- False
- """
- # Set node attributes based on type of `values`
- if name is not None: # `values` must not be a dict of dict
- try: # `values` is a dict
- for n, v in values.items():
- try:
- G.nodes[n][name] = values[n]
- except KeyError:
- pass
- except AttributeError: # `values` is a constant
- for n in G:
- G.nodes[n][name] = values
- else: # `values` must be dict of dict
- for n, d in values.items():
- try:
- G.nodes[n].update(d)
- except KeyError:
- pass
- def get_node_attributes(G, name):
- """Get node attributes from graph
- Parameters
- ----------
- G : NetworkX Graph
- name : string
- Attribute name
- Returns
- -------
- Dictionary of attributes keyed by node.
- Examples
- --------
- >>> G = nx.Graph()
- >>> G.add_nodes_from([1, 2, 3], color="red")
- >>> color = nx.get_node_attributes(G, "color")
- >>> color[1]
- 'red'
- """
- return {n: d[name] for n, d in G.nodes.items() if name in d}
- def set_edge_attributes(G, values, name=None):
- """Sets edge attributes from a given value or dictionary of values.
- .. Warning:: The call order of arguments `values` and `name`
- switched between v1.x & v2.x.
- Parameters
- ----------
- G : NetworkX Graph
- values : scalar value, dict-like
- What the edge attribute should be set to. If `values` is
- not a dictionary, then it is treated as a single attribute value
- that is then applied to every edge in `G`. This means that if
- you provide a mutable object, like a list, updates to that object
- will be reflected in the edge attribute for each edge. The attribute
- name will be `name`.
- If `values` is a dict or a dict of dict, it should be keyed
- by edge tuple to either an attribute value or a dict of attribute
- key/value pairs used to update the edge's attributes.
- For multigraphs, the edge tuples must be of the form ``(u, v, key)``,
- where `u` and `v` are nodes and `key` is the edge key.
- For non-multigraphs, the keys must be tuples of the form ``(u, v)``.
- name : string (optional, default=None)
- Name of the edge attribute to set if values is a scalar.
- Examples
- --------
- After computing some property of the edges of a graph, you may want
- to assign a edge attribute to store the value of that property for
- each edge::
- >>> G = nx.path_graph(3)
- >>> bb = nx.edge_betweenness_centrality(G, normalized=False)
- >>> nx.set_edge_attributes(G, bb, "betweenness")
- >>> G.edges[1, 2]["betweenness"]
- 2.0
- If you provide a list as the second argument, updates to the list
- will be reflected in the edge attribute for each edge::
- >>> labels = []
- >>> nx.set_edge_attributes(G, labels, "labels")
- >>> labels.append("foo")
- >>> G.edges[0, 1]["labels"]
- ['foo']
- >>> G.edges[1, 2]["labels"]
- ['foo']
- If you provide a dictionary of dictionaries as the second argument,
- the entire dictionary will be used to update edge attributes::
- >>> G = nx.path_graph(3)
- >>> attrs = {(0, 1): {"attr1": 20, "attr2": "nothing"}, (1, 2): {"attr2": 3}}
- >>> nx.set_edge_attributes(G, attrs)
- >>> G[0][1]["attr1"]
- 20
- >>> G[0][1]["attr2"]
- 'nothing'
- >>> G[1][2]["attr2"]
- 3
- The attributes of one Graph can be used to set those of another.
- >>> H = nx.path_graph(3)
- >>> nx.set_edge_attributes(H, G.edges)
- Note that if the dict contains edges that are not in `G`, they are
- silently ignored::
- >>> G = nx.Graph([(0, 1)])
- >>> nx.set_edge_attributes(G, {(1, 2): {"weight": 2.0}})
- >>> (1, 2) in G.edges()
- False
- For multigraphs, the `values` dict is expected to be keyed by 3-tuples
- including the edge key::
- >>> MG = nx.MultiGraph()
- >>> edges = [(0, 1), (0, 1)]
- >>> MG.add_edges_from(edges) # Returns list of edge keys
- [0, 1]
- >>> attributes = {(0, 1, 0): {"cost": 21}, (0, 1, 1): {"cost": 7}}
- >>> nx.set_edge_attributes(MG, attributes)
- >>> MG[0][1][0]["cost"]
- 21
- >>> MG[0][1][1]["cost"]
- 7
- If MultiGraph attributes are desired for a Graph, you must convert the 3-tuple
- multiedge to a 2-tuple edge and the last multiedge's attribute value will
- overwrite the previous values. Continuing from the previous case we get::
- >>> H = nx.path_graph([0, 1, 2])
- >>> nx.set_edge_attributes(H, {(u, v): ed for u, v, ed in MG.edges.data()})
- >>> nx.get_edge_attributes(H, "cost")
- {(0, 1): 7}
- """
- if name is not None:
- # `values` does not contain attribute names
- try:
- # if `values` is a dict using `.items()` => {edge: value}
- if G.is_multigraph():
- for (u, v, key), value in values.items():
- try:
- G[u][v][key][name] = value
- except KeyError:
- pass
- else:
- for (u, v), value in values.items():
- try:
- G[u][v][name] = value
- except KeyError:
- pass
- except AttributeError:
- # treat `values` as a constant
- for u, v, data in G.edges(data=True):
- data[name] = values
- else:
- # `values` consists of doct-of-dict {edge: {attr: value}} shape
- if G.is_multigraph():
- for (u, v, key), d in values.items():
- try:
- G[u][v][key].update(d)
- except KeyError:
- pass
- else:
- for (u, v), d in values.items():
- try:
- G[u][v].update(d)
- except KeyError:
- pass
- def get_edge_attributes(G, name):
- """Get edge attributes from graph
- Parameters
- ----------
- G : NetworkX Graph
- name : string
- Attribute name
- Returns
- -------
- Dictionary of attributes keyed by edge. For (di)graphs, the keys are
- 2-tuples of the form: (u, v). For multi(di)graphs, the keys are 3-tuples of
- the form: (u, v, key).
- Examples
- --------
- >>> G = nx.Graph()
- >>> nx.add_path(G, [1, 2, 3], color="red")
- >>> color = nx.get_edge_attributes(G, "color")
- >>> color[(1, 2)]
- 'red'
- """
- if G.is_multigraph():
- edges = G.edges(keys=True, data=True)
- else:
- edges = G.edges(data=True)
- return {x[:-1]: x[-1][name] for x in edges if name in x[-1]}
- def all_neighbors(graph, node):
- """Returns all of the neighbors of a node in the graph.
- If the graph is directed returns predecessors as well as successors.
- Parameters
- ----------
- graph : NetworkX graph
- Graph to find neighbors.
- node : node
- The node whose neighbors will be returned.
- Returns
- -------
- neighbors : iterator
- Iterator of neighbors
- """
- if graph.is_directed():
- values = chain(graph.predecessors(node), graph.successors(node))
- else:
- values = graph.neighbors(node)
- return values
- def non_neighbors(graph, node):
- """Returns the non-neighbors of the node in the graph.
- Parameters
- ----------
- graph : NetworkX graph
- Graph to find neighbors.
- node : node
- The node whose neighbors will be returned.
- Returns
- -------
- non_neighbors : iterator
- Iterator of nodes in the graph that are not neighbors of the node.
- """
- nbors = set(neighbors(graph, node)) | {node}
- return (nnode for nnode in graph if nnode not in nbors)
- def non_edges(graph):
- """Returns the non-existent edges in the graph.
- Parameters
- ----------
- graph : NetworkX graph.
- Graph to find non-existent edges.
- Returns
- -------
- non_edges : iterator
- Iterator of edges that are not in the graph.
- """
- if graph.is_directed():
- for u in graph:
- for v in non_neighbors(graph, u):
- yield (u, v)
- else:
- nodes = set(graph)
- while nodes:
- u = nodes.pop()
- for v in nodes - set(graph[u]):
- yield (u, v)
- @not_implemented_for("directed")
- def common_neighbors(G, u, v):
- """Returns the common neighbors of two nodes in a graph.
- Parameters
- ----------
- G : graph
- A NetworkX undirected graph.
- u, v : nodes
- Nodes in the graph.
- Returns
- -------
- cnbors : iterator
- Iterator of common neighbors of u and v in the graph.
- Raises
- ------
- NetworkXError
- If u or v is not a node in the graph.
- Examples
- --------
- >>> G = nx.complete_graph(5)
- >>> sorted(nx.common_neighbors(G, 0, 1))
- [2, 3, 4]
- """
- if u not in G:
- raise nx.NetworkXError("u is not in the graph.")
- if v not in G:
- raise nx.NetworkXError("v is not in the graph.")
- # Return a generator explicitly instead of yielding so that the above
- # checks are executed eagerly.
- return (w for w in G[u] if w in G[v] and w not in (u, v))
- def is_weighted(G, edge=None, weight="weight"):
- """Returns True if `G` has weighted edges.
- Parameters
- ----------
- G : graph
- A NetworkX graph.
- edge : tuple, optional
- A 2-tuple specifying the only edge in `G` that will be tested. If
- None, then every edge in `G` is tested.
- weight: string, optional
- The attribute name used to query for edge weights.
- Returns
- -------
- bool
- A boolean signifying if `G`, or the specified edge, is weighted.
- Raises
- ------
- NetworkXError
- If the specified edge does not exist.
- Examples
- --------
- >>> G = nx.path_graph(4)
- >>> nx.is_weighted(G)
- False
- >>> nx.is_weighted(G, (2, 3))
- False
- >>> G = nx.DiGraph()
- >>> G.add_edge(1, 2, weight=1)
- >>> nx.is_weighted(G)
- True
- """
- if edge is not None:
- data = G.get_edge_data(*edge)
- if data is None:
- msg = f"Edge {edge!r} does not exist."
- raise nx.NetworkXError(msg)
- return weight in data
- if is_empty(G):
- # Special handling required since: all([]) == True
- return False
- return all(weight in data for u, v, data in G.edges(data=True))
- def is_negatively_weighted(G, edge=None, weight="weight"):
- """Returns True if `G` has negatively weighted edges.
- Parameters
- ----------
- G : graph
- A NetworkX graph.
- edge : tuple, optional
- A 2-tuple specifying the only edge in `G` that will be tested. If
- None, then every edge in `G` is tested.
- weight: string, optional
- The attribute name used to query for edge weights.
- Returns
- -------
- bool
- A boolean signifying if `G`, or the specified edge, is negatively
- weighted.
- Raises
- ------
- NetworkXError
- If the specified edge does not exist.
- Examples
- --------
- >>> G = nx.Graph()
- >>> G.add_edges_from([(1, 3), (2, 4), (2, 6)])
- >>> G.add_edge(1, 2, weight=4)
- >>> nx.is_negatively_weighted(G, (1, 2))
- False
- >>> G[2][4]["weight"] = -2
- >>> nx.is_negatively_weighted(G)
- True
- >>> G = nx.DiGraph()
- >>> edges = [("0", "3", 3), ("0", "1", -5), ("1", "0", -2)]
- >>> G.add_weighted_edges_from(edges)
- >>> nx.is_negatively_weighted(G)
- True
- """
- if edge is not None:
- data = G.get_edge_data(*edge)
- if data is None:
- msg = f"Edge {edge!r} does not exist."
- raise nx.NetworkXError(msg)
- return weight in data and data[weight] < 0
- return any(weight in data and data[weight] < 0 for u, v, data in G.edges(data=True))
- def is_empty(G):
- """Returns True if `G` has no edges.
- Parameters
- ----------
- G : graph
- A NetworkX graph.
- Returns
- -------
- bool
- True if `G` has no edges, and False otherwise.
- Notes
- -----
- An empty graph can have nodes but not edges. The empty graph with zero
- nodes is known as the null graph. This is an $O(n)$ operation where n
- is the number of nodes in the graph.
- """
- return not any(G.adj.values())
- def nodes_with_selfloops(G):
- """Returns an iterator over nodes with self loops.
- A node with a self loop has an edge with both ends adjacent
- to that node.
- Returns
- -------
- nodelist : iterator
- A iterator over nodes with self loops.
- See Also
- --------
- selfloop_edges, number_of_selfloops
- Examples
- --------
- >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
- >>> G.add_edge(1, 1)
- >>> G.add_edge(1, 2)
- >>> list(nx.nodes_with_selfloops(G))
- [1]
- """
- return (n for n, nbrs in G.adj.items() if n in nbrs)
- def selfloop_edges(G, data=False, keys=False, default=None):
- """Returns an iterator over selfloop edges.
- A selfloop edge has the same node at both ends.
- Parameters
- ----------
- G : graph
- A NetworkX graph.
- data : string or bool, optional (default=False)
- Return selfloop edges as two tuples (u, v) (data=False)
- or three-tuples (u, v, datadict) (data=True)
- or three-tuples (u, v, datavalue) (data='attrname')
- keys : bool, optional (default=False)
- If True, return edge keys with each edge.
- default : value, optional (default=None)
- Value used for edges that don't have the requested attribute.
- Only relevant if data is not True or False.
- Returns
- -------
- edgeiter : iterator over edge tuples
- An iterator over all selfloop edges.
- See Also
- --------
- nodes_with_selfloops, number_of_selfloops
- Examples
- --------
- >>> G = nx.MultiGraph() # or Graph, DiGraph, MultiDiGraph, etc
- >>> ekey = G.add_edge(1, 1)
- >>> ekey = G.add_edge(1, 2)
- >>> list(nx.selfloop_edges(G))
- [(1, 1)]
- >>> list(nx.selfloop_edges(G, data=True))
- [(1, 1, {})]
- >>> list(nx.selfloop_edges(G, keys=True))
- [(1, 1, 0)]
- >>> list(nx.selfloop_edges(G, keys=True, data=True))
- [(1, 1, 0, {})]
- """
- if data is True:
- if G.is_multigraph():
- if keys is True:
- return (
- (n, n, k, d)
- for n, nbrs in G.adj.items()
- if n in nbrs
- for k, d in nbrs[n].items()
- )
- else:
- return (
- (n, n, d)
- for n, nbrs in G.adj.items()
- if n in nbrs
- for d in nbrs[n].values()
- )
- else:
- return ((n, n, nbrs[n]) for n, nbrs in G.adj.items() if n in nbrs)
- elif data is not False:
- if G.is_multigraph():
- if keys is True:
- return (
- (n, n, k, d.get(data, default))
- for n, nbrs in G.adj.items()
- if n in nbrs
- for k, d in nbrs[n].items()
- )
- else:
- return (
- (n, n, d.get(data, default))
- for n, nbrs in G.adj.items()
- if n in nbrs
- for d in nbrs[n].values()
- )
- else:
- return (
- (n, n, nbrs[n].get(data, default))
- for n, nbrs in G.adj.items()
- if n in nbrs
- )
- else:
- if G.is_multigraph():
- if keys is True:
- return (
- (n, n, k) for n, nbrs in G.adj.items() if n in nbrs for k in nbrs[n]
- )
- else:
- return (
- (n, n)
- for n, nbrs in G.adj.items()
- if n in nbrs
- for i in range(len(nbrs[n])) # for easy edge removal (#4068)
- )
- else:
- return ((n, n) for n, nbrs in G.adj.items() if n in nbrs)
- def number_of_selfloops(G):
- """Returns the number of selfloop edges.
- A selfloop edge has the same node at both ends.
- Returns
- -------
- nloops : int
- The number of selfloops.
- See Also
- --------
- nodes_with_selfloops, selfloop_edges
- Examples
- --------
- >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
- >>> G.add_edge(1, 1)
- >>> G.add_edge(1, 2)
- >>> nx.number_of_selfloops(G)
- 1
- """
- return sum(1 for _ in nx.selfloop_edges(G))
- def is_path(G, path):
- """Returns whether or not the specified path exists.
- For it to return True, every node on the path must exist and
- each consecutive pair must be connected via one or more edges.
- Parameters
- ----------
- G : graph
- A NetworkX graph.
- path : list
- A list of nodes which defines the path to traverse
- Returns
- -------
- bool
- True if `path` is a valid path in `G`
- """
- return all((node in G and nbr in G[node]) for node, nbr in nx.utils.pairwise(path))
- def path_weight(G, path, weight):
- """Returns total cost associated with specified path and weight
- Parameters
- ----------
- G : graph
- A NetworkX graph.
- path: list
- A list of node labels which defines the path to traverse
- weight: string
- A string indicating which edge attribute to use for path cost
- Returns
- -------
- cost: int or float
- An integer or a float representing the total cost with respect to the
- specified weight of the specified path
- Raises
- ------
- NetworkXNoPath
- If the specified edge does not exist.
- """
- multigraph = G.is_multigraph()
- cost = 0
- if not nx.is_path(G, path):
- raise nx.NetworkXNoPath("path does not exist")
- for node, nbr in nx.utils.pairwise(path):
- if multigraph:
- cost += min(v[weight] for v in G[node][nbr].values())
- else:
- cost += G[node][nbr][weight]
- return cost
|