Can we exclude networks where the root/outgroup is involved in hybridization?

27 views
Skip to first unread message

Ana Otero

unread,
May 4, 2026, 7:20:13 AMMay 4
to JuliaPhylo users
Hi, 
I get this error when I tried to do root at node when testing h=3 and beyond.

"
rootatnode!(net1, "Linaria_elegans")
ERROR: RootMismatch: the desired root is below a reticulation,
reverting to old root position.
Stacktrace:
 [1] rootonedge!(net::HybridNetwork, edgeNumber::Int64; index::Bool)
   @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:125
 [2] rootonedge!
   @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:103 [inlined]
 [3] #rootonedge!#137
   @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:100 [inlined]
 [4] rootonedge!
   @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:99 [inlined]
 [5] rootatnode!(net::HybridNetwork, nodeNumber::Int64; index::Bool)
   @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:61
 [6] rootatnode!(net::HybridNetwork, nodeName::String; kwargs::@Kwargs{})
   @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:40
 [7] rootatnode!(net::HybridNetwork, nodeName::String)
   @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:33
 [8] top-level scope
   @ REPL[6]:1

caused by: RootMismatch: non-leaf node 6 had 0 children.
Could be a hybrid whose parents' direction conflicts with the root.
ischild1 and containroot were updated for a subset of edges in the network only.
Stacktrace:
  [1] traverseDirectEdges!(node::PhyloNetworks.Node, edge::PhyloNetworks.EdgeT{PhyloNetworks.Node}, containroot::Bool)
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:619
  [2] traverseDirectEdges!(node::PhyloNetworks.Node, edge::PhyloNetworks.EdgeT{PhyloNetworks.Node}, containroot::Bool) (repeats 2 times)
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:615
  [3] directedges!(net::HybridNetwork; checkMajor::Bool)
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:587
  [4] directedges!
    @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:564 [inlined]
  [5] rootonedge!(net::HybridNetwork, edgeNumber::Int64; index::Bool)
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:118
  [6] rootonedge!
    @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:103 [inlined]
  [7] #rootonedge!#137
    @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:100 [inlined]
  [8] rootonedge!
    @ C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:99 [inlined]
  [9] rootatnode!(net::HybridNetwork, nodeNumber::Int64; index::Bool)
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:61
 [10] rootatnode!(net::HybridNetwork, nodeName::String; kwargs::@Kwargs{})
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:40
 [11] rootatnode!(net::HybridNetwork, nodeName::String)
    @ PhyloNetworks C:\Users\usuario\.julia\packages\PhyloNetworks\fnzzn\src\manipulateNet.jl:33
 [12] top-level scope
    @ REPL[6]:1


"


Is there any way to solve this in a automated manner? I would like to indicate that any hybridization event that involves the root can be directly discarded.

Thank you very much!

Ana.

Joshua Justison

unread,
May 4, 2026, 10:13:41 AMMay 4
to JuliaPhylo users
Hello Ana,

Depending on your goals, you can actually use the error itself to help automate this process for you. If you have a collection of networks you'd like to try rooting (say in a vector called `nets`), you can use a `try` `catch` block to find out which networks can be rooted in this manner:

```
cant_root_inds = Vector{Int}() #indices to delete from our vector of networks
for (i,net) in enumerate(nets) # go thru all networks
     try
          rootatnode!(net, "Linaria_elegans")
     catch e 
          if e isa PhyloNetworks.RootMismatch #we couldn't root the network
               #do things with the network we couldn't root
               push!(cant_root_inds,i) #record the index of our unrootable network
         end
     end
end
deleteat!(nets,cant_root_inds) #delete indices we couldn't root
```

In this case, the networks that can't be rooted are discarded. If your aim is to  remove hybridization events themselves that conflict with a given rooting, this is a bit more nontrivial (I think) and would need to think more on how to identify the conflict-causing hybridizations so they can be deleted. In the meantime, if you are using SNaQ, you could also try looking at the `.networks` file for alternative network topologies that may be compatible with your rooting (see here).
Hope this helps! 

Josh

Joshua Justison

unread,
May 5, 2026, 12:46:55 PMMay 5
to JuliaPhylo users
Hello Ana,

Just following up on yesterday. I wrote a small function that can delete hybridizations that cause the outgroup to be below a hybridization node. This should allow you to root at the specified outgroup if you want to discard hybridizations that have the outgroup as a descendant. See the example below:

```
using PhyloNetworks

function remove_outgroupreticulations!(net,outgroup)

    preorder!(net)
    nd_ind = findfirst(x-> x.name==outgroup,net.vec_node)
    desc_mat = descendencematrix(net;checkpreorder=false).V
    nd_ancs = net.vec_node[desc_mat[nd_ind,:] .> 0.0] #nodes that are ancestor to our outgroup
    hyb_ancs = filter(x->x.hybrid,nd_ancs) #ancestors of outgroup that are hybrids

    for hyb_nd in hyb_ancs
        hyb_edge = getparentedgeminor(hyb_nd) #the minor edge to delete
        PhyloNetworks.deletehybridedge!(net,hyb_edge)
    end
end

net = readnewick("(C,D,((O,(E,#H7:::0.196):0.314):0.664,(((A1,A2))#H7:::0.804,B):10.0):10.0);")
rootatnode!(net,"A1") ##gives RootMismatch error because of H7
remove_outgroupreticulations!(net,"A1")
net #no more reticulation that leads to A1
rootatnode!(net,"A1") #success
```
A few things to note:
  • I have only tested this function on this small example so be sure to double check the logic and test it to ensure that it performs as you want. Your mileage may vary on other networks.
  • The function always removes the minor hybrid edge, though removing the major edge may be a perfectly valid phylogeny too, in terms of rooting. It is worth noting that when gamma values are not specified (i.e., `hybrid_edge.gamma` is `-1`) then the choice of major/minor edge is arbitrary and determined by how the newick is specified. In this case you may want to consider swapping the major/minor edges with `setgamma!` to look at different resolutions of the network.

Reply all
Reply to author
Forward
0 new messages