首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将NetworkX图转换为ete3树对象?

如何将NetworkX图转换为ete3树对象?
EN

Stack Overflow用户
提问于 2018-07-10 21:06:22
回答 2查看 2K关注 0票数 2

我试图弄清楚如何从一个ete3.Tree有向图构建一个networkx对象?我以我认为会产生预期结果的方式添加了每个child,但我遇到了麻烦。

代码语言:javascript
复制
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")

代码语言:javascript
复制
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

我也尝试过以下几种方法,但没有奏效:

代码语言:javascript
复制
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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-13 19:41:00

代码语言:javascript
复制
# 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
票数 2
EN

Stack Overflow用户

发布于 2018-07-11 03:15:24

子树和从networkX对象中读取是可以的,问题是您要直接将所有子树添加到原始tree实例中。在ete3中,Tree类是实际上只是一个节点 (包括指向其后代的指针,如果有的话),因此tree.add_child直接向根节点添加新的子节点/子树。

你应该做的是在枯树的叶子上迭代,找到一个node.name == parent,并把所有的孩子都附加到它上。另外,您应该一个接一个地附加它们,而不是预先生成一个子树.否则,您将得到具有一个父节点和一个子节点的附加内部节点。

编辑:

您的代码的第二个版本几乎是正确的,但是您没有考虑到如果根不是它们的实际父节点,则永远不会将节点附加到树(即根)。这可能就是为什么您将lvl-1作为一个单独的节点,而不是其他节点的父节点。另外,我不确定networkX图的遍历顺序,这可能很重要。更安全(如果更丑)版本如下所示:

代码语言:javascript
复制
# 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)的东西,所有的迭代和列表删除都是这样。可能有一种方法可以将图形从根遍历到叶,这将不需要边缘列表的副本(并且将在一个迭代中工作)。但它最终会产生一棵正确的树。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51273890

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档