Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/networkx/classes/graph.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/networkx/classes/graph.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1890 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg <hagberg@lanl.gov> -# Dan Schult <dschult@colgate.edu> -# Pieter Swart <swart@lanl.gov> -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov), -# Pieter Swart (swart@lanl.gov), -# Dan Schult(dschult@colgate.edu) -"""Base class for undirected graphs. - -The Graph class allows any hashable object as a node -and can associate key/value attribute pairs with each undirected edge. - -Self-loops are allowed but multiple edges are not (see MultiGraph). - -For directed graphs see DiGraph and MultiDiGraph. -""" -import warnings -from copy import deepcopy -from collections.abc import Mapping - -import networkx as nx -from networkx.classes.coreviews import AtlasView, AdjacencyView -from networkx.classes.reportviews import NodeView, EdgeView, DegreeView -from networkx.exception import NetworkXError -import networkx.convert as convert -from networkx.utils import pairwise - - -class Graph(object): - """ - Base class for undirected graphs. - - A Graph stores nodes and edges with optional data, or attributes. - - Graphs hold undirected edges. Self loops are allowed but multiple - (parallel) edges are not. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, NumPy matrix - or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - DiGraph - MultiGraph - MultiDiGraph - OrderedGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.Graph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> G.add_edge(1, 2) - - a list of edges, - - >>> G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. There are no errors when adding - nodes or edges that already exist. - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.Graph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time='5pm') - >>> G.add_nodes_from([3], time='2pm') - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]['room'] = 714 # node must exist already to use G.nodes - >>> del G.nodes[1]['room'] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> G.add_edge(1, 2, weight=4.7 ) - >>> G.add_edges_from([(3, 4), (4, 5)], color='red') - >>> G.add_edges_from([(1, 2, {'color': 'blue'}), (2, 3, {'weight': 8})]) - >>> G[1][2]['weight'] = 4.7 - >>> G.edges[1, 2]['weight'] = 4 - - Warning: we protect the graph data structure by making `G.edges` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, eattr in nbrsdict.items(): - ... if 'weight' in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, weight in G.edges.data('weight'): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using object-attributes and methods. - Reporting typically provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The Graph class uses a dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge data keyed by neighbor. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these three dicts can be replaced in a subclass by a user defined - dict-like object. In general, the dict-like features should be - maintained but extra features can be added. To replace one of the - dicts create a new graph class by changing the class(!) variable - holding the factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds edge data keyed by neighbor. - It should require no arguments and return a dict-like object - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherit without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - Examples - -------- - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {'weight': 1} - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - - Please see :mod:`~networkx.classes.ordered` for more examples of - creating graph subclasses by overwriting the base class `dict` with - a dictionary-like object. - """ - node_dict_factory = dict - node_attr_dict_factory = dict - adjlist_outer_dict_factory = dict - adjlist_inner_dict_factory = dict - edge_attr_dict_factory = dict - graph_attr_dict_factory = dict - - def to_directed_class(self): - """Returns the class to use for empty directed copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return nx.DiGraph - - def to_undirected_class(self): - """Returns the class to use for empty undirected copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return Graph - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a NumPy matrix - or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name='my graph') - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.graph_attr_dict_factory = self.graph_attr_dict_factory - self.node_dict_factory = self.node_dict_factory - self.node_attr_dict_factory = self.node_attr_dict_factory - self.adjlist_outer_dict_factory = self.adjlist_outer_dict_factory - self.adjlist_inner_dict_factory = self.adjlist_inner_dict_factory - self.edge_attr_dict_factory = self.edge_attr_dict_factory - - self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes - self._node = self.node_dict_factory() # empty node attribute dict - self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict - # attempt to load graph with data - if incoming_graph_data is not None: - convert.to_networkx_graph(incoming_graph_data, create_using=self) - # load graph attributes (must be after convert) - self.graph.update(attr) - - @property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return AdjacencyView(self._adj) - - @property - def name(self): - """String identifier of the graph. - - This graph attribute appears in the attribute dict G.graph - keyed by the string `"name"`. as well as an attribute (technically - a property) `G.name`. This is entirely user controlled. - """ - return self.graph.get('name', '') - - @name.setter - def name(self, s): - self.graph['name'] = s - - def __str__(self): - """Returns the graph name. - - Returns - ------- - name : string - The name of the graph. - - Examples - -------- - >>> G = nx.Graph(name='foo') - >>> str(G) - 'foo' - """ - return self.name - - def __iter__(self): - """Iterate over the nodes. Use: 'for n in G'. - - Returns - ------- - niter : iterator - An iterator over all nodes in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [n for n in G] - [0, 1, 2, 3] - >>> list(G) - [0, 1, 2, 3] - """ - return iter(self._node) - - def __contains__(self, n): - """Returns True if n is a node, False otherwise. Use: 'n in G'. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> 1 in G - True - """ - try: - return n in self._node - except TypeError: - return False - - def __len__(self): - """Returns the number of nodes in the graph. Use: 'len(G)'. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - number_of_nodes, order which are identical - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> len(G) - 4 - - """ - return len(self._node) - - def __getitem__(self, n): - """Returns a dict of neighbors of node n. Use: 'G[n]'. - - Parameters - ---------- - n : node - A node in the graph. - - Returns - ------- - adj_dict : dictionary - The adjacency dictionary for nodes connected to n. - - Notes - ----- - G[n] is the same as G.adj[n] and similar to G.neighbors(n) - (which is an iterator over G.adj[n]) - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G[0] - AtlasView({1: {}}) - """ - return self.adj[n] - - def add_node(self, node_for_adding, **attr): - """Add a single node `node_for_adding` and update node attributes. - - Parameters - ---------- - node_for_adding : node - A node can be any hashable Python object except None. - attr : keyword arguments, optional - Set or change node attributes using key=value. - - See Also - -------- - add_nodes_from - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_node(1) - >>> G.add_node('Hello') - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_node(K3) - >>> G.number_of_nodes() - 3 - - Use keywords set/change node attributes: - - >>> G.add_node(1, size=10) - >>> G.add_node(3, weight=0.4, UTM=('13S', 382871, 3972649)) - - Notes - ----- - A hashable object is one that can be used as a key in a Python - dictionary. This includes strings, numbers, tuples of strings - and numbers, etc. - - On many platforms hashable items also include mutables such as - NetworkX Graphs, though one should be careful that the hash - doesn't change on mutables. - """ - if node_for_adding not in self._node: - self._adj[node_for_adding] = self.adjlist_inner_dict_factory() - attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: # update attr even if node already exists - self._node[node_for_adding].update(attr) - - def add_nodes_from(self, nodes_for_adding, **attr): - """Add multiple nodes. - - Parameters - ---------- - nodes_for_adding : iterable container - A container of nodes (list, dict, set, etc.). - OR - A container of (node, attribute dict) tuples. - Node attributes are updated using the attribute dict. - attr : keyword arguments, optional (default= no attributes) - Update attributes for all nodes in nodes. - Node attributes specified in nodes as a tuple take - precedence over attributes specified via keyword arguments. - - See Also - -------- - add_node - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_nodes_from('Hello') - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_nodes_from(K3) - >>> sorted(G.nodes(), key=str) - [0, 1, 2, 'H', 'e', 'l', 'o'] - - Use keywords to update specific node attributes for every node. - - >>> G.add_nodes_from([1, 2], size=10) - >>> G.add_nodes_from([3, 4], weight=0.4) - - Use (node, attrdict) tuples to update attributes for specific nodes. - - >>> G.add_nodes_from([(1, dict(size=11)), (2, {'color':'blue'})]) - >>> G.nodes[1]['size'] - 11 - >>> H = nx.Graph() - >>> H.add_nodes_from(G.nodes(data=True)) - >>> H.nodes[1]['size'] - 11 - - """ - for n in nodes_for_adding: - # keep all this inside try/except because - # CPython throws TypeError on n not in self._node, - # while pre-2.7.5 ironpython throws on self._adj[n] - try: - if n not in self._node: - self._adj[n] = self.adjlist_inner_dict_factory() - attr_dict = self._node[n] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: - self._node[n].update(attr) - except TypeError: - nn, ndict = n - if nn not in self._node: - self._adj[nn] = self.adjlist_inner_dict_factory() - newdict = attr.copy() - newdict.update(ndict) - attr_dict = self._node[nn] = self.node_attr_dict_factory() - attr_dict.update(newdict) - else: - olddict = self._node[nn] - olddict.update(attr) - olddict.update(ndict) - - def remove_node(self, n): - """Remove node n. - - Removes the node n and all adjacent edges. - Attempting to remove a non-existent node will raise an exception. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------- - NetworkXError - If n is not in the graph. - - See Also - -------- - remove_nodes_from - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> list(G.edges) - [(0, 1), (1, 2)] - >>> G.remove_node(1) - >>> list(G.edges) - [] - - """ - adj = self._adj - try: - nbrs = list(adj[n]) # list handles self-loops (allows mutation) - del self._node[n] - except KeyError: # NetworkXError if n not in self - raise NetworkXError("The node %s is not in the graph." % (n,)) - for u in nbrs: - del adj[u][n] # remove all edges n-u in graph - del adj[n] # now remove node - - def remove_nodes_from(self, nodes): - """Remove multiple nodes. - - Parameters - ---------- - nodes : iterable container - A container of nodes (list, dict, set, etc.). If a node - in the container is not in the graph it is silently - ignored. - - See Also - -------- - remove_node - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = list(G.nodes) - >>> e - [0, 1, 2] - >>> G.remove_nodes_from(e) - >>> list(G.nodes) - [] - - """ - adj = self._adj - for n in nodes: - try: - del self._node[n] - for u in list(adj[n]): # list handles self-loops - del adj[u][n] # (allows mutation of dict in loop) - del adj[n] - except KeyError: - pass - - @property - def nodes(self): - """A NodeView of the Graph as G.nodes or G.nodes(). - - Can be used as `G.nodes` for data lookup and for set-like operations. - Can also be used as `G.nodes(data='color', default=None)` to return a - NodeDataView which reports specific node data but no set operations. - It presents a dict-like interface as well with `G.nodes.items()` - iterating over `(node, nodedata)` 2-tuples and `G.nodes[3]['foo']` - providing the value of the `foo` attribute for node `3`. In addition, - a view `G.nodes.data('foo')` provides a dict-like interface to the - `foo` attribute of each node. `G.nodes.data('foo', default=1)` - provides a default for nodes that do not have attribute `foo`. - - Parameters - ---------- - data : string or bool, optional (default=False) - The node attribute returned in 2-tuple (n, ddict[data]). - If True, return entire node attribute dict as (n, ddict). - If False, return just the nodes n. - - default : value, optional (default=None) - Value used for nodes that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - NodeView - Allows set-like operations over the nodes as well as node - attribute dict lookup and calling to get a NodeDataView. - A NodeDataView iterates over `(n, data)` and has no set operations. - A NodeView iterates over `n` and includes set operations. - - When called, if data is False, an iterator over nodes. - Otherwise an iterator of 2-tuples (node, attribute value) - where the attribute is specified in `data`. - If data is True then the attribute becomes the - entire data dictionary. - - Notes - ----- - If your node data is not needed, it is simpler and equivalent - to use the expression ``for n in G``, or ``list(G)``. - - Examples - -------- - There are two simple ways of getting a list of all nodes in the graph: - - >>> G = nx.path_graph(3) - >>> list(G.nodes) - [0, 1, 2] - >>> list(G) - [0, 1, 2] - - To get the node data along with the nodes: - - >>> G.add_node(1, time='5pm') - >>> G.nodes[0]['foo'] = 'bar' - >>> list(G.nodes(data=True)) - [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] - >>> list(G.nodes.data()) - [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] - - >>> list(G.nodes(data='foo')) - [(0, 'bar'), (1, None), (2, None)] - >>> list(G.nodes.data('foo')) - [(0, 'bar'), (1, None), (2, None)] - - >>> list(G.nodes(data='time')) - [(0, None), (1, '5pm'), (2, None)] - >>> list(G.nodes.data('time')) - [(0, None), (1, '5pm'), (2, None)] - - >>> list(G.nodes(data='time', default='Not Available')) - [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] - >>> list(G.nodes.data('time', default='Not Available')) - [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] - - If some of your nodes have an attribute and the rest are assumed - to have a default attribute value you can create a dictionary - from node/attribute pairs using the `default` keyword argument - to guarantee the value is never None:: - - >>> G = nx.Graph() - >>> G.add_node(0) - >>> G.add_node(1, weight=2) - >>> G.add_node(2, weight=3) - >>> dict(G.nodes(data='weight', default=1)) - {0: 1, 1: 2, 2: 3} - - """ - nodes = NodeView(self) - # Lazy View creation: overload the (class) property on the instance - # Then future G.nodes use the existing View - # setattr doesn't work because attribute already exists - self.__dict__['nodes'] = nodes - return nodes - - def number_of_nodes(self): - """Returns the number of nodes in the graph. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - order, __len__ which are identical - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.number_of_nodes() - 3 - """ - return len(self._node) - - def order(self): - """Returns the number of nodes in the graph. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - number_of_nodes, __len__ which are identical - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.order() - 3 - """ - return len(self._node) - - def has_node(self, n): - """Returns True if the graph contains the node n. - - Identical to `n in G` - - Parameters - ---------- - n : node - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.has_node(0) - True - - It is more readable and simpler to use - - >>> 0 in G - True - - """ - try: - return n in self._node - except TypeError: - return False - - def add_edge(self, u_of_edge, v_of_edge, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - Adding an edge that already exists updates the edge data. - - Many NetworkX algorithms designed for weighted graphs use - an edge attribute (by default `weight`) to hold a numerical value. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = (1, 2) - >>> G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - >>> G.add_edges_from([(1, 2)]) # add edges from iterable container - - Associate data to edges using keywords: - - >>> G.add_edge(1, 2, weight=3) - >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> G.add_edge(1, 2) - >>> G[1][2].update({0: 5}) - >>> G.edges[1, 2].update({0: 5}) - """ - u, v = u_of_edge, v_of_edge - # add nodes - if u not in self._node: - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._node: - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - # add the edge - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - self._adj[u][v] = datadict - self._adj[v][u] = datadict - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges must be given as as 2-tuples (u, v) or - 3-tuples (u, v, d) where d is a dictionary containing edge data. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label='WN2898') - """ - for e in ebunch_to_add: - ne = len(e) - if ne == 3: - u, v, dd = e - elif ne == 2: - u, v = e - dd = {} # doesn't need edge_attr_dict_factory - else: - raise NetworkXError( - "Edge tuple %s must be a 2-tuple or 3-tuple." % (e,)) - if u not in self._node: - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._node: - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - datadict.update(dd) - self._adj[u][v] = datadict - self._adj[v][u] = datadict - - def add_weighted_edges_from(self, ebunch_to_add, weight='weight', **attr): - """Add weighted edges in `ebunch_to_add` with specified weight attr - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the list or container will be added - to the graph. The edges must be given as 3-tuples (u, v, w) - where w is a number. - weight : string, optional (default= 'weight') - The attribute name for the edge weights to be added. - attr : keyword arguments, optional (default= no attributes) - Edge attributes to add/update for all edges. - - See Also - -------- - add_edge : add a single edge - add_edges_from : add multiple edges - - Notes - ----- - Adding the same edge twice for Graph/DiGraph simply updates - the edge data. For MultiGraph/MultiDiGraph, duplicate edges - are stored. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_weighted_edges_from([(0, 1, 3.0), (1, 2, 7.5)]) - """ - self.add_edges_from(((u, v, {weight: d}) for u, v, d in ebunch_to_add), - **attr) - - def remove_edge(self, u, v): - """Remove the edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove the edge between nodes u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, etc - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - >>> e = (2, 3, {'weight':7}) # an edge with attribute data - >>> G.remove_edge(*e[:2]) # select first part of edge tuple - """ - try: - del self._adj[u][v] - if u != v: # self-loop needs only one entry removed - del self._adj[v][u] - except KeyError: - raise NetworkXError("The edge %s-%s is not in the graph" % (u, v)) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) edge between u and v. - - 3-tuples (u, v, k) where k is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch=[(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - """ - adj = self._adj - for e in ebunch: - u, v = e[:2] # ignore edge data if present - if u in adj and v in adj[u]: - del adj[u][v] - if u != v: # self loop needs only one entry removed - del adj[v][u] - - def update(self, edges=None, nodes=None): - """Update the graph using nodes/edges/graphs as input. - - Like dict.update, this method takes a graph as input, adding the - graph's nodes and edges to this graph. It can also take two inputs: - edges and nodes. Finally it can take either edges or nodes. - To specify only nodes the keyword `nodes` must be used. - - The collections of edges and nodes are treated similarly to - the add_edges_from/add_nodes_from methods. When iterated, they - should yield 2-tuples (u, v) or 3-tuples (u, v, datadict). - - Parameters - ---------- - edges : Graph object, collection of edges, or None - The first parameter can be a graph or some edges. If it has - attributes `nodes` and `edges`, then it is taken to be a - Graph-like object and those attributes are used as collections - of nodes and edges to be added to the graph. - If the first parameter does not have those attributes, it is - treated as a collection of edges and added to the graph. - If the first argument is None, no edges are added. - nodes : collection of nodes, or None - The second parameter is treated as a collection of nodes - to be added to the graph unless it is None. - If `edges is None` and `nodes is None` an exception is raised. - If the first parameter is a Graph, then `nodes` is ignored. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> G.update(nx.complete_graph(range(4,10))) - >>> from itertools import combinations - >>> edges = ((u, v, {'power': u * v}) - ... for u, v in combinations(range(10, 20), 2) - ... if u * v < 225) - >>> nodes = [1000] # for singleton, use a container - >>> G.update(edges, nodes) - - Notes - ----- - It you want to update the graph using an adjacency structure - it is straightforward to obtain the edges/nodes from adjacency. - The following examples provide common cases, your adjacency may - be slightly different and require tweaks of these examples. - - >>> # dict-of-set/list/tuple - >>> adj = {1: {2, 3}, 2: {1, 3}, 3: {1, 2}} - >>> e = [(u, v) for u, nbrs in adj.items() for v in nbrs] - >>> G.update(edges=e, nodes=adj) - - >>> DG = nx.DiGraph() - >>> # dict-of-dict-of-attribute - >>> adj = {1: {2: 1.3, 3: 0.7}, 2: {1: 1.4}, 3: {1: 0.7}} - >>> e = [(u, v, {'weight': d}) for u, nbrs in adj.items() - ... for v, d in nbrs.items()] - >>> DG.update(edges=e, nodes=adj) - - >>> # dict-of-dict-of-dict - >>> adj = {1: {2: {'weight': 1.3}, 3: {'color': 0.7, 'weight':1.2}}} - >>> e = [(u, v, {'weight': d}) for u, nbrs in adj.items() - ... for v, d in nbrs.items()] - >>> DG.update(edges=e, nodes=adj) - - >>> # predecessor adjacency (dict-of-set) - >>> pred = {1: {2, 3}, 2: {3}, 3: {3}} - >>> e = [(v, u) for u, nbrs in pred.items() for v in nbrs] - - >>> # MultiGraph dict-of-dict-of-dict-of-attribute - >>> MDG = nx.MultiDiGraph() - >>> adj = {1: {2: {0: {'weight': 1.3}, 1: {'weight': 1.2}}}, - ... 3: {2: {0: {'weight': 0.7}}}} - >>> e = [(u, v, ekey, d) for u, nbrs in adj.items() - ... for v, keydict in nbrs.items() - ... for ekey, d in keydict.items()] - >>> MDG.update(edges=e) - - See Also - -------- - add_edges_from: add multiple edges to a graph - add_nodes_from: add multiple nodes to a graph - """ - if edges is not None: - if nodes is not None: - self.add_nodes_from(nodes) - self.add_edges_from(edges) - else: - # check if edges is a Graph object - try: - graph_nodes = edges.nodes - graph_edges = edges.edges - except AttributeError: - # edge not Graph-like - self.add_edges_from(edges) - else: # edges is Graph-like - self.add_nodes_from(graph_nodes.data()) - self.add_edges_from(graph_edges.data()) - self.graph.update(edges.graph) - elif nodes is not None: - self.add_nodes_from(nodes) - else: - raise NetworkXError("update needs nodes or edges input") - - def has_edge(self, u, v): - """Returns True if the edge (u, v) is in the graph. - - This is the same as `v in G[u]` without KeyError exceptions. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - - Returns - ------- - edge_ind : bool - True if edge is in the graph, False otherwise. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.has_edge(0, 1) # using two nodes - True - >>> e = (0, 1) - >>> G.has_edge(*e) # e is a 2-tuple (u, v) - True - >>> e = (0, 1, {'weight':7}) - >>> G.has_edge(*e[:2]) # e is a 3-tuple (u, v, data_dictionary) - True - - The following syntax are equivalent: - - >>> G.has_edge(0, 1) - True - >>> 1 in G[0] # though this gives KeyError if 0 not in G - True - - """ - try: - return v in self._adj[u] - except KeyError: - return False - - def neighbors(self, n): - """Returns an iterator over all neighbors of node n. - - This is identical to `iter(G[n])` - - Parameters - ---------- - n : node - A node in the graph - - Returns - ------- - neighbors : iterator - An iterator over all neighbors of node n - - Raises - ------ - NetworkXError - If the node n is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [n for n in G.neighbors(0)] - [1] - - Notes - ----- - It is usually more convenient (and faster) to access the - adjacency dictionary as ``G[n]``: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge('a', 'b', weight=7) - >>> G['a'] - AtlasView({'b': {'weight': 7}}) - >>> G = nx.path_graph(4) - >>> [n for n in G[0]] - [1] - """ - try: - return iter(self._adj[n]) - except KeyError: - raise NetworkXError("The node %s is not in the graph." % (n,)) - - @property - def edges(self): - """An EdgeView of the Graph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, default=None) - - The EdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges.data('color', default='red'):` - iterates through all the edges yielding the color attribute - with default `'red'` if no color attribute exists. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - 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 - ------- - edges : EdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.path_graph(3) # or MultiGraph, etc - >>> G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges] - [(0, 1), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - EdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data('weight', default=1) - EdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges([0, 3]) # only edges incident to these nodes - EdgeDataView([(0, 1), (3, 2)]) - >>> G.edges(0) # only edges incident to a single node (use G.adj[0]?) - EdgeDataView([(0, 1)]) - """ - return EdgeView(self) - - def get_edge_data(self, u, v, default=None): - """Returns the attribute dictionary associated with edge (u, v). - - This is identical to `G[u][v]` except the default is returned - instead of an exception if the edge doesn't exist. - - Parameters - ---------- - u, v : nodes - default: any Python object (default=None) - Value to return if the edge (u, v) is not found. - - Returns - ------- - edge_dict : dictionary - The edge attribute dictionary. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G[0][1] - {} - - Warning: Assigning to `G[u][v]` is not permitted. - But it is safe to assign attributes `G[u][v]['foo']` - - >>> G[0][1]['weight'] = 7 - >>> G[0][1]['weight'] - 7 - >>> G[1][0]['weight'] - 7 - - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.get_edge_data(0, 1) # default edge data is {} - {} - >>> e = (0, 1) - >>> G.get_edge_data(*e) # tuple form - {} - >>> G.get_edge_data('a', 'b', default=0) # edge not in graph, return 0 - 0 - """ - try: - return self._adj[u][v] - except KeyError: - return default - - def adjacency(self): - """Returns an iterator over (node, adjacency dict) tuples for all nodes. - - For directed graphs, only outgoing neighbors/adjacencies are included. - - Returns - ------- - adj_iter : iterator - An iterator over (node, adjacency dictionary) for all nodes in - the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [(n, nbrdict) for n, nbrdict in G.adjacency()] - [(0, {1: {}}), (1, {0: {}, 2: {}}), (2, {1: {}, 3: {}}), (3, {2: {}})] - - """ - return iter(self._adj.items()) - - @property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_view : A DegreeView object capable of iterating (node, degree) pairs - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.degree[0] # node 0 has degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - """ - return DegreeView(self) - - def clear(self): - """Remove all nodes and edges from the graph. - - This also removes the name, and all graph, node, and edge attributes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear() - >>> list(G.nodes) - [] - >>> list(G.edges) - [] - - """ - self._adj.clear() - self._node.clear() - self.graph.clear() - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return False - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return False - - def copy(self, as_view=False): - """Returns a copy of the graph. - - The copy method by default returns an independent shallow copy - of the graph and attributes. That is, if an attribute is a - container, that container is shared by the original an the copy. - Use Python's `copy.deepcopy` for new containers. - - If `as_view` is True then a view is returned instead of a copy. - - Notes - ----- - All copies reproduce the graph structure, but data attributes - may be handled in different ways. There are four types of copies - of a graph that people might want. - - Deepcopy -- A "deepcopy" copies the graph structure as well as - all data attributes and any objects they might contain. - The entire graph object is new so that changes in the copy - do not affect the original object. (see Python's copy.deepcopy) - - Data Reference (Shallow) -- For a shallow copy the graph structure - is copied but the edge, node and graph attribute dicts are - references to those in the original graph. This saves - time and memory but could cause confusion if you change an attribute - in one graph and it changes the attribute in the other. - NetworkX does not provide this level of shallow copy. - - Independent Shallow -- This copy creates new independent attribute - dicts and then does a shallow copy of the attributes. That is, any - attributes that are containers are shared between the new graph - and the original. This is exactly what `dict.copy()` provides. - You can obtain this style copy using: - - >>> G = nx.path_graph(5) - >>> H = G.copy() - >>> H = G.copy(as_view=False) - >>> H = nx.Graph(G) - >>> H = G.__class__(G) - - Fresh Data -- For fresh data, the graph structure is copied while - new empty data attribute dicts are created. The resulting graph - is independent of the original and it has no edge, node or graph - attributes. Fresh copies are not enabled. Instead use: - - >>> H = G.__class__() - >>> H.add_nodes_from(G) - >>> H.add_edges_from(G.edges) - - View -- Inspired by dict-views, graph-views act like read-only - versions of the original graph, providing a copy of the original - structure without requiring any memory for copying the information. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Parameters - ---------- - as_view : bool, optional (default=False) - If True, the returned graph-view provides a read-only view - of the original graph without actually copying any data. - - Returns - ------- - G : Graph - A copy of the graph. - - See Also - -------- - to_directed: return a directed copy of the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.copy() - - """ - if as_view is True: - return nx.graphviews.generic_graph_view(self) - G = self.__class__() - G.graph.update(self.graph) - G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) - G.add_edges_from((u, v, datadict.copy()) - for u, nbrs in self._adj.items() - for v, datadict in nbrs.items()) - return G - - def to_directed(self, as_view=False): - """Returns a directed representation of the graph. - - Returns - ------- - G : DiGraph - A directed graph with the same name, same nodes, and with - each edge (u, v, data) replaced by two directed edges - (u, v, data) and (v, u, data). - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=DiGraph(G) which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed Graph to use dict-like objects - in the data structure, those changes do not transfer to the - DiGraph created by this method. - - Examples - -------- - >>> G = nx.Graph() # or MultiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - - If already directed, return a (deep) copy - - >>> G = nx.DiGraph() # or MultiDiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1)] - """ - graph_class = self.to_directed_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from((u, v, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, data in nbrs.items()) - return G - - def to_undirected(self, as_view=False): - """Returns an undirected copy of the graph. - - Parameters - ---------- - as_view : bool (optional, default=False) - If True return a view of the original undirected graph. - - Returns - ------- - G : Graph/MultiGraph - A deepcopy of the graph. - - See Also - -------- - Graph, copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar `G = nx.DiGraph(D)` which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed DiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - Graph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from((u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items()) - return G - - def subgraph(self, nodes): - """Returns a SubGraph view of the subgraph induced on `nodes`. - - The induced subgraph of the graph contains the nodes in `nodes` - and the edges between those nodes. - - Parameters - ---------- - nodes : list, iterable - A container of nodes which will be iterated through once. - - Returns - ------- - G : SubGraph View - A subgraph view of the graph. The graph structure cannot be - changed but node/edge attributes can and are shared with the - original graph. - - Notes - ----- - The graph, edge and node attributes are shared with the original graph. - Changes to the graph structure is ruled out by the view, but changes - to attributes are reflected in the original graph. - - To create a subgraph with its own copy of the edge/node attributes use: - G.subgraph(nodes).copy() - - For an inplace reduction of a graph to a subgraph you can remove nodes: - G.remove_nodes_from([n for n in G if n not in set(nodes)]) - - Subgraph views are sometimes NOT what you want. In most cases where - you want to do more than simply look at the induced edges, it makes - more sense to just create the subgraph as its own graph with code like: - - :: - - # Create a subgraph SG based on a (possibly multigraph) G - SG = G.__class__() - SG.add_nodes_from((n, G.nodes[n]) for n in largest_wcc) - if SG.is_multigraph: - SG.add_edges_from((n, nbr, key, d) - for n, nbrs in G.adj.items() if n in largest_wcc - for nbr, keydict in nbrs.items() if nbr in largest_wcc - for key, d in keydict.items()) - else: - SG.add_edges_from((n, nbr, d) - for n, nbrs in G.adj.items() if n in largest_wcc - for nbr, d in nbrs.items() if nbr in largest_wcc) - SG.graph.update(G.graph) - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.subgraph([0, 1, 2]) - >>> list(H.edges) - [(0, 1), (1, 2)] - """ - induced_nodes = nx.filters.show_nodes(self.nbunch_iter(nodes)) - # if already a subgraph, don't make a chain - subgraph = nx.graphviews.subgraph_view - if hasattr(self, '_NODE_OK'): - return subgraph(self._graph, induced_nodes, self._EDGE_OK) - return subgraph(self, induced_nodes) - - def edge_subgraph(self, edges): - """Returns the subgraph induced by the specified edges. - - The induced subgraph contains each edge in `edges` and each - node incident to any one of those edges. - - Parameters - ---------- - edges : iterable - An iterable of edges in this graph. - - Returns - ------- - G : Graph - An edge-induced subgraph of this graph with the same edge - attributes. - - Notes - ----- - The graph, edge, and node attributes in the returned subgraph - view are references to the corresponding attributes in the original - graph. The view is read-only. - - To create a full graph version of the subgraph with its own copy - of the edge or node attributes, use:: - - >>> G.edge_subgraph(edges).copy() # doctest: +SKIP - - 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)] - - """ - return nx.edge_subgraph(self, edges) - - def size(self, weight=None): - """Returns the number of edges or total of all edge weights. - - Parameters - ---------- - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - - Returns - ------- - size : numeric - The number of edges or - (if weight keyword is provided) the total weight sum. - - If weight is None, returns an int. Otherwise a float - (or more general numeric if the weights are more general). - - See Also - -------- - number_of_edges - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.size() - 3 - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge('a', 'b', weight=2) - >>> G.add_edge('b', 'c', weight=4) - >>> G.size() - 2 - >>> G.size(weight='weight') - 6.0 - """ - s = sum(d for v, d in self.degree(weight=weight)) - # If `weight` is None, the sum of the degrees is guaranteed to be - # even, so we can perform integer division and hence return an - # integer. Otherwise, the sum of the weighted degrees is not - # guaranteed to be an integer, so we perform "real" division. - return s // 2 if weight is None else s / 2 - - def number_of_edges(self, u=None, v=None): - """Returns the number of edges between two nodes. - - Parameters - ---------- - u, v : nodes, optional (default=all edges) - If u and v are specified, return the number of edges between - u and v. Otherwise return the total number of all edges. - - Returns - ------- - nedges : int - The number of edges in the graph. If nodes `u` and `v` are - specified return the number of edges between those nodes. If - the graph is directed, this only returns the number of edges - from `u` to `v`. - - See Also - -------- - size - - Examples - -------- - For undirected graphs, this method counts the total number of - edges in the graph: - - >>> G = nx.path_graph(4) - >>> G.number_of_edges() - 3 - - If you specify two nodes, this counts the total number of edges - joining the two nodes: - - >>> G.number_of_edges(0, 1) - 1 - - For directed graphs, this method can count the total number of - directed edges from `u` to `v`: - - >>> G = nx.DiGraph() - >>> G.add_edge(0, 1) - >>> G.add_edge(1, 0) - >>> G.number_of_edges(0, 1) - 1 - - """ - if u is None: - return int(self.size()) - if v in self._adj[u]: - return 1 - return 0 - - def nbunch_iter(self, nbunch=None): - """Returns an iterator over nodes contained in nbunch that are - also in the graph. - - The nodes in nbunch are checked for membership in the graph - and if not are silently ignored. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - Returns - ------- - niter : iterator - An iterator over nodes in nbunch that are also in the graph. - If nbunch is None, iterate over all nodes in the graph. - - Raises - ------ - NetworkXError - If nbunch is not a node or or sequence of nodes. - If a node in nbunch is not hashable. - - See Also - -------- - Graph.__iter__ - - Notes - ----- - When nbunch is an iterator, the returned iterator yields values - directly from nbunch, becoming exhausted when nbunch is exhausted. - - To test whether nbunch is a single node, one can use - "if nbunch in self:", even after processing with this routine. - - If nbunch is not a node or a (possibly empty) sequence/iterator - or None, a :exc:`NetworkXError` is raised. Also, if any object in - nbunch is not hashable, a :exc:`NetworkXError` is raised. - """ - if nbunch is None: # include all nodes via iterator - bunch = iter(self._adj) - elif nbunch in self: # if nbunch is a single node - bunch = iter([nbunch]) - else: # if nbunch is a sequence of nodes - def bunch_iter(nlist, adj): - try: - for n in nlist: - if n in adj: - yield n - except TypeError as e: - message = e.args[0] - # capture error for non-sequence/iterator nbunch. - if 'iter' in message: - msg = "nbunch is not a node or a sequence of nodes." - raise NetworkXError(msg) - # capture error for unhashable node. - elif 'hashable' in message: - msg = "Node {} in sequence nbunch is not a valid node." - raise NetworkXError(msg.format(n)) - else: - raise - bunch = bunch_iter(nbunch, self._adj) - return bunch