summaryrefslogtreecommitdiff
path: root/networkx/classes/multigraph.py
diff options
context:
space:
mode:
Diffstat (limited to 'networkx/classes/multigraph.py')
-rw-r--r--networkx/classes/multigraph.py128
1 files changed, 40 insertions, 88 deletions
diff --git a/networkx/classes/multigraph.py b/networkx/classes/multigraph.py
index a5543f63..cfbce77d 100644
--- a/networkx/classes/multigraph.py
+++ b/networkx/classes/multigraph.py
@@ -231,6 +231,20 @@ class MultiGraph(Graph):
dict which holds attrbute 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
--------
@@ -244,6 +258,22 @@ class MultiGraph(Graph):
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.
@@ -845,20 +875,6 @@ class MultiGraph(Graph):
"""Return True if graph is directed, False otherwise."""
return False
- def fresh_copy(self):
- """Return a fresh copy graph with the same data structure.
-
- A fresh copy has no nodes, edges or graph attributes. It is
- the same data structure as the current graph. This method is
- typically used to create an empty version of the graph.
-
- Notes
- -----
- If you subclass the base class you should overwrite this method
- to return your class of graph.
- """
- return MultiGraph()
-
def copy(self, as_view=False):
"""Return a copy of the graph.
@@ -897,14 +913,14 @@ class MultiGraph(Graph):
>>> H = G.copy()
>>> H = G.copy(as_view=False)
>>> H = nx.Graph(G)
- >>> H = G.fresh_copy().__class__(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.fresh_copy()
+ >>> H = G.__class__()
>>> H.add_nodes_from(G)
>>> H.add_edges_from(G.edges)
@@ -937,8 +953,8 @@ class MultiGraph(Graph):
"""
if as_view is True:
- return nx.graphviews.MultiGraphView(self)
- G = self.fresh_copy()
+ 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())
@@ -989,11 +1005,11 @@ class MultiGraph(Graph):
>>> list(H.edges)
[(0, 1)]
"""
+ graph_class = self.to_directed_class()
if as_view is True:
- return nx.graphviews.MultiDiGraphView(self)
+ return nx.graphviews.generic_graph_view(self, graph_class)
# deepcopy when not a view
- from networkx.classes.multidigraph import MultiDiGraph
- G = MultiDiGraph()
+ 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))
@@ -1040,10 +1056,11 @@ class MultiGraph(Graph):
>>> list(G2.edges)
[(0, 1)]
"""
+ graph_class = self.to_undirected_class()
if as_view is True:
- return nx.graphviews.MultiGraphView(self)
+ return nx.graphviews.generic_graph_view(self, graph_class)
# deepcopy when not a view
- G = MultiGraph()
+ 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))
@@ -1052,71 +1069,6 @@ class MultiGraph(Graph):
for key, datadict in keydict.items())
return G
- def subgraph(self, nodes):
- """Return a SubGraph view of the subgraph induced on nodes in `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.fresh_copy()
- 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.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
- >>> nx.add_path(G, [0, 1, 2, 3])
- >>> H = G.subgraph([0, 1, 2])
- >>> list(H.edges)
- [(0, 1), (1, 2)]
- """
- induced_nodes = nx.filters.show_nodes(self.nbunch_iter(nodes))
- SubGraph = nx.graphviews.SubMultiGraph
- # if already a subgraph, don't make a chain
- if hasattr(self, '_NODE_OK'):
- return SubGraph(self._graph, induced_nodes, self._EDGE_OK)
- return SubGraph(self, induced_nodes)
-
def number_of_edges(self, u=None, v=None):
"""Return the number of edges between two nodes.