2013-03-12 6 views
4

Можно ли изменить следующий код, чтобы поставить Child_4 на тот же горизонтальный уровень, что и Grandchild_0 (тем самым нажав Grandchild_4 на собственный уровень)?Программно указывающие узлы того же ранга в оболочке networkx для pygraphviz/dot

import networkx as nx 
import matplotlib.pyplot as plt 

G = nx.DiGraph() 
G.add_node("ROOT") 
for i in xrange(5): 
    G.add_node("Child_%i" % i) 
    G.add_node("Grandchild_%i" % i) 
    G.add_edge("ROOT", "Child_%i" % i) 
    G.add_edge("Child_%i" % i, "Grandchild_%i" % i) 

pos=nx.graphviz_layout(G,prog='dot') 
nx.draw(G,pos,arrows=False) 
plt.show() 

Приведенный выше код производит следующий макет, который я хотел бы изменить, перемещая ребенка на один уровень вниз, чтобы быть выровнены по горизонтали с внуками: img shows a root node, five children, and a single grandchild beneath each child


В сети Python library networkx, я использую графический движок graphviz для рендеринга дерева (после this recommendation). Я хотел бы управлять y-позицией узлов, указав, какие узлы должны иметь одинаковую высоту. Узлы могут находиться на разных глубинах в дереве.

Я знаю, что могу управлять высотой узла, если я написал свой собственный код graphviz, используя команду rank=same (например, {rank=same; n4 -> p2;} [ex.]). Тем не менее, я полагаюсь на networkx.graphviz_layout() [doc | source] для генерации позиций узлов, а graphviz_layout может отправлять только аргументы командной строки pygraphviz. Мои попытки использовать варианты nx.graphviz_layout(G, prog='dot', args="-Grank=same; n4 -> p2;") не удались. Возможно ли описать требуемые высоты узлов в оболочке NetworkX для pygraphviz, или мне нужно написать собственную обертку вокруг pygraphviz? Редактировать: Ответ представляет новую оболочку вокруг pygraphviz. Это значительно упростит отправку информации о ранге в существующую оболочку NetworkX для pygraphviz. Я изменю принятый ответ, если кто-нибудь скажет мне, как это возможно.

ответ

3

Я не могу найти способ добиться этого через оригинальную упаковку networkx.

Вместо этого я написал новую обертку для pygraphviz, с большинством строк, скопированных с the source code. Он добавляет параметр sameRank = [] для списка списков узлов с одинаковым рангом и цикла for вокруг вызова pygraphviz.add_subgraph(listOfNodes,rank="same").

def graphviz_layout_with_rank(G, prog = "neato", root = None, sameRank = [], args = ""): 
    ## See original import of pygraphviz in try-except block 
    ## See original identification of root through command line 
    A = nx.to_agraph(G) 
    for sameNodeHeight in sameRank: 
     if type(sameNodeHeight) == str: 
      print("node \"%s\" has no peers in its rank group" %sameNodeHeight) 
     A.add_subgraph(sameNodeHeight, rank="same") 
    A.layout(prog=prog, args=args) 
    ## See original saving of each node location to node_pos 
    return node_pos 

В примере вопроса, Child_4 могут быть прижаты к одной и той же горизонтальном уровне, Grandchild_0 через линию:

pos=graphviz_layout_with_rank(G, prog='dot',sameRank=[["Child_4","Grandchild_0"]])