Skip to content

Instantly share code, notes, and snippets.

@spond
Last active April 17, 2018 02:02
Show Gist options
  • Save spond/707878838762cb57d892a5d8e774d4e0 to your computer and use it in GitHub Desktop.
Save spond/707878838762cb57d892a5d8e774d4e0 to your computer and use it in GitHub Desktop.
Annotated phylotree.js

A hackish example for annotating trees

This example uses tree.style_nodes to append colored rectangles to the node names as annotations. It requires some less than pretty spacing calculations in the handler, but both radial and rectangular layouts are supported.

This is in reference to veg/phylotree.js#64

<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<link href="//veg.github.io/phylotree.js/phylotree.css" rel="stylesheet">
<script src="//code.jquery.com/jquery.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//veg.github.io/phylotree.js/phylotree.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js" charset="utf-8"></script>
</head>
<body>
<div>
<form>
<label>Radial layout
<input type = "checkbox" id = "layout" checked/>
</form>
</div>
<svg id="tree_display" />
<script>
var example_tree = "(((EELA:0.150276,CONGERA:0.213019):0.230956,(EELB:0.263487,CONGERB:0.202633):0.246917):0.094785,((CAVEFISH:0.451027,(GOLDFISH:0.340495,ZEBRAFISH:0.390163):0.220565):0.067778,((((((NSAM:0.008113,NARG:0.014065):0.052991,SPUN:0.061003,(SMIC:0.027806,SDIA:0.015298,SXAN:0.046873):0.046977):0.009822,(NAUR:0.081298,(SSPI:0.023876,STIE:0.013652):0.058179):0.091775):0.073346,(MVIO:0.012271,MBER:0.039798):0.178835):0.147992,((BFNKILLIFISH:0.317455,(ONIL:0.029217,XCAU:0.084388):0.201166):0.055908,THORNYHEAD:0.252481):0.061905):0.157214,LAMPFISH:0.717196,((SCABBARDA:0.189684,SCABBARDB:0.362015):0.282263,((VIPERFISH:0.318217,BLACKDRAGON:0.109912):0.123642,LOOSEJAW:0.397100):0.287152):0.140663):0.206729):0.222485,(COELACANTH:0.558103,((CLAWEDFROG:0.441842,SALAMANDER:0.299607):0.135307,((CHAMELEON:0.771665,((PIGEON:0.150909,CHICKEN:0.172733):0.082163,ZEBRAFINCH:0.099172):0.272338):0.014055,((BOVINE:0.167569,DOLPHIN:0.157450):0.104783,ELEPHANT:0.166557):0.367205):0.050892):0.114731):0.295021)"
// tree from Yokoyama et al http://www.ncbi.nlm.nih.gov/pubmed/18768804
var tree = d3.layout.phylotree()
// create a tree layout object
.svg(d3.select("#tree_display")).align_tips (true).radial (true);
// render to this SVG element
var attribute_to_color = d3.scale.category10();
var standard_label = tree.branch_name();
tree.branch_name (function (node) {
return standard_label(node) + " ";
});
tree(d3.layout.newick_parser(example_tree));
var tree_attributes = {};
/* the following loop just populates an object with key : value pairs like
leaf_name -> [a,b,c], where a,b,c are random numbers in {0,1,2,3,4}
*/
var maximum_length = 0;
tree.traverse_and_compute (function (node) {
if (d3.layout.phylotree.is_leafnode (node)) {
tree_attributes[node.name] = [0,0,0].map (function () {return Math.floor(Math.random() * 5);});
maximum_length = maximum_length < node.name.length ? node.name.length : maximum_length;
}
});
tree.style_nodes(function (element, node_data) {
if (node_data.name in tree_attributes) { // see if the node has attributes
var node_label = element.select("text");
var font_size = parseFloat (node_label.style ("font-size"));
var annotation = element.selectAll ("rect").data (tree_attributes[node_data.name]);
annotation.enter().append ("rect");
annotation.attr ("width", font_size)
.attr ("height", font_size)
.attr ("y", -font_size/2).style ("fill", function(d, i) {
return attribute_to_color (d);
});
var move_past_label = maximum_length * 0.75 * font_size;
if (tree.radial ()) {
var shifter = tree.shift_tip (node_data)[0];
annotation.attr ("transform", "rotate (" + node_data.text_angle + ")")
.attr ("x", function (d, i) { return shifter > 0 ? shifter + font_size * i + move_past_label : shifter - font_size * (i+1) - move_past_label;})
} else {
var x_shift = tree.shift_tip (node_data)[0] + move_past_label;
annotation.attr ("transform", null).attr ("x", function (d, i) { return x_shift + font_size * i;});
}
}
});
$("#layout").on ("click", function (e) {
tree.radial ($(this).prop ("checked")).placenodes().update ();
});
// parse the Newick into a d3 hierarchy object with additional fields
tree.layout();
// layout and render the tree
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment