'Rendering a tree in python using anytree and graphviz, without merging common nodes
I am creating a tree from a list ["abc", "abd", "aec", "add", "adcf"]
using anytree package of python3. In this tree first character of each list element - a
is a root, and subsequently, other characters are added as their children. When I render tree it looks like:
a
├── b
│ ├── c
│ └── d
├── e
│ └── c
└── d
├── d
└── c
└── f
But when I render the tree to picture using to_picture
method, the image is -
I don't want the common nodes to be merged, as it is adding unwanted paths to my tree.
Solution 1:[1]
The node are arranged in graphviz
using their id. In your case the graph is generated with just node names and then graphviz
created the loop edge as you get it.
What you really want is different id
for each node and a label
associated with the same. The DotExporter
class has a attribute named nodeattrfunc
to which we can pass a function or a lambda and generate attributes for the nodes
Below is how you would do it based on your array
import anytree
from anytree import Node, RenderTree
data = ["abc", "abd", "aec", "add", "adcf"]
from anytree.exporter import DotExporter
nodes = {}
first_node = None
for elem in data:
parent_node = None
parent_node_name = ""
for i, val in enumerate(elem):
if i not in nodes:
nodes[i] = {}
key = parent_node_name + val
if key not in nodes[i]:
print("Creating new node for ", key)
nodes[i][key] = Node(key, parent=parent_node, display_name=val)
if first_node is None:
first_node = nodes[i][key]
parent_node = nodes[i][key]
parent_node_name = val
print(nodes)
DotExporter(nodes[0]["a"],
nodeattrfunc=lambda node: 'label="{}"'.format(node.display_name)).to_dotfile("graph.txt")
DotExporter(nodes[0]["a"],
nodeattrfunc=lambda node: 'label="{}"'.format(node.display_name)).to_picture("graph.png")
This will generate the below dot file
digraph tree {
"a" [label="a"];
"ab" [label="b"];
"bc" [label="c"];
"bd" [label="d"];
"ae" [label="e"];
"ec" [label="c"];
"ad" [label="d"];
"dd" [label="d"];
"dc" [label="c"];
"cf" [label="f"];
"a" -> "ab";
"a" -> "ae";
"a" -> "ad";
"ab" -> "bc";
"ab" -> "bd";
"ae" -> "ec";
"ad" -> "dd";
"ad" -> "dc";
"dc" -> "cf";
}
And the below graph
Solution 2:[2]
As anytree
to_picture()
function use graphviz to generate the file.
From here = similar question, you can read :
graphviz uses the node id as label. If distinct nodes need to have the same label, the label has to be defined explicitly.
Solution 3:[3]
I was about to implement the recommended fix but found that using UniqueDotExporter dealt with the repeated ids perfectly!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Tarun Lalwani |
Solution 2 | A STEFANI |
Solution 3 | notsamdonald |