diff env/lib/python3.7/site-packages/networkx/classes/function.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/function.py	Thu May 14 16:47:39 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1192 +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>
-#          Pieter Swart <swart@lanl.gov>
-#          Dan Schult <dschult@colgate.edu>
-"""Functional interface to graph methods and assorted utilities.
-"""
-
-from collections import Counter
-from itertools import chain
-try:
-    from itertools import zip_longest
-except ImportError:
-    from itertools import izip_longest as zip_longest
-
-import networkx as nx
-from networkx.utils import pairwise, not_implemented_for
-
-from networkx.classes.graphviews import subgraph_view, reverse_view
-
-__all__ = ['nodes', 'edges', 'degree', 'degree_histogram', 'neighbors',
-           'number_of_nodes', 'number_of_edges', 'density',
-           'is_directed', 'info', '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',
-           ]
-
-
-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 e:
-    ...    print(str(e))
-    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.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
-    --------
-    >>> import networkx as nx
-    >>> 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(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
-    --------
-    >>> import networkx as nx
-    >>> 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
-    --------
-    >>> import networkx as nx
-    >>> 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 info(G, n=None):
-    """Print short summary of information for the graph G or the node n.
-
-    Parameters
-    ----------
-    G : Networkx graph
-       A graph
-    n : node (any hashable)
-       A node in the graph G
-    """
-    info = ''  # append this all to a string
-    if n is None:
-        info += "Name: %s\n" % G.name
-        type_name = [type(G).__name__]
-        info += "Type: %s\n" % ",".join(type_name)
-        info += "Number of nodes: %d\n" % G.number_of_nodes()
-        info += "Number of edges: %d\n" % G.number_of_edges()
-        nnodes = G.number_of_nodes()
-        if len(G) > 0:
-            if G.is_directed():
-                deg = sum(d for n, d in G.in_degree()) / float(nnodes)
-                info += "Average in degree: %8.4f\n" % deg
-                deg = sum(d for n, d in G.out_degree()) / float(nnodes)
-                info += "Average out degree: %8.4f" % deg
-            else:
-                s = sum(dict(G.degree()).values())
-                info += "Average degree: %8.4f" % (float(s) / float(nnodes))
-
-    else:
-        if n not in G:
-            raise nx.NetworkXError("node %s not in graph" % (n,))
-        info += "Node % s has the following properties:\n" % n
-        info += "Degree: %d\n" % G.degree(n)
-        info += "Neighbors: "
-        info += ' '.join(str(nbr) for nbr in G.neighbors(n))
-    return info
-
-
-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]
-        {}
-
-    """
-    # 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
-
-    """
-    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 = 'Edge {!r} does not exist.'.format(edge)
-            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 = 'Edge {!r} does not exist.'.format(edge)
-            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
-    ----------
-    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 d in nbrs[n].values())
-        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))