veg / phylotree.js

Interactive viewer of phylogenetic trees
http://phylotree.hyphy.org
MIT License
169 stars 71 forks source link

:bug: Tree-length not conserved after reroot #433

Open LeoFeatherstone opened 1 year ago

LeoFeatherstone commented 1 year ago

Hi,

Thanks for putting this wonderful resource together.

I think I've found a bug wherein the length of the tree is not conserved after rerooting. For a reproducible example, I am rerooting at the 90th-100th nodes of the MERS tree given in the observable example (nwk string omitted for brevity). I have found the the length after rerooting is off by an amount equal to the branch length of one of the root's children. I have noted that there is a trifucation at the base of the MERS example, but I have also observed this pattern for other trees containing only bifurcations.

I would greatly appreciate any insight at all here!

All the best, Leo

const phylo = require("phylotree")

let nwk = "" // paste in nwk from observable example

function getLength(tree) {
    let length =  tree.nodes.descendants().slice(1).map( // slice(1) avoids undefined root length
      (n) => tree.branch_length_accessor(n)
    ).reduce(
      (a, b) => a+b
    )
    return length;
}

let tree = new phylo.phylotree(nwk)
const refLength = getLength(tree)
var dummyTree

for (let n = 90; n < 100; n++) {

    dummyTree = new phylo.phylotree(nwk)

    let rerootNode = dummyTree.nodes.descendants()[n]
    dummyTree.reroot(rerootNode)

    rerootLength = getLength(dummyTree)

    console.log(rerootLength - refLength)
} // Returns:
// -0.0002748347999999845
// -0.0002748347999999845
// -0.0002748347999999845
// -0.00027483479999995675
// -0.0002748347999999845
// -0.0002748347999999845
// -0.00027483480000001226
// -0.00027483480000001226
// -0.00027483480000001226
// -0.00027483480000001226

console.log(tree.nodes.children.map(
    (n) => tree.branch_length_accessor(n)
)) // Returns: [ 0.0000013865, 0.0000013652, 0.0002748348 ]