pydot: 是否可能在两个不同的节点中绘制相同的字符串?

11
我使用pydot在Python中绘制图形。我想表示一个决策树,例如(a1、a2、a3是属性,两个类别是0和1:
       a1>3
      /    \
  a2>10    a3>-7
   /  \     /  \
  1    0   1    0

然而,使用pydot只创建了两个叶子,树的样子如下(附带png):

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

现在,在这种简单的情况下,逻辑是正确的,但在更大的树中,它会变得混乱,因为属于不同分支的内部节点被统一了。

我正在使用的简单代码是:

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')

我也尝试过创建与创建边缘不同的节点对象,然后将其添加到图形中,但似乎 pydot 会检查节点池中是否存在同名的节点,而不是创建一个新节点。

有什么想法吗?谢谢!

由上述代码创建的图像

2个回答

17

您的节点必须始终具有唯一的名称,否则您无法将它们命名为唯一的并在它们之间添加边缘。然而,您可以为每个节点分配一个标签,这是呈现时显示的内容。

因此,您需要添加具有唯一标识的节点:

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'))

然后添加连接这些节点的图边:

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)

除了您定义的其余边缘之外,这样做:

具有正确边缘的图形


2
“规范”的答案是使用标准库中的uuid模块,就像networkx在此处做的一样。
这比使用idpydot创建节点名称更好,因为如果(理论上)在构建pydot图时删除了节点对象,则该id不一定是唯一的。相反,创建的UUID对象是唯一的、持久的,并独立于原始节点的生命周期。
然而,要发生这种情况,您在创建pydot图时必须正在进行某些非常奇怪的事情,这相当不可能。使用id的优点是您无需构建并传递从原始节点到UUID对象的映射(因此您可以在添加节点后一致地构造边缘)。
一个有趣的例子是嵌套图:两个不同的图可能包含networkx中相同的可哈希对象(假设为a),那么id就不能再直接用于该节点。但在这种情况下,id仍然可以被使用,通过将(节点,图)对组合成:str(id(node)) + str(id(graph))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接