1

pydot を使用して、同じ深さのすべてのノードが同じ深さで表示され、すべてのエッジが一定の角度 (真下ではない) である「通常のツリー グラフ」のように見える有向ツリー グラフを生成する方法はありますか?

これらのデフォルトを使用する場合:

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 つが 2 と 3、および 7 と 6 の間でまっすぐ下を向いています。以下を参照してください。 ここに画像の説明を入力

真っ直ぐ下を向いているエッジは、実際の問題であることが判明しました。左右の兄弟が両方とも描画されない場合、どちらのノード (左または右) が描画されるかは明確ではありません。

PS: この同じプロジェクトに関する以前の質問で、pydot で生成されたツリー グラフでエッジが真下を向かないように、エッジの角度を制御する方法を尋ねました。その質問は、「Guy」によって非常によく答えられました。目に見えないノードを使用してガイのソリューションを実装した後、新しい副作用が発生しました。一部のグラフの一部のエッジの長さが長すぎます。参照用の前の質問へのリンクは次のとおりです。 pyDot でグラフを作成するときに線の角度を制御する方法はありますか

4

1 に答える 1

2

pydot digraph のノードの位置とエッジの長さを適切に制御して、同じ方向を指しているときにエッジが互いに平行になり、エッジが真下を向かないようにし、すべてのノードが適切なレベルに描画されるようにするには、非表示のノードを使用する必要があります。

このトピック「線の角度を制御する方法...」に関する以前の SO Q/A セッションで、見えないノードを使用して欠落しているリーフ ノードを埋めることを学びました。これは一部のツリーで機能しますが、いくつかの副作用がありました。

これで、左右両方のノードを持つ各ノードに 3 番目の非表示ノードを追加する方法を学習しました。目に見えないノードはツリーに追加されませんが、グラフに描画されるだけです。そのため、ツリーは引き続き検索、挿入、削除、およびその他の方法で使用できます。

ソリューションを示すグラフビズの例を次に示します。

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/

典型的な小さな画像は、そもそも私が望んでいたように描画されるようになりました: 二分探索木

大きな木でさえ、同様のジオメトリで描画できます。 順序付けられた検索トレイルを持つより大きな二分探索木

于 2013-12-26T05:42:40.523 に答える