You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

绘制含公共节点的层级树时触发Python RecursionError问题

解决NetworkX绘制层级结构时的RecursionError问题

这问题我之前也碰到过,本质是你的图结构和布局函数的适配性出了问题,我帮你拆解下原因和解决办法:

问题根源

你现在用的是nx.Graph()(无向图),但_hierarchy_pos这个函数是为严格树结构设计的——树的特点是无环,且每个节点(除根节点外)只有一个父节点。

当多个分支指向同一个公共节点(比如B和C都指向G)时,无向图会给G和B、C建立双向连接。递归布局时,程序会陷入A→B→G→B→A→C→G→C→...的无限循环,直接触发Python的递归深度限制,也就是你看到的RecursionError。

解决方案

这里有几个可行的思路,你可以根据需求选择:

1. 改用有向图(最简单的修复)

把图换成nx.DiGraph()(有向图),让边保持单向性,同时给_hierarchy_pos加个小过滤,避免递归回溯父节点:

import networkx as nx
import matplotlib.pyplot as plt
import time

timestr = time.strftime("%Y%m%d-%H%M%S")

def _hierarchy_pos(G, root=None, width=1., vert_gap=0.2, vert_loc=0, xcenter=0.5,
                  pos=None, parent=None):
    if pos is None:
        pos = {root: (xcenter, vert_loc)}
    else:
        pos[root] = (xcenter, vert_loc)
    # 获取当前节点的邻居,移除父节点防止回溯
    children = list(G.neighbors(root))
    if parent is not None and parent in children:
        children.remove(parent)
    if not children:
        return pos
    dx = width / len(children)
    nextx = xcenter - width/2 - dx/2
    for child in children:
        nextx += dx
        pos = _hierarchy_pos(G, child, width=dx, vert_gap=vert_gap,
                            vert_loc=vert_loc-vert_gap, xcenter=nextx,
                            pos=pos, parent=root)
    return pos

def Create_Hierarchy(chunks):
    # 替换为有向图
    G = nx.DiGraph()
    G.add_edges_from(chunks)
    pos = _hierarchy_pos(G, root='A', width=0.07, vert_gap=0.02, vert_loc=0.09, xcenter=0.50)
    nx.draw(G, pos, arrows=True, with_labels=True)
    plt.subplots_adjust(top=0.9, wspace=4.0, hspace=2.99)
    plt.savefig(f'D:\\Hierarchy{timestr}.png')
    plt.show()

Create_Hierarchy(chunks=[('A','B'), ('A','C'), ('A','D'), ('A','E'), ('A','F'), ('B','G'), ('C','G'), ('D','I'), ('E','J'), ('F','K')])

2. 使用DAG专用布局(更专业的选择)

你的结构其实是有向无环图(DAG),不是严格的树。用NetworkX结合Graphviz的dot布局会更适合这种多分支汇聚的场景,布局效果也更规整:
首先需要安装依赖:

  • 下载安装Graphviz软件(对应你的系统版本)
  • 安装Python库:pip install graphviz

然后修改代码:

import networkx as nx
import matplotlib.pyplot as plt
import time

timestr = time.strftime("%Y%m%d-%H%M%S")

def Create_Hierarchy(chunks):
    G = nx.DiGraph()
    G.add_edges_from(chunks)
    # 用Graphviz的dot布局自动处理DAG层级
    pos = nx.nx_agraph.graphviz_layout(G, prog='dot')
    nx.draw(G, pos, arrows=True, with_labels=True)
    plt.subplots_adjust(top=0.9, wspace=4.0, hspace=2.99)
    plt.savefig(f'D:\\Hierarchy{timestr}.png')
    plt.show()

Create_Hierarchy(chunks=[('A','B'), ('A','C'), ('A','D'), ('A','E'), ('A','F'), ('B','G'), ('C','G'), ('D','I'), ('E','J'), ('F','K')])

3. 给递归函数加访问标记(兼容无向图的方案)

如果你一定要用无向图,可以在_hierarchy_pos里加个已访问集合,避免重复遍历同一个节点:

def _hierarchy_pos(G, root=None, width=1., vert_gap=0.2, vert_loc=0, xcenter=0.5,
                  pos=None, parent=None, visited=None):
    if visited is None:
        visited = set()
    visited.add(root)
    if pos is None:
        pos = {root: (xcenter, vert_loc)}
    else:
        pos[root] = (xcenter, vert_loc)
    # 只遍历未访问过的邻居
    children = [child for child in G.neighbors(root) if child not in visited]
    if not children:
        return pos
    dx = width / len(children)
    nextx = xcenter - width/2 - dx/2
    for child in children:
        nextx += dx
        pos = _hierarchy_pos(G, child, width=dx, vert_gap=vert_gap,
                            vert_loc=vert_loc-vert_gap, xcenter=nextx,
                            pos=pos, parent=root, visited=visited)
    return pos

总结

核心问题就是无向图的双向边导致递归无限循环,要么换成有向图切断反向边,要么用更适合DAG的布局算法,要么给递归加访问标记避免重复遍历。

内容的提问来源于stack exchange,提问作者Chits

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:47:29