Warning

This documents an unmaintained version of NetworkX. Please upgrade to a maintained version and see the current NetworkX documentation.

Source code for networkx.classes.graphviews

#    Copyright (C) 2004-2018 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)
"""View of Graphs as SubGraph, Reverse, Directed, Undirected.

In some algorithms it is convenient to temporarily morph
a graph to exclude some nodes or edges. It should be better
to do that via a view than to remove and then re-add.
In other algorithms it is convenient to temporarily morph
a graph to reverse directed edges, or treat a directed graph
as undirected, etc. This module provides those graph views.

The resulting views are essentially read-only graphs that
report data from the orignal graph object. We provide an
attribute G._graph which points to the underlying graph object.

Note: Since graphviews look like graphs, one can end up with
view-of-view-of-view chains. Be careful with chains because
they become very slow with about 15 nested views.
For the common simple case of node induced subgraphs created
from the graph class, we short-cut the chain by returning a
subgraph of the original graph directly rather than a subgraph
of a subgraph. We are careful not to disrupt any edge filter in
the middle subgraph. In general, determining how to short-cut
the chain is tricky and much harder with restricted_views than
with induced subgraphs.
Often it is easiest to use .copy() to avoid chains.
"""
from networkx.classes.coreviews import UnionAdjacency, UnionMultiAdjacency, \
    FilterAtlas, FilterAdjacency, FilterMultiAdjacency
from networkx.classes.filters import no_filter
from networkx.exception import NetworkXError, NetworkXNotImplemented
# remove the graph class import when deprecated GraphView removed
from networkx.classes import Graph, DiGraph, MultiGraph, MultiDiGraph

import networkx as nx

__all__ = ['generic_graph_view', 'subgraph_view', 'reverse_view',
           'SubGraph', 'SubDiGraph', 'SubMultiGraph', 'SubMultiDiGraph',
           'ReverseView', 'MultiReverseView',
           'DiGraphView', 'MultiDiGraphView',
           'GraphView', 'MultiGraphView',
           ]


[docs]def generic_graph_view(G, create_using=None): if create_using is None: newG = G.__class__() else: newG = nx.empty_graph(0, create_using) if G.is_multigraph() != newG.is_multigraph(): raise NetworkXError("Multigraph for G must agree with create_using") newG = nx.freeze(newG) # create view by assigning attributes from G newG._graph = G newG.graph = G.graph newG._node = G._node if newG.is_directed(): if G.is_directed(): newG._succ = G._succ newG._pred = G._pred newG._adj = G._succ else: newG._succ = G._adj newG._pred = G._adj newG._adj = G._adj elif G.is_directed(): if G.is_multigraph(): newG._adj = UnionMultiAdjacency(G._succ, G._pred) else: newG._adj = UnionAdjacency(G._succ, G._pred) else: newG._adj = G._adj return newG
[docs]def subgraph_view(G, filter_node=no_filter, filter_edge=no_filter): newG = nx.freeze(G.__class__()) newG._NODE_OK = filter_node newG._EDGE_OK = filter_edge # create view by assigning attributes from G newG._graph = G newG.graph = G.graph newG._node = FilterAtlas(G._node, filter_node) if G.is_multigraph(): Adj = FilterMultiAdjacency def reverse_edge(u, v, k): return filter_edge(v, u, k) else: Adj = FilterAdjacency def reverse_edge(u, v): return filter_edge(v, u) if G.is_directed(): newG._succ = Adj(G._succ, filter_node, filter_edge) newG._pred = Adj(G._pred, filter_node, reverse_edge) newG._adj = newG._succ else: newG._adj = Adj(G._adj, filter_node, filter_edge) return newG
[docs]def reverse_view(G): if not G.is_directed(): msg = "not implemented for undirected type" raise NetworkXNotImplemented(msg) newG = generic_graph_view(G) newG._succ, newG._pred = G._pred, G._succ newG._adj = newG._succ return newG
# The remaining definitions are for backward compatibility with v2.0 and 2.1 def ReverseView(G): # remove by v3 if not before import warnings msg = 'ReverseView is deprecated. Use reverse_view instead' warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return reverse_view(G) def SubGraph(G, filter_node=no_filter, filter_edge=no_filter): # remove by v3 if not before import warnings msg = 'SubGraph is deprecated. Use subgraph_view instead' warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return subgraph_view(G, filter_node, filter_edge) def GraphView(G): # remove by v3 if not before import warnings msg = 'GraphView is deprecated. Use generic_graph_view instead' warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return generic_graph_view(G, Graph) def DiGraphView(G): # remove by v3 if not before import warnings msg = 'GraphView is deprecated. Use generic_graph_view instead' warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return generic_graph_view(G, DiGraph) def MultiGraphView(G): # remove by v3 if not before import warnings msg = 'GraphView is deprecated. Use generic_graph_view instead' warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return generic_graph_view(G, MultiGraph) def MultiDiGraphView(G): # remove by v3 if not before import warnings msg = 'GraphView is deprecated. Use generic_graph_view instead' warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return generic_graph_view(G, MultiDiGraph) MultiReverseView = ReverseView SubMultiGraph = SubMultiDiGraph = SubDiGraph = SubGraph