comparison env/lib/python3.7/site-packages/networkx/classes/graphviews.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 # Copyright (C) 2004-2019 by
2 # Aric Hagberg <hagberg@lanl.gov>
3 # Dan Schult <dschult@colgate.edu>
4 # Pieter Swart <swart@lanl.gov>
5 # All rights reserved.
6 # BSD license.
7 #
8 # Author: Aric Hagberg (hagberg@lanl.gov),
9 # Pieter Swart (swart@lanl.gov),
10 # Dan Schult(dschult@colgate.edu)
11 """View of Graphs as SubGraph, Reverse, Directed, Undirected.
12
13 In some algorithms it is convenient to temporarily morph
14 a graph to exclude some nodes or edges. It should be better
15 to do that via a view than to remove and then re-add.
16 In other algorithms it is convenient to temporarily morph
17 a graph to reverse directed edges, or treat a directed graph
18 as undirected, etc. This module provides those graph views.
19
20 The resulting views are essentially read-only graphs that
21 report data from the orignal graph object. We provide an
22 attribute G._graph which points to the underlying graph object.
23
24 Note: Since graphviews look like graphs, one can end up with
25 view-of-view-of-view chains. Be careful with chains because
26 they become very slow with about 15 nested views.
27 For the common simple case of node induced subgraphs created
28 from the graph class, we short-cut the chain by returning a
29 subgraph of the original graph directly rather than a subgraph
30 of a subgraph. We are careful not to disrupt any edge filter in
31 the middle subgraph. In general, determining how to short-cut
32 the chain is tricky and much harder with restricted_views than
33 with induced subgraphs.
34 Often it is easiest to use .copy() to avoid chains.
35 """
36 from networkx.classes.coreviews import UnionAdjacency, UnionMultiAdjacency, \
37 FilterAtlas, FilterAdjacency, FilterMultiAdjacency
38 from networkx.classes.filters import no_filter
39 from networkx.exception import NetworkXError
40 from networkx.utils import not_implemented_for
41
42 import networkx as nx
43
44 __all__ = ['generic_graph_view', 'subgraph_view', 'reverse_view']
45
46
47 def generic_graph_view(G, create_using=None):
48 if create_using is None:
49 newG = G.__class__()
50 else:
51 newG = nx.empty_graph(0, create_using)
52 if G.is_multigraph() != newG.is_multigraph():
53 raise NetworkXError("Multigraph for G must agree with create_using")
54 newG = nx.freeze(newG)
55
56 # create view by assigning attributes from G
57 newG._graph = G
58 newG.graph = G.graph
59
60 newG._node = G._node
61 if newG.is_directed():
62 if G.is_directed():
63 newG._succ = G._succ
64 newG._pred = G._pred
65 newG._adj = G._succ
66 else:
67 newG._succ = G._adj
68 newG._pred = G._adj
69 newG._adj = G._adj
70 elif G.is_directed():
71 if G.is_multigraph():
72 newG._adj = UnionMultiAdjacency(G._succ, G._pred)
73 else:
74 newG._adj = UnionAdjacency(G._succ, G._pred)
75 else:
76 newG._adj = G._adj
77 return newG
78
79
80 def subgraph_view(G, filter_node=no_filter, filter_edge=no_filter):
81 """ View of `G` applying a filter on nodes and edges.
82
83 `subgraph_view` provides a read-only view of the input graph that excludes
84 nodes and edges based on the outcome of two filter functions `filter_node`
85 and `filter_edge`.
86
87 The `filter_node` function takes one argument --- the node --- and returns
88 `True` if the node should be included in the subgraph, and `False` if it
89 should not be included.
90
91 The `filter_edge` function takes two arguments --- the nodes describing an
92 edge --- and returns `True` if the edge should be included in the subgraph,
93 and `False` if it should not be included.
94
95 Both node and edge filter functions are called on graph elements as they
96 are queried, meaning there is no up-front cost to creating the view.
97
98 Parameters
99 ----------
100 G : networkx.Graph
101 A directed/undirected graph/multigraph
102
103 filter_node : callable, optional
104 A function taking a node as input, which returns `True` if the node
105 should appear in the view.
106
107 filter_edge : callable, optional
108 A function taking as input the two nodes describing an edge, which
109 returns `True` if the edge should appear in the view.
110
111 Returns
112 -------
113 graph : networkx.Graph
114 A read-only graph view of the input graph.
115
116 Examples
117 --------
118 >>> import networkx as nx
119 >>> G = nx.path_graph(6)
120
121 Filter functions operate on the node, and return `True` if the node should
122 appear in the view:
123
124 >>> def filter_node(n1):
125 ... return n1 != 5
126 ...
127 >>> view = nx.subgraph_view(
128 ... G,
129 ... filter_node=filter_node
130 ... )
131 >>> view.nodes()
132 NodeView((0, 1, 2, 3, 4))
133
134 We can use a closure pattern to filter graph elements based on additional
135 data --- for example, filtering on edge data attached to the graph:
136
137 >>> G[3][4]['cross_me'] = False
138 >>> def filter_edge(n1, n2):
139 ... return G[n1][n2].get('cross_me', True)
140 ...
141 >>> view = nx.subgraph_view(
142 ... G,
143 ... filter_edge=filter_edge
144 ... )
145 >>> view.edges()
146 EdgeView([(0, 1), (1, 2), (2, 3), (4, 5)])
147
148 >>> view = nx.subgraph_view(
149 ... G,
150 ... filter_node=filter_node,
151 ... filter_edge=filter_edge,
152 ... )
153 >>> view.nodes()
154 NodeView((0, 1, 2, 3, 4))
155 >>> view.edges()
156 EdgeView([(0, 1), (1, 2), (2, 3)])
157 """
158 newG = nx.freeze(G.__class__())
159 newG._NODE_OK = filter_node
160 newG._EDGE_OK = filter_edge
161
162 # create view by assigning attributes from G
163 newG._graph = G
164 newG.graph = G.graph
165
166 newG._node = FilterAtlas(G._node, filter_node)
167 if G.is_multigraph():
168 Adj = FilterMultiAdjacency
169
170 def reverse_edge(u, v, k): return filter_edge(v, u, k)
171 else:
172 Adj = FilterAdjacency
173
174 def reverse_edge(u, v): return filter_edge(v, u)
175 if G.is_directed():
176 newG._succ = Adj(G._succ, filter_node, filter_edge)
177 newG._pred = Adj(G._pred, filter_node, reverse_edge)
178 newG._adj = newG._succ
179 else:
180 newG._adj = Adj(G._adj, filter_node, filter_edge)
181 return newG
182
183
184 @not_implemented_for('undirected')
185 def reverse_view(G):
186 """ View of `G` with edge directions reversed
187
188 `reverse_view` returns a read-only view of the input graph where
189 edge directions are reversed.
190
191 Identical to digraph.reverse(copy=False)
192
193 Parameters
194 ----------
195 G : networkx.DiGraph
196
197 Returns
198 -------
199 graph : networkx.DiGraph
200
201 Examples
202 --------
203 >>> import networkx as nx
204 >>> G = nx.DiGraph()
205 >>> G.add_edge(1, 2)
206 >>> G.add_edge(2, 3)
207 >>> G.edges()
208 OutEdgeView([(1, 2), (2, 3)])
209
210 >>> view = nx.reverse_view(G)
211 >>> view.edges()
212 OutEdgeView([(2, 1), (3, 2)])
213 """
214 newG = generic_graph_view(G)
215 newG._succ, newG._pred = G._pred, G._succ
216 newG._adj = newG._succ
217 return newG