【问题标题】:How to find all node's ancestors in NetworkX?如何在 NetworkX 中找到所有节点的祖先?
【发布时间】:2019-06-17 17:14:21
【问题描述】:

我有一个很大的DiGraph,其中包含相关作业。例如,对于图 a>b>c,作业 c 只能在作业 b 完成后运行。我试图找到一个函数来获取所有 c 的上游作业(即 (a, b))。我用DiGraph.predecessors,但它只返回工作b。

有没有列出所有 c 的上游作业的函数?

如何绘制叶节点(如作业 c)的依赖关系图?

我已阅读文档但找不到答案。

【问题讨论】:

    标签: python dependencies networkx directed-acyclic-graphs


    【解决方案1】:

    使用predecessors 只会将具有直接边的节点返回到输入节点。查找所有节点的ancestors可以如下:

    import networkx as nx
    import matplotlib.pyplot as plt
    G = nx.DiGraph()
    
    # G is:
    #      e-->f
    #      ^
    #      |
    # a--->b-->c-->d
    #
    
    G.add_edges_from([('a', 'b'),('b', 'c'),('c', 'd'), ('b', 'e'), ('e', 'f')])
    T = nx.dfs_tree(G.reverse(), source='f').reverse()     
    
    # T is: a-->b-->e-->f
    
    pos = nx.nx_pydot.pydot_layout(T, prog='dot')
    nx.draw_networkx(T, pos=pos, arrows= True, with_labels=True)
    plt.show()
    

    我们所做的只是从反转有向图上的输入节点运行 DFS,然后再次反转结果以使边沿其原始方向。

    最后三行用于绘制结果。

    【讨论】:

    • 我收到以下错误:AttributeError: 'Graph' object has no attribute 'predecessors'@zohar.kom
    • @alper 'predecessors' 适用于 DiGraph 对象,但不适用于 Graph 对象(有向图与无向图)。
    • 我收到以下错误:ModuleNotFoundError: No module named 'pydot'
    【解决方案2】:

    可能看起来很奇怪,但是这个函数叫做ancestors :)

    nx.ancestors(G, your_node)

    【讨论】:

    • 但要小心:Note that most of these functions are only guaranteed to work for DAGs. In general, these functions do not check for acyclic-ness, so it is up to the user to check for that. [来自文档]
    【解决方案3】:

    我在最近的一个项目中遇到了类似的问题,其中工作依​​赖于其他工作。我发现保证以正确顺序处理它们的最可靠方法是使用 DiGraph 方法topological_sort

    下面是一个最小的例子,从有向图的创建开始:

    import networkx as nx
    import matplotlib.pyplot as plt
    from networkx.drawing.nx_pydot import graphviz_layout
    
    # this function is optional
    # just moves the node labels on the plot so they don't overlap the lines 
    def nudge(pos, x_shift, y_shift):
        return {n:(x + x_shift, y + y_shift) for n,(x,y) in pos.items()} 
    
    # start with a directed graph
    dag = nx.DiGraph()
    
    dag.add_edges_from(
        [
            ('root', 'a'), 
            ('a', 'b'),
            ('a', 'c'),
            ('b', 'd'),
            ('d', 'e'),
            ('d', 'f')
        ]
    )
    
    # plot the graph
    pos = graphviz_layout(dag, prog="dot")
    pos_labels = nudge(pos, -5, 15)
    
    fig = plt.figure(figsize=(8, 6))
    ax = plt.subplot(1, 1, 1)
    plt.margins(0.1)
    
    nx.draw(
        dag, 
        pos=pos,
        ax=ax,
        with_labels=False,
        arrows=True,
        node_size=100, 
        arrowsize=20
    )
    
    labels = nx.draw_networkx_labels(
        dag,
        pos=pos_labels,
        ax=ax,
        font_size=18,
        font_weight='bold', 
        font_color='orange',
        verticalalignment='bottom'
    )
    

    图形的输出图如下:

    首先要做的最好的事情可能是验证图是有向无环图:

    nx.is_directed_acyclic_graph(dag)
    

    这将返回 True 或 False。接下来,我们可以使用topological_sort按依赖顺序检索节点:

    list(nx.algorithms.topological_sort(dag))
    

    这会返回:

    ['root', 'a', 'b', 'c', 'd', 'e', 'f']

    如果您希望拥有边对而不仅仅是节点:

    list(nx.topological_sort(nx.line_graph(dag)))
    

    返回:

    [('root', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'd'), ('d', 'e'), ('d', 'f')]

    最后,如果作业需要倒序,您可以使用reverse

    dag_reverse = dag.reverse()
    

    重新运行命令::

    list(nx.algorithms.topological_sort(dag_reverse))
    

    给予:

    ['c', 'e', 'f', 'd', 'b', 'a', 'root']

    和:

    list(nx.topological_sort(nx.line_graph(dag_reverse)))
    

    给予:

    [('c', 'a'), ('e', 'd'), ('f', 'd'), ('d', 'b'), ('b', 'a'), ('a', 'root')]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多