Reputation: 39
I have a Graph with many nodes of degree 2 (derived from a LineString). In order to simplify the Graph I would like to reduce it to just the nodes with a degree not equal to 2 but still containig the same overall connections. You can find an example of what I mean in the picture below. So if there are multiple nodes mit degree=2 between two nodes with the degree of 3, all the nodes and edges in the middle should be deleted and a single connection between the two deg=3 nodes should be established with the same weight as the sum of the omitted edges.
Example Picture of reduced Graph
Upvotes: 3
Views: 1234
Reputation: 19
nx.component.connected_component_subgraphs
has been deprecated. components
can now be defined as:
components = [chains.subgraph(c) for c in nx.components.connected_components(chains)]
Upvotes: 1
Reputation: 13031
You can identify chains by 1) inducing a subgraph only containing nodes with degree 2, and 2) then identifying the individual components in the induced subgraph. Then it is a simple matter of summing the weights in each chain and creating a new edge with that weight between the nodes connecting to the end points of the chain.
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
def contract(g):
"""
Contract chains of neighbouring vertices with degree 2 into a single edge.
Arguments:
----------
g -- networkx.Graph or networkx.DiGraph instance
Returns:
--------
h -- networkx.Graph or networkx.DiGraph instance
the contracted graph
"""
# create subgraph of all nodes with degree 2
is_chain = [node for node, degree in g.degree() if degree == 2]
chains = g.subgraph(is_chain)
# contract connected components (which should be chains of variable length) into single node
components = list(nx.components.connected_component_subgraphs(chains))
hyper_edges = []
for component in components:
end_points = [node for node, degree in component.degree() if degree < 2]
candidates = set([neighbor for node in end_points for neighbor in g.neighbors(node)])
connectors = candidates - set(list(component.nodes()))
hyper_edge = list(connectors)
weights = [component.get_edge_data(*edge)['weight'] for edge in component.edges()]
hyper_edges.append((hyper_edge, np.sum(weights)))
# initialise new graph with all other nodes
not_chain = [node for node in g.nodes() if not node in is_chain]
h = g.subgraph(not_chain).copy()
for hyper_edge, weight in hyper_edges:
h.add_edge(*hyper_edge, weight=weight)
return h
# create weighted graph
edges = np.random.randint(0, 20, size=(int(400*0.2), 2))
weights = np.random.rand(len(edges))
g = nx.Graph()
for edge, weight in zip(edges, weights):
g.add_edge(*edge, weight=weight)
h = nx.algorithms.minimum_spanning_tree(g)
# contract
i = contract(h)
# plot
pos = nx.spring_layout(h)
fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)
nx.draw(h, pos=pos, ax=ax1)
nx.draw(i, pos=pos, ax=ax2)
plt.show()
Upvotes: 6