有没有一种方法可以使用 pydot 生成一个看起来像“普通 TreeMap ”的有向 TreeMap ,其中相同深度的每个节点都以相同的深度显示,并且每条边都处于某个角度(不是直下)?
当我使用这些默认值时:
graph = pydot.Dot(graph_type='digraph', nodesep=.75)
graph.set_node_defaults(style="filled", fillcolor="grey")
graph.set_edge_defaults(color="blue", arrowhead="vee", weight="0")
节点 2 和 1 之间的边长度太长。请参阅:
我可以使用边权重“1”来校正节点的长度,例如:
graph.set_edge_defaults(color="blue", arrowhead="vee", weight="1")
但是现在 2 和 3、7 和 6 之间的两条边直接指向下方。请参阅:
事实证明,笔直向下的边缘是一个真正的问题。如果左右兄弟都没有绘制,那么就不清楚绘制哪个节点(左或右)。
PS:在我之前关于同一项目的问题中,我询问如何控制边缘的角度,以便 pydot 生成的 TreeMap 可以避免边缘直接向下指向。这个问题“盖伊”很好地回答了。使用不可见节点实现盖伊的解决方案后,出现了一个新的副作用:某些图上的某些边的长度太长。这是之前问题的链接供引用:Is there a way to control line angle when producing graphs with pyDot最佳答案
要正确控制 pydot 有向图的节点位置和边长,以便在指向同一方向时边彼此平行,没有边直接向下,并且所有节点都绘制到适当的级别 - 必须使用不可见节点。
在之前关于“如何控制线角度...”主题的 SO Q/A session 中,我了解到不可见节点用于填充缺失的叶节点。这对某些树木有效,但有一些副作用。
现在,我学会了向每个具有左右节点的节点添加第三个不可见节点。请注意,不可见节点不会添加到树中,而只是绘制到图中。所以树仍然可以用于搜索、插入、删除等方法。
这是一个展示解决方案的 graphviz 示例:
digraph {
nodesep=0.35
ordering=out
node[style="filled", fillcolor="grey"]
edge[color="blue", arrowhead="vee"]
{ node[shape=point style=invis] m5 m2 m8 m6 m4 }
5 -> 2
5 -> m5 [weight=100 style=invis]
5 -> 8
2 -> 1
2 -> m2 [weight=100 style=invis]
2 -> 4
8 -> 6
8 -> m8 [weight=100 style=invis]
4 -> 3
4 -> m4 [weight=100 style=invis]
6 -> m6 [weight=100 style=invis]
6 -> 7
}
这是我更新的 python 代码片段,用于使用典型的树类自动执行此过程:
vT = visualizeTree(0, fileDir, 'bst_graph','.png',1) # instantiate the visualizeTree Object
graph = pydot.Dot(graph_type='digraph', nodesep=.5, pad=.3, size="19.2, 10.1")
graph.set_node_defaults(style="filled", fillcolor="grey")
graph.set_edge_defaults(color="blue", arrowhead="vee")
vT.searchTree(root, sketchTree)
vT.updateGraph()
class visualizeTree(object):
# more code and comments located at project home
def __init__(self, fileCount, fileDir, fileName, fileExt, vidFrames):
def sketchTree(node, stack, find=None, draw=None):
if node.getLeftBranch():
draw(str(node), str(node.getLeftBranch()))
stack.append(node.getLeftBranch())
if node.getRightBranch():
# insert invisible third node in-between left and right nodes
draw(str(node), ":"+str(node), style_type="invisible")
elif node.getRightBranch():
# draw any missing left branches as invisible nodes/edges with dummy unique labels
draw(str(node), ":"+str(node), style_type="invisible")
if node.getRightBranch():
draw(str(node), str(node.getRightBranch()))
stack.append(node.getRightBranch())
elif node.getLeftBranch():
# draw any missing right branches as invisible nodes/edges with dummy unique labels
draw(str(node), ";"+str(node), style_type="invisible")
def draw(self, parent_name, child_name, fill_color="grey", style_type='filled'):
if style_type=="invisible":
# save original edge defaults
weight_ = "100"
saveEdgeDefaults = graph.get_edge_defaults()[0]
graph.set_edge_defaults(style=style_type, color="white", arrowhead="none")
else:
weight_ = "3"
edge = pydot.Edge(parent_name, child_name, style=style_type, weight=weight_)
graph.add_edge(edge)
if style_type=="invisible":
graph.set_edge_defaults(**saveEdgeDefaults)
if not self.nodeNames:
self.nodeNames[parent_name] = pydot.Node(parent_name, label=parent_name, fillcolor=fill_color, style=style_type)
graph.add_node(self.nodeNames[parent_name])
if (parent_name not in self.nodeNames):
self.nodeNames[parent_name] = pydot.Node(parent_name, label=parent_name, fillcolor=fill_color, style=style_type)
graph.add_node(self.nodeNames[parent_name])
if child_name not in self.nodeNames:
self.nodeNames[child_name] = pydot.Node(child_name, label=child_name, fillcolor=fill_color, style=style_type)
graph.add_node(self.nodeNames[child_name])
完整的源代码可以在项目主页找到: http://www.embeddedcomponents.com/blogs/2013/12/visualizing-software-tree-structures/
典型的小图像现在可以按照我想要的方式绘制:
即使是大树也可以用类似的几何形状来绘制:
关于python - 需要控制pydot边长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20697032/