pythontreeconvertersnetworkxete3

How to convert from NetworkX graph to ete3 Tree object?


I'm trying to figure out how to build an ete3.Tree object from a networkx directed graph? I added each child in the way I thought would produce the desired result but I am having trouble.

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

enter image description here

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

I've also tried the following but it did not work:

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

Solution

  • # 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