phylotree
Version:
A JavaScript library for developing applications and interactive visualizations involving [phylogenetic trees](https://en.wikipedia.org/wiki/Phylogenetic_tree), written as an extension of the [D3](http://d3js.org) [hierarchy layout](https://github.com/d3/
82 lines (69 loc) • 2.49 kB
JavaScript
/**
* Compute midpoint of a phylogenetic tree
*
* @param {Object} tree -- the phylotree.js tree object
* @return {Object} the calculated midpoint to root on
* { location: root_node, breakpoint: 0 }
*
*/
export function computeMidpoint(tree) {
if (!tree.hasBranchLengths()) {
throw "Center of tree calculation cannot be performed on trees that do not have fully specified branch lengths";
}
var bl = tree.branch_length;
tree.traverse_and_compute(function(node) {
if (node.parent) {
var my_longest_path_length = bl(node);
var my_longest_path_terminus;
if (tree.isLeafNode(node)) {
my_longest_path_terminus = node;
node.max_path = 0;
node.max_path_terminus = node;
} else {
my_longest_path_length += node.max_path;
my_longest_path_terminus = node.max_path_terminus;
}
if (
!node.parent.max_path ||
node.parent.max_path < my_longest_path_length
) {
node.parent.max_path = my_longest_path_length;
node.parent.max_path_terminus = my_longest_path_terminus;
}
}
});
var root_node = tree.getRootNode();
var longest_path_length = 0;
root_node.children.forEach(function(root_child) {
if (root_child.max_path_terminus !== root_node.max_path_terminus) {
var pl = root_child.max_path + bl(root_child);
if (pl >= longest_path_length) {
longest_path_length = pl;
}
}
});
if (root_node.max_path > longest_path_length) {
// not already midpoint rooted
longest_path_length = (longest_path_length + root_node.max_path) * 0.5;
// start traversing up from the deepest leaf to the root, until we find the
// half-way point
var root_on = root_node.max_path_terminus;
while (true) {
var current_bl = bl(root_on);
//console.log (current_bl, longest_path_length);
if (current_bl <= longest_path_length) {
longest_path_length -= current_bl;
root_on = root_on.parent;
} else {
//console.log ("Rooting on ", root_on, longest_path_length[0], current_bl);
return {
location: root_on,
breakpoint: longest_path_length / current_bl
};
//console.log ("Longest " + root_path (tree.getNodeByName(root_node.max_path_terminus.name)));
//console.log ("Second longest " + root_path (tree.getNodeByName(longest_path_length[1].name)));
}
}
}
return { location: root_node, breakpoint: 0 };
}