Python中简化NetworkX图:合并度数为2的直边节点
合并NetworkX有向图中直边节点的解决方案
你要处理的「直边」节点,本质是无向视角下度数为2的中间节点——这类节点只连接另外两个节点,没有分支,合并时可以直接将其两个邻居相连,同时删除该中间节点。针对DiGraph的双向连接需求,下面给出具体实现方案,同时解决端点保留的问题:
实现代码
import networkx as nx def merge_straight_edges(original_digraph): # 复制原图,避免修改原始数据 g = original_digraph.copy() # 循环处理,直到没有符合条件的直边节点 while True: # 收集当前所有无向度数为2的节点(排除自环节点) straight_nodes = [ node for node in g.nodes() if len(list(nx.all_neighbors(g, node))) == 2 and not g.has_edge(node, node) ] if not straight_nodes: break for u in straight_nodes: # 获取该节点的两个邻居 neighbors = list(nx.all_neighbors(g, u)) v, w = neighbors[0], neighbors[1] # 合并边属性(示例:累加骨架长度,可根据实际需求调整) attr_vu = g.get_edge_data(v, u, default={}) attr_uw = g.get_edge_data(u, w, default={}) merged_attr = {} if 'length' in attr_vu and 'length' in attr_uw: merged_attr['length'] = attr_vu['length'] + attr_uw['length'] # 添加双向边,保持有向图的双向连通性 g.add_edge(v, w, **merged_attr) g.add_edge(w, v, **merged_attr) # 删除中间节点及其关联边 g.remove_node(u) return g
代码说明
- 原图复制:避免直接修改输入的原始骨架图数据,保证原始数据可回溯。
- 循环处理逻辑:删除一个直边节点后,其邻居的度数可能变为2,需要重复检测处理,直到没有符合条件的节点。
- 直边节点判定:用
nx.all_neighbors()获取节点的所有邻居(忽略边的方向),长度为2的节点即为需要合并的中间节点;度数为1的端点节点不会被纳入处理列表,自然保留。 - 双向边添加:针对DiGraph的需求,合并后给两个邻居互相添加边,保持原骨架的无向连通特性。
- 边属性合并:如果原骨架边带有属性(比如长度、权重),可以通过累加或其他逻辑合并,示例中处理了
length属性,可根据实际需求修改。
使用示例
假设你从skan生成的骨架已转成DiGraph格式的original_g,调用函数即可得到简化后的图:
simplified_g = merge_straight_edges(original_g)
注意事项
- 如果骨架图存在环(所有节点度数均为2),该函数会将环简化为双向连通的两个节点;若需要保留环的完整结构,可在代码中添加环的判定逻辑跳过处理。
- 若原边有其他自定义属性(如颜色、标记),需调整
merged_attr的逻辑来合并这些属性。
内容的提问来源于stack exchange,提问作者Gomorra
相关产品推荐
相关产品推荐

