pydot: можно ли построить два разных узла с одной и той же строкой?

Я использую 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 проверяет пул узлов на наличие узлов с тем же именем вместо создания нового.

Любые идеи? Благодарность!

изображение, созданное указанным выше кодом


person ScienceFriction    schedule 22.10.2012    source источник


Ответы (2)


Вашим узлам всегда нужны уникальные имена, иначе вы не сможете дать им однозначное имя, чтобы соединить ребра между ними. Однако вы можете дать каждому узлу метку, которая будет отображаться при рендеринге.

Поэтому вам нужно добавить узлы с уникальными идентификаторами:

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)

Вместе с остальными краями, которые вы определили, это дает:

граф с правильными ребрами

person Martijn Pieters    schedule 22.10.2012

"Канонический" ответ - использовать модуль uuid из стандартной библиотеки, поскольку networkx здесь.

Это лучше, чем использование id для создания имен узлов для pydot, соответствующих узлы в исходном графе, потому что если (теоретически) объект узла будет удален во время построения вашего pydot графа, то этот id не обязательно будет уникальным. Напротив, созданные UUID объекты уникальны, постоянны и не зависят от срока службы исходных узлов.

Однако, чтобы это произошло, во время создания графика pydot должно происходить что-то очень странное, что маловероятно. Преимущество использования id состоит в том, что вам не нужно строить и передавать отображение от исходных узлов к UUID объектам (так что вы строите последовательно ребра после добавления узлов).

Один интересный случай - вложенные графы: два разных графа могут содержать один и тот же хешируемый объект в networkx (скажем, a), тогда id больше не может использоваться непосредственно на узле. Но в этом случае id все еще можно использовать, объединив пару (узел, граф) как: str(id(node)) + str(id(graph)).

person Ioannis Filippidis    schedule 10.09.2014