Pydot: is it possible to build two different nodes in it with the same string?

I am using pydot to draw graphs in python. I would like to introduce a decision tree, say, something like (a1, a2, a3 are attributes, and two classes are 0 and 1:

a1>3 / \ a2>10 a3>-7 / \ / \ 1 0 1 0 

However, using pydot, only two sheets are created, and the tree looks like this (png attached):

  a1>3 / \ a2>10 a3>-7 | X | 1 0 

Now, in this simple case, the logic is beautiful, but in large trees these dirty internal nodes belonging to different branches are unified.

Simple code that I use:

 import pydot graph = pydot.Dot(graph_type='graph') edge = pydot.Edge("a_1>3", "a_2>10") graph.add_edge(edge) edge = pydot.Edge("a_1>3", "a_3>-7") graph.add_edge(edge) edge = pydot.Edge("a_2>10", "1") graph.add_edge(edge) edge = pydot.Edge("a_2>10", "0") graph.add_edge(edge) edge = pydot.Edge("a_3>-7", "1") graph.add_edge(edge) edge = pydot.Edge("a_3>-7", "0") graph.add_edge(edge) graph.write_png('simpleTree.png') 

I also tried to create different node objects than to create edges and then add it to the graph, but it seems that pydot is checking the node pool for nodes of the same name instead of creating a new one.

Any ideas? thanks!

the image created by the code above

+8
python decision-tree pydot
source share
2 answers

Your nodes always need unique names, otherwise you cannot unambiguously name them to connect the edges between them. However, you can give each node a label that is displayed during rendering.

So, you need to add nodes with unique identifiers:

 graph = pydot.Dot(graph_type='graph') graph.add_node(pydot.Node('literal_0_0', label='0')) graph.add_node(pydot.Node('literal_0_1', label='0')) graph.add_node(pydot.Node('literal_1_0', label='1')) graph.add_node(pydot.Node('literal_1_1', label='1')) 

then add the edges of the graph connecting these nodes:

 edge = pydot.Edge("a_2>10", "literal_0_0") graph.add_edge(edge) edge = pydot.Edge("a_2>10", "literal_1_0") graph.add_edge(edge) edge = pydot.Edge("a_3>-7", "literal_0_1") graph.add_edge(edge) edge = pydot.Edge("a_3>-7", "literal_1_1") graph.add_edge(edge) 

Together with the rest of the edges that you have defined, this does:

graph with correct edges

+13
source share

The "canonical" answer is to use the uuid module from the standard library, since networkx here .

This is better than using id to create the node names for pydot that correspond to the nodes of the source graph, because if (theoretically) the node object is deleted when the pydot graph is pydot , then the id will not necessarily be unique. In contrast, the uuid objects created are unique, persistent, and independent of the lifespan of the source nodes.

However, for this, something very strange must happen when you create a pydot graph, which is unlikely. The advantage of using id is that you do not need to create and skip the mapping from the source nodes to uuid objects (so that you consistently construct the edges after adding the nodes).

One interesting case is nested graphs: two different graphs can contain the same hashable object in networkx (say, a ), then id can no longer be used directly on node. But in this case, id can still be used by combining a pair (node, graph) like: str(id(node)) + str(id(graph)) .

+1
source share

All Articles