[英]How to convert from NetworkX graph to ete3 Tree object?
我試圖弄清楚如何從networkx
向圖構建ete3.Tree
對象? 我以我認為會產生預期結果的方式添加了每個child
,但是我遇到了麻煩。
edges = [('lvl-1', 'lvl-2.1'), ('lvl-1', 'lvl-2.2'), ('lvl-2.1', 'lvl-3.1'), ('lvl-2.1', 2), ('lvl-2.2', 4), ('lvl-2.2', 6), ('lvl-3.1', 'lvl-4.1'), ('lvl-3.1', 5), ('lvl-4.1', 1), ('lvl-4.1', 3), ('input', 'lvl-1')]
graph = nx.OrderedDiGraph()
graph.add_edges_from(edges)
nx.draw(graph, pos=nx.nx_agraph.graphviz_layout(graph, prog="dot"), with_labels=True, node_size=1000, node_color="lightgray")
tree = ete3.Tree()
for parent, children in itertools.groupby(graph.edges(), lambda edge:edge[0]):
subtree = ete3.Tree(name=parent)
for child in children:
subtree.add_child(name=child[1])
tree.add_child(child=subtree, name=parent)
print(tree)
# /-lvl-2.1
# /-|
# | \-lvl-2.2
# |
# | /-lvl-3.1
# |--|
# | \-2
# |
# | /-4
# |--|
# --| \-6
# |
# | /-lvl-4.1
# |--|
# | \-5
# |
# | /-1
# |--|
# | \-3
# |
# \- /-lvl-1
我也嘗試了以下方法,但是沒有用:
tree = ete3.Tree()
for parent, child in graph.edges():
if parent not in tree:
tree.add_child(name=parent)
subtree = tree.search_nodes(name=parent)[0]
subtree.add_child(name=child)
print(tree)
# /-1
# /-|
# /-| \-3
# | |
# /-| \-5
# | |
# /-| \-2
# | |
# | | /-4
# --| \-|
# | \-6
# |
# \- /-lvl-1
# Graph
edges = [('lvl-1', 'lvl-2.1'), ('lvl-1', 'lvl-2.2'), ('lvl-2.1', 'lvl-3.1'), ('lvl-2.1', 2), ('lvl-2.2', 4), ('lvl-2.2', 6), ('lvl-3.1', 'lvl-4.1'), ('lvl-3.1', 5), ('lvl-4.1', 1), ('lvl-4.1', 3), ('input', 'lvl-1')]
G = nx.OrderedDiGraph()
G.add_edges_from(edges)
# Tree
root = "input"
subtrees = {node:ete3.Tree(name=node) for node in G.nodes()}
[*map(lambda edge:subtrees[edge[0]].add_child(subtrees[edge[1]]), G.edges())]
tree = subtrees[root]
print(tree.get_ascii())
# /-1
# /lvl-4.1
# /lvl-3.1 \-3
# | |
# /lvl-2.1 \-5
# | |
# -inputlvl-1 \-2
# |
# | /-4
# \lvl-2.2
# \-6
子樹和從networkX對象讀取都是可以的,問題是您將所有子tree
直接添加到原始tree
實例中。 在ete3中, Tree
類實際上只是一個Node (包括指向其后代的指針,如果有的話),因此tree.add_child
將新的子節點/子樹直接添加到根節點。
相反,您應該做的是遍歷ete樹的葉子 ,找到node.name == parent
樹 ,然后將所有子樹附加到該樹上 。 另外,您應該一個接一個地連接它們,而不是預先生成子樹。 否則,您將獲得具有單親和單子的附加內部節點。
代碼的第二個版本幾乎是正確的,但是您不能認為如果根不是它們的實際父節點,則永遠不要將節點附加到樹( 即根)上。 這可能就是為什么您將lvl-1
作為一個單獨的節點,而不是其他節點的父節點。 另外,我不確定networkX圖形的遍歷順序,這可能很重要。 更安全(如果較丑)的版本將如下所示:
# Setting up a root node for lvl-1 to attach to
tree.add_child(name='input')
# A copy in a list, because you may not want to edit the original graph
edges = list(graph.edges)
while len(edges) > 0:
for parent, child in edges:
# check if this edge's parent is in the tree
for leaf it tree.get_leaves():
if leaf.name == parent:
# if it is, add child and thus create an edge
leaf.add_child(name=child)
# Wouldn't want to add the same edge twice, would you?
edges.remove((parent, child))
# Now if there are edges still unplaced, try again.
那里可能有一些錯別字,而且絕對是超慢的。 由於邊緣計數或更差,在O(n ** 2)周圍發生了什么,所有迭代和列表刪除都發生了什么。 大概有一種方法可以將圖形從根到葉,這不需要邊緣列表的副本(並且可以在單個迭代中工作)。 但這最終會產生正確的樹。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.