在使用networkx打印Python图形时保留左子对象和右子对象

2022-03-31 00:00:00 python networkx graph pygraphviz tree

问题描述

我正在尝试使用python中的networkx库打印二叉树。

但是,我无法保存左右两个孩子。是否有方法告诉Graph先打印左侧子项,然后打印右侧子项?

import networkx as nx
G = nx.Graph()
G.add_edges_from([(10,20), (11,20)])
nx.draw_networkx(G)

编辑1:在使用pygraph wiz时,它至少会生成有向图。因此,我对根节点有了更好的了解。

下面是我使用的代码:

import pygraphviz as pgv
G = pgv.AGraph()
G.add_node('20')
G.add_node('10')
G.add_node('11')
G.add_edge('20','10')
G.add_edge('20','11')
G.add_edge('10','7')
G.add_edge('10','12')

G.layout()
G.draw('file1.png')
from IPython.display import Image
Image('file1.png')

但是,这还远远不是一个结构化的格式。接下来我会发布我的发现。新图形如下所示(至少我们知道根):

编辑2:对于那些面临安装问题的人,请refer to this post.The answer to this-如果您想在Windows 64位上安装pygraph viz,这将非常有用。


解决方案

注意如果您使用的是Networkx1.11版或更早版本,请参阅结尾处的注释。

下面假设每个节点都有一个属性分配给它,该属性告诉它是其父节点的左子节点还是右子节点。因此,您必须指定这一点--默认情况下,图形没有任何这方面的概念。也许有可能说服networkx的人们制作一种新的图形,它是一棵二叉树,自动存储这些信息,但目前还不存在。我不知道是否会有足够的兴趣来证明这一点。

import networkx as nx

def binary_tree_layout(G, root, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5, 
                  pos = None, parent = None):
    '''If there is a cycle that is reachable from root, then this will see infinite recursion.
       G: the graph
       root: the root node of current branch
       width: horizontal space allocated for this branch - avoids overlap with other branches
       vert_gap: gap between levels of hierarchy
       vert_loc: vertical location of root
       xcenter: horizontal location of root
       pos: a dict saying where all nodes go if they have been assigned
       parent: parent of this branch.
       each node has an attribute "left: or "right"'''
    if pos == None:
        pos = {root:(xcenter,vert_loc)}
    else:
        pos[root] = (xcenter, vert_loc)
    neighbors = list(G.neighbors(root))
    if parent != None:
        neighbors.remove(parent)
    if len(neighbors)!=0:
        dx = width/2.
        leftx = xcenter - dx/2
        rightx = xcenter + dx/2
        for neighbor in neighbors:
            if G.nodes[neighbor]['child_status'] == 'left':
                pos = binary_tree_layout(G,neighbor, width = dx, vert_gap = vert_gap, 
                                    vert_loc = vert_loc-vert_gap, xcenter=leftx, pos=pos, 
                    parent = root)
            elif G.nodes[neighbor]['child_status'] == 'right':
                pos = binary_tree_layout(G,neighbor, width = dx, vert_gap = vert_gap, 
                                    vert_loc = vert_loc-vert_gap, xcenter=rightx, pos=pos, 
                    parent = root)
    return pos

以下是我将偶数节点转换为左子节点的示例调用。

G= nx.Graph()
G.add_edges_from([(0,1),(0,2), (1,3), (1,4), (2,5), (2,6), (3,7)])
for node in G.nodes():
    if node%2==0:
        G.nodes[node]['child_status'] = 'left'  #assign even to be left
    else:
        G.nodes[node]['child_status'] = 'right' #and odd to be right
pos = binary_tree_layout(G,0)
nx.draw(G, pos=pos, with_labels = True)


编辑备注此答案的早期版本适用于Networkx版本1.11及更早版本。如果需要,请打开编辑历史记录并使用此答案的第二个版本。

相关文章