Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/networkx/classes/multigraph.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/multigraph.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1139 +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. -# -# Authors: Aric Hagberg <hagberg@lanl.gov> -# Dan Schult <dschult@colgate.edu> -# Pieter Swart <swart@lanl.gov> -"""Base class for MultiGraph.""" -from copy import deepcopy - -import networkx as nx -from networkx.classes.graph import Graph -from networkx.classes.coreviews import MultiAdjacencyView -from networkx.classes.reportviews import MultiEdgeView, MultiDegreeView -from networkx import NetworkXError -from networkx.utils import iterable - - -class MultiGraph(Graph): - """ - An undirected graph class that can store multiedges. - - Multiedges are multiple edges between two nodes. Each edge - can hold optional data or attributes. - - A MultiGraph holds undirected edges. Self loops are allowed. - - 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 - -------- - Graph - DiGraph - MultiDiGraph - OrderedMultiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.MultiGraph() - - 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, - - >>> key = G.add_edge(1, 2) - - a list of edges, - - >>> keys = G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> keys = G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. If an edge already exists, an additional - edge is created and stored using a key to identify the edge. - By default the key is the lowest unused integer. - - >>> keys = G.add_edges_from([(4,5,{'route':28}), (4,5,{'route':37})]) - >>> G[4] - AdjacencyView({3: {0: {}}, 5: {0: {}, 1: {'route': 28}, 2: {'route': 37}}}) - - **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.MultiGraph(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 - >>> 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. - - >>> key = G.add_edge(1, 2, weight=4.7 ) - >>> keys = G.add_edges_from([(3, 4), (4, 5)], color='red') - >>> keys = G.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})]) - >>> G[1][2][0]['weight'] = 4.7 - >>> G.edges[1, 2, 0]['weight'] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, 2]` 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 - >>> G[1] # adjacency dict-like view keyed by neighbor to edge attributes - AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}}) - - 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, keydict in nbrsdict.items(): - ... for key, eattr in keydict.items(): - ... if 'weight' in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, keys, weight in G.edges(data='weight', keys=True): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using methods and object-attributes. - Reporting usually 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 MultiGraph class uses a dict-of-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_key dicts keyed by neighbor. The edge_key dict holds each edge_attr - dict keyed by edge key. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these four dicts in the dict-of-dict-of-dict-of-dict - structure can be replaced 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_key_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 multiedge key dicts keyed by neighbor. - It should require no arguments and return a dict-like object. - - edge_key_dict_factory : function, (default: dict) - Factory function to be used to create the edge key dict - which holds edge data keyed by edge key. - 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 inherited 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 - -------- - - Please see :mod:`~networkx.classes.ordered` for examples of - creating graph subclasses by overwriting the base class `dict` with - a dictionary-like object. - """ - # node_dict_factory = dict # already assigned in Graph - # adjlist_outer_dict_factory = dict - # adjlist_inner_dict_factory = dict - edge_key_dict_factory = dict - # edge_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.MultiDiGraph - - 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 MultiGraph - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph - Data to initialize graph. If incoming_graph_data=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.edge_key_dict_factory = self.edge_key_dict_factory - Graph.__init__(self, incoming_graph_data, **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 edgekey-data-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, nbrdict 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 MultiAdjacencyView(self._adj) - - def new_edge_key(self, u, v): - """Returns an unused key for edges between nodes `u` and `v`. - - The nodes `u` and `v` do not need to be already in the graph. - - Notes - ----- - In the standard MultiGraph class the new key is the number of existing - edges between `u` and `v` (increased if necessary to ensure unused). - The first edge will have key 0, then 1, etc. If an edge is removed - further new_edge_keys may not be in this order. - - Parameters - ---------- - u, v : nodes - - Returns - ------- - key : int - """ - try: - keydict = self._adj[u][v] - except KeyError: - return 0 - key = len(keydict) - while key in keydict: - key += 1 - return key - - def add_edge(self, u_for_edge, v_for_edge, key=None, **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_for_edge, v_for_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - key : hashable identifier, optional (default=lowest unused integer) - Used to distinguish multiedges between a pair of nodes. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - The edge key assigned to the edge. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - To replace/update edge data, use the optional key argument - to identify a unique edge. Otherwise a new edge will be created. - - NetworkX algorithms designed for weighted graphs cannot use - multigraphs directly because it is not clear how to handle - multiedge weights. Convert to Graph using edge attribute - 'weight' to enable weighted graph algorithms. - - Default keys are generated using the method `new_edge_key()`. - This method can be overridden by subclassing the base class and - providing a custom `new_edge_key()` method. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.MultiGraph() - >>> e = (1, 2) - >>> ekey = G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - 1 - >>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container - [2] - - Associate data to edges using keywords: - - >>> ekey = G.add_edge(1, 2, weight=3) - >>> ekey = G.add_edge(1, 2, key=0, weight=4) # update data for key=0 - >>> ekey = G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> ekey = G.add_edge(1, 2) - >>> G[1][2][0].update({0: 5}) - >>> G.edges[1, 2, 0].update({0: 5}) - """ - u, v = u_for_edge, v_for_edge - # add nodes - if u not in self._adj: - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._adj: - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - if key is None: - key = self.new_edge_key(u, v) - if v in self._adj[u]: - keydict = self._adj[u][v] - datadict = keydict.get(key, self.edge_attr_dict_factory()) - datadict.update(attr) - keydict[key] = datadict - else: - # selfloops work this way without special treatment - datadict = self.edge_attr_dict_factory() - datadict.update(attr) - keydict = self.edge_key_dict_factory() - keydict[key] = datadict - self._adj[u][v] = keydict - self._adj[v][u] = keydict - return key - - 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 can be: - - - 2-tuples (u, v) or - - 3-tuples (u, v, d) for an edge data dict d, or - - 3-tuples (u, v, k) for not iterable key k, or - - 4-tuples (u, v, k, d) for an edge with data and key k - - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - A list of edge keys assigned to the edges in `ebunch`. - - 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. - - Default keys are generated using the method ``new_edge_key()``. - This method can be overridden by subclassing the base class and - providing a custom ``new_edge_key()`` method. - - 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') - """ - keylist = [] - for e in ebunch_to_add: - ne = len(e) - if ne == 4: - u, v, key, dd = e - elif ne == 3: - u, v, dd = e - key = None - elif ne == 2: - u, v = e - dd = {} - key = None - else: - msg = "Edge tuple {} must be a 2-tuple, 3-tuple or 4-tuple." - raise NetworkXError(msg.format(e)) - ddd = {} - ddd.update(attr) - try: - ddd.update(dd) - except: - if ne != 3: - raise - key = dd - key = self.add_edge(u, v, key) - self[u][v][key].update(ddd) - keylist.append(key) - return keylist - - def remove_edge(self, u, v, key=None): - """Remove an edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove an edge between nodes u and v. - key : hashable identifier, optional (default=None) - Used to distinguish multiple edges between a pair of nodes. - If None remove a single (arbitrary) edge between u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v, or - if there is no edge with the specified key. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.MultiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - - For multiple edges - - >>> G = nx.MultiGraph() # or MultiDiGraph, etc - >>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned - [0, 1, 2] - >>> G.remove_edge(1, 2) # remove a single (arbitrary) edge - - For edges with keys - - >>> G = nx.MultiGraph() # or MultiDiGraph, etc - >>> G.add_edge(1, 2, key='first') - 'first' - >>> G.add_edge(1, 2, key='second') - 'second' - >>> G.remove_edge(1, 2, key='second') - - """ - try: - d = self._adj[u][v] - except KeyError: - raise NetworkXError( - "The edge %s-%s is not in the graph." % (u, v)) - # remove the edge with specified data - if key is None: - d.popitem() - else: - try: - del d[key] - except KeyError: - msg = "The edge %s-%s with key %s is not in the graph." - raise NetworkXError(msg % (u, v, key)) - if len(d) == 0: - # remove the key entries if last edge - del self._adj[u][v] - if u != v: # check for selfloop - del self._adj[v][u] - - 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) All edges between u and v are removed. - - 3-tuples (u, v, key) The edge identified by key is removed. - - 4-tuples (u, v, key, data) where data 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) - - Removing multiple copies of edges - - >>> G = nx.MultiGraph() - >>> keys = G.add_edges_from([(1, 2), (1, 2), (1, 2)]) - >>> G.remove_edges_from([(1, 2), (1, 2)]) - >>> list(G.edges()) - [(1, 2)] - >>> G.remove_edges_from([(1, 2), (1, 2)]) # silently ignore extra copy - >>> list(G.edges) # now empty graph - [] - """ - for e in ebunch: - try: - self.remove_edge(*e[:3]) - except NetworkXError: - pass - - def has_edge(self, u, v, key=None): - """Returns True if the graph has an edge between nodes u and v. - - This is the same as `v in G[u] or key in G[u][v]` - without KeyError exceptions. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - - key : hashable identifier, optional (default=None) - If specified return True only if the edge with - key is found. - - Returns - ------- - edge_ind : bool - True if edge is in the graph, False otherwise. - - Examples - -------- - Can be called either using two nodes u, v, an edge tuple (u, v), - or an edge tuple (u, v, key). - - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.has_edge(0, 1) # using two nodes - True - >>> e = (0, 1) - >>> G.has_edge(*e) # e is a 2-tuple (u, v) - True - >>> G.add_edge(0, 1, key='a') - 'a' - >>> G.has_edge(0, 1, key='a') # specify key - True - >>> e=(0, 1, 'a') - >>> G.has_edge(*e) # e is a 3-tuple (u, v, 'a') - True - - The following syntax are equivalent: - - >>> G.has_edge(0, 1) - True - >>> 1 in G[0] # though this gives :exc:`KeyError` if 0 not in G - True - - """ - try: - if key is None: - return v in self._adj[u] - else: - return key in self._adj[u][v] - except KeyError: - return False - - @property - def edges(self): - """Returns an iterator over the edges. - - edges(self, nbunch=None, data=False, keys=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. - - Edges are returned as tuples with optional data and keys - in the order (node, neighbor, key, data). - - 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). - 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 - ------- - edges : MultiEdgeView - A view of edge attributes, usually it iterates over (u, v) - (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as `edges[u, v, k]['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.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2]) - >>> key = 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) - MultiEdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data('weight', default=1) - MultiEdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges(keys=True) # default keys are integers - MultiEdgeView([(0, 1, 0), (1, 2, 0), (2, 3, 0)]) - >>> G.edges.data(keys=True) - MultiEdgeDataView([(0, 1, 0, {}), (1, 2, 0, {}), (2, 3, 0, {'weight': 5})]) - >>> G.edges.data('weight', default=1, keys=True) - MultiEdgeDataView([(0, 1, 0, 1), (1, 2, 0, 1), (2, 3, 0, 5)]) - >>> G.edges([0, 3]) - MultiEdgeDataView([(0, 1), (3, 2)]) - >>> G.edges(0) - MultiEdgeDataView([(0, 1)]) - """ - return MultiEdgeView(self) - - def get_edge_data(self, u, v, key=None, default=None): - """Returns the attribute dictionary associated with edge (u, v). - - This is identical to `G[u][v][key]` except the default is returned - instead of an exception is 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. - - key : hashable identifier, optional (default=None) - Return data only for the edge with specified key. - - Returns - ------- - edge_dict : dictionary - The edge attribute dictionary. - - Examples - -------- - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> key = G.add_edge(0, 1, key='a', weight=7) - >>> G[0][1]['a'] # key='a' - {'weight': 7} - >>> G.edges[0, 1, 'a'] # key='a' - {'weight': 7} - - Warning: we protect the graph data structure by making - `G.edges` and `G[1][2]` read-only dict-like structures. - However, you can assign values to attributes in e.g. - `G.edges[1, 2, 'a']` or `G[1][2]['a']` using an additional - bracket as shown next. You need to specify all edge info - to assign to the edge data associated with an edge. - - >>> G[0][1]['a']['weight'] = 10 - >>> G.edges[0, 1, 'a']['weight'] = 10 - >>> G[0][1]['a']['weight'] - 10 - >>> G.edges[1, 0, 'a']['weight'] - 10 - - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.get_edge_data(0, 1) - {0: {}} - >>> e = (0, 1) - >>> G.get_edge_data(*e) # tuple form - {0: {}} - >>> G.get_edge_data('a', 'b', default=0) # edge not in graph, return 0 - 0 - """ - try: - if key is None: - return self._adj[u][v] - else: - return self._adj[u][v][key] - except KeyError: - return default - - @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, if a single node is passed as argument. - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, degree). - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1])) - [(0, 1), (1, 2)] - - """ - return MultiDegreeView(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return True - - 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, key, datadict.copy()) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items()) - return G - - def to_directed(self, as_view=False): - """Returns a directed representation of the graph. - - Returns - ------- - G : MultiDiGraph - 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 MultiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - MultiDiGraph 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, key, deepcopy(datadict)) - for u, nbrs in self.adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items()) - return G - - def to_undirected(self, as_view=False): - """Returns an undirected copy of the graph. - - Returns - ------- - G : Graph/MultiGraph - A deepcopy of the graph. - - See Also - -------- - 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.MultiGraph(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 MultiiGraph to use dict-like - objects in the data structure, those changes do not transfer - to the MultiGraph 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, key, deepcopy(datadict)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items()) - return G - - def number_of_edges(self, u=None, v=None): - """Returns the number of edges between two nodes. - - Parameters - ---------- - u, v : nodes, optional (Gefault=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 multigraphs, this method counts the total number - of edges in the graph:: - - >>> G = nx.MultiGraph() - >>> G.add_edges_from([(0, 1), (0, 1), (1, 2)]) - [0, 1, 0] - >>> 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) - 2 - - For directed multigraphs, this method can count the total number - of directed edges from `u` to `v`:: - - >>> G = nx.MultiDiGraph() - >>> G.add_edges_from([(0, 1), (0, 1), (1, 0)]) - [0, 1, 0] - >>> G.number_of_edges(0, 1) - 2 - >>> G.number_of_edges(1, 0) - 1 - - """ - if u is None: - return self.size() - try: - edgedata = self._adj[u][v] - except KeyError: - return 0 # no such edge - return len(edgedata)
