@@ -141,9 +141,10 @@ chooseEdgesGamma(net::HybridNetwork) = chooseEdgesGamma(net, false, net.edge)
141
141
chooseEdgesGamma (net:: HybridNetwork , blacklist:: Bool ) = chooseEdgesGamma (net, blacklist, net. edge)
142
142
143
143
# aux function for addHybridization
144
- # that takes the output edge1, edge2, gamma from
145
- # chooseEdgesGamma and created necessary edges
144
+ # that takes the output edge1, edge2.
146
145
# returns edge3, edge4, and adjusts edge1, edge2 to shorter length
146
+ # fixit: problem if edge1 or edge2 have a missing length, coded as -1.0.
147
+ # would be best to set lengths of e3, e4 to 0.0, and leave lengths of e1,e2 unchanged
147
148
function parameters4createHybrid! (edge1:: Edge , edge2:: Edge ,net:: HybridNetwork )
148
149
max_edge = maximum ([e. number for e in net. edge]);
149
150
t1 = rand ()* edge1. length;
@@ -343,21 +344,21 @@ end
343
344
addHybridizationUpdateSmart! (net:: HybridNetwork , N:: Integer ) = addHybridizationUpdateSmart! (net, false ,N)
344
345
345
346
346
- # ----------------------------------- add alternative hybridizations found in bootstrap ------------------------------------
347
+ # --- add alternative hybridizations found in bootstrap
347
348
"""
348
349
addAlternativeHybridizations!(net::HybridNetwork, BSe::DataFrame;
349
350
cutoff=10::Number, top=3::Int)
350
351
351
- Modify the network `net` (the best network estimated with snaq ) by adding other hybridizations
352
- that are present in the bootstrap networks. By default, it will only consider hybrid edges with
353
- more than 10% bootstrap support (`cutoff`) and it will only include the three top hybridizations
354
- (`top`) sorted by bootstrap support.
352
+ Modify the network `net` (the best estimated network ) by adding some of
353
+ the hybridizations present in the bootstrap networks. By default, it will only
354
+ add hybrid edges with more than 10% bootstrap support (`cutoff`) and it will
355
+ only include the top 3 hybridizations (`top`) sorted by bootstrap support.
355
356
356
- The function also modifies the dataframe `BSe`. In the original `BSe`,
357
+ The dataframe `BSe` is also modified . In the original `BSe`,
357
358
supposedly obtained with `hybridBootstrapSupport`, hybrid edges that do not
358
359
appear in the best network have a missing number.
359
- After the hybrid edges are added with `addAlternativeHybridizations`, `BSe` is modified to include the
360
- edge numbers of the newly added hybrid edges.
360
+ After hybrid edges from bootstrap networks are added,
361
+ `BSe` is modified to include the edge numbers of the newly added hybrid edges.
361
362
To distinguish hybrid edges present in the original network versus new edges,
362
363
an extra column of true/false values is also added to `BSe`, named "alternative",
363
364
with true for newly added edges absent from the original network.
@@ -367,76 +368,109 @@ major tree topology.
367
368
368
369
# example
369
370
370
- ```julia
371
- bootnet = readMultiTopology("bootstrap-networks.txt")
372
- bestnet = readTopology("best.tre")
373
- BSn, BSe, BSc, BSgam, BSedgenum = hybridBootstrapSupport(bootnet, bestnet);
374
- addAlternativeHybridizations!(bestnet,BSe)
375
- using PhyloPlots
376
- plot(bestnet, edgelabel=BSe[[:edge,:BS_hybrid_edge]])
371
+ ```jldoctest
372
+ julia> bootnet = readMultiTopology(joinpath(dirname(pathof(PhyloNetworks)), "..","examples", "bootsnaq.out")); # vector of 10 networks
373
+
374
+ julia> bestnet = readTopology("((O,(E,#H7:::0.196):0.314):0.332,(((A)#H7:::0.804,B):10.0,(C,D):10.0):0.332);");
375
+
376
+ julia> BSn, BSe, BSc, BSgam, BSedgenum = hybridBootstrapSupport(bootnet, bestnet);
377
+
378
+ julia> BSe[1:6,[:edge,:hybrid_clade,:sister_clade,:BS_hybrid_edge]]
379
+ 6×4 DataFrame
380
+ Row │ edge hybrid_clade sister_clade BS_hybrid_edge
381
+ │ Int64? String String Float64
382
+ ─────┼─────────────────────────────────────────────────────
383
+ 1 │ 7 H7 B 33.0
384
+ 2 │ 3 H7 E 32.0
385
+ 3 │ missing c_minus3 c_minus8 44.0
386
+ 4 │ missing c_minus3 H7 44.0
387
+ 5 │ missing E O 12.0
388
+ 6 │ missing c_minus6 c_minus8 9.0
389
+
390
+ julia> PhyloNetworks.addAlternativeHybridizations!(bestnet, BSe)
391
+
392
+ julia> BSe[1:6,[:edge,:hybrid_clade,:sister_clade,:BS_hybrid_edge,:alternative]]
393
+ 6×5 DataFrame
394
+ Row │ edge hybrid_clade sister_clade BS_hybrid_edge alternative
395
+ │ Int64? String String Float64 Bool
396
+ ─────┼──────────────────────────────────────────────────────────────────
397
+ 1 │ 7 H7 B 33.0 false
398
+ 2 │ 3 H7 E 32.0 false
399
+ 3 │ 16 c_minus3 c_minus8 44.0 true
400
+ 4 │ 19 c_minus3 H7 44.0 true
401
+ 5 │ 22 E O 12.0 true
402
+ 6 │ missing c_minus6 c_minus8 9.0 false
403
+
404
+ julia> # using PhyloPlots; plot(bestnet, edgelabel=BSe[:,[:edge,:BS_hybrid_edge]]);
377
405
```
378
406
"""
379
407
function addAlternativeHybridizations! (net:: HybridNetwork ,BSe:: DataFrame ; cutoff= 10 :: Number ,top= 3 :: Int )
380
408
top > 0 || error (" top must be greater than 0" )
381
- BSe[:alternative ] = falses (length (BSe[ :hybrid ] ))
382
- newBSe = BSe[BSe[ :BS_hybrid_edge ] .> cutoff,:]
383
- newBSe = newBSe[. ! ismissing .(newBSe[ :hybrid ]) & . ! ismissing .(newBSe[ :sister ]),:]
384
- newBSe = newBSe[ ismissing .(newBSe[ :edge ]),:]
385
- newHyb = newBSe[ 1 : top,:]
386
-
387
- if ( size (newHyb, 1 ) == 0 )
388
- @warn " Did not find any alternative hybridizations with bootstrap support greater than the cutoff, so nothign added"
409
+ BSe[! , :alternative ] = falses (nrow (BSe))
410
+ newBSe = subset ( BSe,
411
+ :BS_hybrid_edge => x -> x .> cutoff, :edge => ByRow ( ismissing),
412
+ :hybrid => ByRow ( ! ismissing), :sister => ByRow ( ! ismissing),
413
+ )
414
+ top = min (top, nrow (newBSe))
415
+ if top == 0
416
+ @info " no alternative hybridizations with support > cutoff $ cutoff% , so nothing added. "
389
417
return
390
418
end
391
-
392
419
for i in 1 : top
393
- hybnum = newHyb[:hybrid ][i]
394
- sisnum = newHyb[:sister ][i]
395
- edgenum = addHybridBetweenClades! (hybnum,sisnum,net)
396
- ind1 = findall (x-> ! ismissing (x) && x== hybnum,BSe[:hybrid ])
397
- ind2 = findall (x-> ! ismissing (x) && x== sisnum,BSe[:sister ])
420
+ hybnum = newBSe[i,:hybrid ]
421
+ sisnum = newBSe[i,:sister ]
422
+ edgenum = addHybridBetweenClades! (net, hybnum, sisnum)
423
+ if isnothing (edgenum)
424
+ @warn " cannot add desired hybrid (BS=$(newBSe[i,:BS_hybrid_edge ]) ): the network would have a directed cycle"
425
+ continue
426
+ end
427
+ ind1 = findall (x-> ! ismissing (x) && x== hybnum, BSe[! ,:hybrid ])
428
+ ind2 = findall (x-> ! ismissing (x) && x== sisnum, BSe[! ,:sister ])
398
429
ind = intersect (ind1,ind2)
399
- BSe[ind,:edge ] = edgenum
400
- BSe[ind,:alternative ] = true
430
+ BSe[ind,:edge ] . = edgenum
431
+ BSe[ind,:alternative ] . = true
401
432
end
402
433
end
403
434
404
435
405
- # # function to a hybrid edge between hybrid clade (hybnum = node number) and sister clade (sisnum = node number)
406
- # # the function finds the parent edges to these nodes, and puts a hybrid edge between them
407
- # # the function modifies net, and it returns the number of the minor hybrid edge added
408
- function addHybridBetweenClades! (hybnum:: Number ,sisnum:: Number ,net:: HybridNetwork )
409
- hybind = getIndexNode (hybnum,net)
410
- sisind = getIndexNode (sisnum,net)
436
+ """
437
+ addHybridBetweenClades!(net::HybridNetwork, hybnum::Number, sisnum::Number)
411
438
412
- # # hybridization ed1->ed2
413
- edge1 = getparentedge (net. node[sisind]) # major parent edges
414
- edge2 = getparentedge (net. node[hybind])
439
+ Modify `net` by adding a minor hybrid edge from "donor" to "recipient",
440
+ where "donor" is the major parent edge `e1` of node number `hybnum` and
441
+ "recipient" is the major parent edge `e2` of node number `sisnum`.
442
+ The new nodes are currently inserted at the middle of these parent edges.
415
443
416
- edge3,edge4 = parameters4createHybrid! (edge1, edge2,net)
417
- hybridnode = createHybrid! (edge1, edge2, edge3, edge4, net, 0.1 ) # # gamma=0.1, fixed later
418
- if (edge1. length < 0 )
419
- setBranchLength! (edge1,- 1.0 )
420
- setBranchLength! (edge3,- 1.0 )
421
- end
422
- if (edge2. length < 0 )
423
- setBranchLength! (edge2,- 1.0 )
424
- setBranchLength! (edge4,- 1.0 )
425
- end
444
+ If a hybrid edge from `e1` to `e2` would create a directed cycle in the network,
445
+ then this hybrid cannot be added.
446
+ In that case, the donor edge `e1` is moved up if its parent is a hybrid node,
447
+ to ensure that the sister clade to the new hybrid would be a desired (the
448
+ descendant taxa from `e1`) and a new attempt is made to create a hybrid edge.
426
449
427
- if (edge2. isChild1)
428
- edge4. hybrid = true
429
- setGamma! (edge4,0.9 )
430
- edge4. isChild1 = true
431
- else
432
- edge2. hybrid = true
433
- setGamma! (edge2,0.9 )
434
- edge2. isChild1 = false
450
+ Output: number of the new hybrid edge, or `nothing` if the desired hybridization
451
+ is not possible.
452
+
453
+ See also:
454
+ [`addhybridedge!`](@ref) (used by this method) and
455
+ [`directionalconflict`](@ref) to check that `net` would still be a DAG.
456
+ """
457
+ function addHybridBetweenClades! (net:: HybridNetwork , hybnum:: Number , sisnum:: Number )
458
+ hybind = getIndexNode (hybnum,net)
459
+ sisind = getIndexNode (sisnum,net)
460
+ e1 = getparentedge (net. node[sisind]) # major parent edges
461
+ e2 = getparentedge (net. node[hybind])
462
+ p1 = getparent (e1)
463
+ if directionalconflict (p1, e2, true ) # then: first try to move the donor up
464
+ # so long as the descendant taxa (= sister clade) remain the same
465
+ while p1. hybrid
466
+ e1 = getparentedge (p1) # major parent edge: same descendant taxa
467
+ p1 = getparent (e1)
468
+ end
469
+ directionalconflict (p1, e2, true ) && return nothing
435
470
end
436
- # # used gamma=0.1 to make the new edge a minor edge, but we really do not have gamma value:
437
- emaj = getparentedge (hybridnode)
438
- emaj. gamma = - 1
439
- e = getparentedgeminor (hybridnode)
440
- e. gamma = - 1
441
- return e. number
471
+ hn, he = addhybridedge! (net, e1, e2, true ) # he: missing length & gamma by default
472
+ # ideally: add option "where" to breakedge!, used by addhybridedge!
473
+ # so as to place the new nodes at the base of each clade.
474
+ # currently: the new nodes are inserted at the middle of e1 and e2.
475
+ return he. number
442
476
end
0 commit comments