我正在尝试使用python中的networkx库打印二叉树。
但是,我无法保留左右孩子。有没有办法告诉图表先打印左边的孩子然后打印正确的孩子?
import networkx as nx
G = nx.Graph()
G.add_edges_from([(10,20), (11,20)])
nx.draw_networkx(G)
编辑1:在使用pygraphwiz时,它会生成至少一个有向图。所以,我有更好的根节点图片。
以下是我正在使用的代码:
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位上安装pygraphviz,这非常有用。
答案 0 :(得分:1)
我认为Networkx不适合二叉树,但您可以自己设置节点位置。我已经编写了以下算法来设置节点位置,但它适用于完整或完整的二叉树,其中关键节点是有序的[0,1,...]。
def full_tree_pos(G):
n = G.number_of_nodes()
if n == 0 : return {}
# Set position of root
pos = {0:(0.5,0.9)}
if n == 1:
return pos
# Calculate height of tree
i = 1
while(True):
if n >= 2**i and n<2**(i+1):
height = i
break
i+=1
# compute positions for children in a breadth first manner
p_key = 0
p_y = 0.9
p_x = 0.5
l_child = True # To indicate the next child to be drawn is a left one, if false it is the right child
for i in xrange(height):
for j in xrange(2**(i+1)):
if 2**(i+1)+j-1 < n:
print 2**(i+1)+j-1
if l_child == True:
pos[2**(i+1)+j-1] = (p_x - 0.2/(i*i+1) ,p_y - 0.1)
G.add_edge(2**(i+1)+j-1,p_key)
l_child = False
else:
pos[2**(i+1)+j-1] = (p_x + 0.2/(i*i+1) ,p_y - 0.1)
l_child = True
G.add_edge(2**(i+1)+j-1,p_key)
p_key += 1
(p_x,p_y) = pos[p_key]
return pos
G = nx.Graph()
G.add_nodes_from(xrange(25))
pos = full_tree_pos(G)
nx.draw(G, pos=pos, with_labels=True)
plt.show()
答案 1 :(得分:0)
以下假设每个节点都分配了一个属性,告诉它是父节点的左子节点还是右子节点。所以你必须分配它 - 默认情况下,图形没有任何这个概念。也许有可能说服网络人员制作一个新的图形图表,它是一个二叉树并自动存储这些信息,但目前,它并不存在。我不知道是否有足够的兴趣证明这一点。
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 = 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.node[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.node[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.node[node]['child_status'] = 'left' #assign even to be left
else:
G.node[node]['child_status'] = 'right' #and odd to be right
pos = binary_tree_layout(G,0)
nx.draw(G, pos=pos, with_labels = True)