|
<!DOCTYPE html> |
|
<html lang='en'> |
|
|
|
<head> |
|
<meta charset="utf-8"> |
|
|
|
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> |
|
|
|
<link href="//veg.github.io/phylotree.js/phylotree.css" rel="stylesheet"> |
|
|
|
<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"> |
|
|
|
<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="//phylotree.hyphy.org/phylotree.js"></script> |
|
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> |
|
|
|
<style> |
|
.date-text { |
|
padding: 0.25em; |
|
text-align: center; |
|
} |
|
|
|
.dot { |
|
stroke: #000; |
|
opacity : 0.1; |
|
} |
|
|
|
.size-bubble, .size-bubble * { |
|
fill: #CCC; |
|
shape-rendering: crispEdges; |
|
stroke: black; |
|
stroke-width: 1px; |
|
} |
|
|
|
.size-label { |
|
display: block; |
|
text-align : center; |
|
font-family: sans-serif; |
|
font-size: 9pt; |
|
} |
|
|
|
.fit-label { |
|
text-anchor : start; |
|
font-family: sans-serif; |
|
font-size: 7pt; |
|
} |
|
|
|
.axis text { |
|
font: 14px sans-serif; |
|
} |
|
|
|
.axis path, .axis line { |
|
fill: none; |
|
stroke: #000; |
|
shape-rendering: crispEdges; |
|
} |
|
|
|
.fit { |
|
fill: none; |
|
stroke-width: 2px; |
|
stroke: red; |
|
} |
|
|
|
.fit-no-counts { |
|
opacity: 0.1; |
|
stroke: gray; |
|
} |
|
|
|
@media print |
|
{ |
|
.no-print, .no-print * |
|
{ |
|
display: none !important; |
|
} |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<nav class="navbar navbar-default" role="navigation"> |
|
<!-- Brand and toggle get grouped for better mobile display --> |
|
<div class="navbar-header"> |
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse"> |
|
<span class="sr-only">Toggle navigation</span> |
|
<span class="icon-bar"></span> |
|
<span class="icon-bar"></span> |
|
<span class="icon-bar"></span> |
|
</button> |
|
<a id = "menu-title" class="navbar-brand" href="#"></a> |
|
</div> |
|
<div class="collapse navbar-collapse"> |
|
<ul class="nav navbar-nav"> |
|
<li class="dropdown"> |
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tree to display <b class="caret"></b></a> |
|
<ul class="dropdown-menu" id = 'tree_selector'> |
|
<li><a href="#" data-tree = "js1774-gag.tre" data-tag = "JS1774 gag"></a></li> |
|
<li><a href="#" data-tree = "sm1727-gag.tre" data-tag = "SM1727 gag"></a></li> |
|
<li><a href="#" data-tree = "tm1679-gag.tre" data-tag = "TM1679 gag"></a></li> |
|
<li><a href="#" data-tree = "js1774-pol-1.tre" data-tag = "JS1774 pol (PR)"></a></li> |
|
<li><a href="#" data-tree = "js1774-pol-2.tre" data-tag = "JS1774 pol (RT)"></a></li> |
|
<li><a href="#" data-tree = "sm1727-pol-1.tre" data-tag = "SM1727 pol (PR)"></a></li> |
|
<li><a href="#" data-tree = "sm1727-pol-2.tre" data-tag = "SM1727 pol (RT)"></a></li> |
|
<li><a href="#" data-tree = "tm1679-pol-1.tre" data-tag = "TM1679 pol (PR)"></a></li> |
|
<li><a href="#" data-tree = "tm1679-pol-2.tre" data-tag = "TM1679 pol (RT)"></a></li> |
|
</ul> |
|
</li> |
|
<li> |
|
<a href="#" data-toggle="modal" data-target="#newick_modal">Input Newick</a> |
|
</li> |
|
</ul> |
|
|
|
<form class="navbar-form navbar-left"> |
|
<div class="checkbox navbar-btn"> |
|
<label class="navbar-link"> |
|
<input type="checkbox" id="layout"> |
|
Radial layout |
|
</label> |
|
</div> |
|
</form> |
|
</div><!-- /.navbar-collapse --> |
|
|
|
</nav> |
|
|
|
<div class = "container"> |
|
|
|
|
|
<div class = "row" style = "margin-top: 1em"> |
|
<div class = "col-md-2" id="date-legend"> |
|
</div> |
|
<div class = "col-md-2" id="compartment-legend"> |
|
</div> |
|
<div class = "col-md-2" id="size-legend"> |
|
</div> |
|
<div class = "col-md-6"> |
|
<svg id="rtt_display"></svg> |
|
</div> |
|
</div> |
|
|
|
<div class = "row"> |
|
<div class = "col-md-12"> |
|
<svg id="tree_display"></svg> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="modal" id = 'newick_modal'> |
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> |
|
<h4 class="modal-title">Newick string to render</h4> |
|
</div> |
|
<div class="modal-body" id = 'newick_body'> |
|
<textarea id = 'nwk_spec' autofocus = true placeholder = "" style = 'width: 100%; height: 100%' rows = 20 selectionStart = 1 selectionEnd = 1000>(a : 0.1, (b : 0.11, (c : 0.12, d : 0.13) : 0.14) : 0.15)</textarea> |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn btn-primary" id = 'validate_newick'>Display this tree</button> |
|
</div> |
|
</div><!-- /.modal-content --> |
|
</div><!-- /.modal-dialog --> |
|
</div><!-- /.modal --> |
|
|
|
<script> |
|
// use these formats for parsing and displaying sampling dates |
|
var date_in = d3.time.format("%Y%m%d"), |
|
date_out = d3.time.format("%B %d, %Y"); |
|
|
|
// default scheme to color by date |
|
var coloring_scheme = d3.scale.category10(); |
|
|
|
// different shapes for labeling compartments |
|
var compartment_labels = d3.scale.ordinal().range(["circle", "square", "diamond", "cross", "triangle-up"]); |
|
|
|
// global tree object |
|
var tree; |
|
|
|
|
|
// bubble size scale |
|
var size_scale = d3.scale.pow ().exponent (0.4).range ([1,6]).clamp (false).domain ([0,1]); |
|
var rescaled_size; |
|
|
|
// determines the size of a node "bubble" |
|
|
|
function bubbleSize(node) { |
|
if (node && node.copy_number) { |
|
return size_scale(node.copy_number); |
|
} |
|
return 1; |
|
} |
|
|
|
function nodeStyler(container, node) { |
|
if (d3.layout.phylotree.is_leafnode(node)) { |
|
|
|
var existing_circle = container.selectAll("circle"); |
|
|
|
if (existing_circle.size() == 1) { |
|
existing_circle.remove(); |
|
} |
|
|
|
if (node.copy_number) { |
|
existing_circle = container.selectAll("path.node_shape").data([node.compartment]); |
|
existing_circle.enter().append("path").classed("node_shape", true); |
|
|
|
var bubble_size = tree.node_bubble_size(node); |
|
|
|
var label = existing_circle.attr("d", function(d) { |
|
return d3.svg.symbol().type(compartment_labels(d)).size(bubble_size * bubble_size)(); |
|
}).selectAll ("title").data ([node.copy_number]); |
|
label.enter().append("title"); |
|
label.text ("" + node.copy_number + " copies"); |
|
|
|
|
|
existing_circle.style("stroke-width", "1px").style("stroke", "black"); |
|
if (node.text_angle) { |
|
existing_circle.attr("transform", function(d) { |
|
return "rotate(" + node.text_angle + ") translate(" + (node.text_align == "end" ? -1 : 1) * bubble_size / 2 + ",0)"; |
|
}); |
|
} else { |
|
existing_circle.attr("transform", function(d) { |
|
return "translate(" + bubble_size / 2 + ",0)"; |
|
}); |
|
} |
|
} |
|
|
|
} |
|
|
|
if (node.date) { |
|
var node_color = coloring_scheme (node.date); |
|
container.selectAll("circle").style("fill", node_color); |
|
container.selectAll("path").style("fill", node_color); |
|
container.style("fill", node_color); |
|
} |
|
|
|
} |
|
|
|
function drawATree(newick) { |
|
|
|
tree = d3.layout.phylotree() |
|
.svg(d3.select("#tree_display")) |
|
.options({ |
|
'selectable': false, |
|
// make nodes and branches not selectable |
|
'collapsible': true, |
|
// turn off the menu on internal nodes |
|
'transitions': false, |
|
// turn off d3 animations. |
|
'draw-size-bubbles': true, |
|
// draw node size bubbles |
|
'annular-limit': 0.5, |
|
// controls how much of the overall diameter can be taken by |
|
// empty "annular" space |
|
'max-radius': 512 |
|
// maximum radial layout radius |
|
}) |
|
.node_span(bubbleSize) |
|
.style_nodes(nodeStyler) |
|
.node_circle_size (2) // do not draw clickable circles for internal nodes |
|
.branch_name (function () {return ""}) // no leaf names |
|
.layout_handler (function (tree) { |
|
plotRTT (tree, "rtt_display", 350,350) |
|
} |
|
) |
|
; |
|
|
|
|
|
/* the next call creates the tree object, and tree nodes */ |
|
tree(d3.layout.newick_parser(newick)); |
|
|
|
/* parse tip names which are assumed to be like this: |
|
6_PB_DNA_1_37-52 |
|
|
|
splitting on '_' yields |
|
|
|
-- TimePoint; parsed and used to assign *colors* to edges/nodes and to draw root-to-tip distances |
|
-- compartment; parsed and used to assign *shapes* to nodes in combination with the DNA/RNA source |
|
-- source; |
|
-- clone ID; ignored |
|
-- another ID; ignored |
|
-- copy number; parsed and used to scale "bubbles" on leaves |
|
|
|
tips which do not conform to this naming convention are labeled as "reference", |
|
and annotated using a special character. |
|
|
|
*/ |
|
|
|
var unique_compartments = {}, |
|
unique_dates = {}; |
|
|
|
var copy_number_range = [1e100,0], |
|
attributed_node = null; |
|
|
|
_.each(tree.get_nodes(), function(value, key) { |
|
var attributes = value.name.split('_'); |
|
if (attributes.length == 5) { |
|
attributed_node = value; |
|
|
|
value.compartment = attributes[1] + ' ' + attributes[2]; |
|
value.copy_number = parseFloat(attributes[4].split ('-')[1]); |
|
|
|
copy_number_range[0] = Math.min (copy_number_range[0], value.copy_number); |
|
copy_number_range[1] = Math.max (copy_number_range[1], value.copy_number); |
|
|
|
value.numeric_date = parseInt (attributes[0]); |
|
value.date = "Month " + attributes[0]; |
|
unique_compartments[value.compartment] = 1; |
|
unique_dates[value.date] = 1; |
|
} else { |
|
value.is_reference = true; |
|
} |
|
|
|
}); |
|
|
|
size_scale.domain (copy_number_range); |
|
coloring_scheme.domain (_.keys(unique_dates).sort()); |
|
compartment_labels.domain (_.keys(unique_compartments).sort()); |
|
|
|
|
|
if ($("#layout").prop("checked")) { |
|
tree.radial (true); |
|
} |
|
tree.placenodes().layout(); |
|
|
|
var rescale = tree.node_bubble_size(attributed_node) / size_scale (attributed_node.copy_number) * 0.5; |
|
|
|
rescaled_size = _.compose (function (d) {return d*rescale}, size_scale); |
|
|
|
// create a legend for sizes |
|
// power of 10 ticks |
|
|
|
var size_bubbles = _.map (d3.range (Math.floor (Math.log(copy_number_range[0])/Math.log (10)), Math.ceil (Math.log(copy_number_range[1])/Math.log (10))), |
|
function (v) {return Math.pow (10,v);}); |
|
|
|
d3.select ("#size-legend").selectAll (".row").remove(); |
|
var reference_sizes = d3.select ("#size-legend").selectAll (".row").data (_.map (size_bubbles, function (d) {return [d];})); |
|
reference_sizes.enter().append ("div").classed ("row", true).selectAll (".col-md-2").data (function (d) {return [d];}).enter().append ("div").classed ("col-md-2", true); |
|
|
|
var max_size = rescaled_size (size_bubbles[size_bubbles.length - 1]); |
|
|
|
reference_sizes.selectAll (".col-md-2").each (function (d) { |
|
var circle_size = rescaled_size (d); |
|
d3.select (this).append ("svg").attr ("width", 2*max_size + 4).attr ("height", 2*circle_size + 4).append ("circle").classed("size-bubble", true).attr ("r", circle_size).attr ("cx", max_size+2).attr ("cy", circle_size+2); |
|
d3.select (this).append ("span").classed ("size-label", true).style ("width", "" + (2*max_size+4) + "px").text (d); |
|
}); |
|
|
|
|
|
// create a legend for compartments |
|
|
|
d3.select ("#compartment-legend").selectAll (".row").remove(); |
|
var compartment_depictions = d3.select ("#compartment-legend").selectAll (".row").data (compartment_labels.domain()); |
|
compartment_depictions.enter().append ("div").classed ("row", true).selectAll (".col-md-2").data (function (d) {return [d];}).enter().append ("div").classed ("col-md-2", true); |
|
compartment_depictions.exit().remove(); |
|
|
|
compartment_depictions.selectAll (".col-md-2").each (function (d) { |
|
d3.select (this).append ("svg").attr ("width", 2*max_size + 4).attr ("height", 2*max_size + 4).append ("path").classed("size-bubble", true).attr("d", function(d) { |
|
return d3.svg.symbol().type(compartment_labels(d)).size(max_size * max_size)(); |
|
}).attr ("transform", "translate( " + max_size + "," + max_size + ")"); |
|
|
|
d3.select (this).append ("span").classed ("size-label", true).style ("width", "" + (2*max_size+4) + "px").text (d); |
|
}); |
|
|
|
// create a legend for dates |
|
d3.select ("#date-legend").selectAll (".row").remove(); |
|
var date_colors = d3.select ("#date-legend").selectAll (".row").data (coloring_scheme.domain()); |
|
date_colors.enter().append ("div").classed ("row", true); |
|
date_colors.exit().remove(); |
|
|
|
date_colors.each (function (d) { |
|
d3.select(this).style ("background-color", coloring_scheme (d)).classed ("date-text", true).text (d).style ("color", d3.rgb(coloring_scheme (d)).hsl().l < 0.5 ? "white" : "black"); |
|
}); |
|
|
|
|
|
|
|
// UI handlers |
|
$("#layout").on("click", function(e) { |
|
tree.radial($(this).prop("checked")).placenodes().update(); |
|
}); |
|
|
|
var best_node = plotRTT (tree, "rtt_display", 350,350, true); |
|
tree.reroot (best_node).update(); |
|
|
|
} |
|
|
|
function computeRootToTip (node) { |
|
if (node.parent) { |
|
node.rtt = node.parent.rtt + tree.branch_length () (node); |
|
} |
|
else { |
|
node.rtt = 0; |
|
} |
|
|
|
if (node.children) { |
|
for (var c = 0; c < node.children.length; c++) { |
|
computeRootToTip (node.children[c]); |
|
} |
|
|
|
} |
|
} |
|
|
|
function computeRootToTipOtherRoot (node, coming_from, shared_distance, distance_to_new_root) { |
|
var my_bl = tree.branch_length () (node); |
|
|
|
var go_up = false; |
|
if (!coming_from) { |
|
shared_distance = node.rtt; |
|
distance_to_new_root = 0; |
|
go_up = true; |
|
} |
|
|
|
|
|
if (node.children) { |
|
for (var c = 0; c < node.children.length; c++) { |
|
if (node.children[c] != coming_from) { |
|
computeRootToTipOtherRoot (node.children[c], node, shared_distance, distance_to_new_root); |
|
} else { |
|
go_up = true; |
|
} |
|
} |
|
} |
|
|
|
node.rtta = node.rtt - shared_distance + distance_to_new_root; |
|
|
|
if (go_up) { |
|
shared_distance -= my_bl; |
|
distance_to_new_root += my_bl; |
|
} |
|
|
|
if (node.parent && go_up) { |
|
computeRootToTipOtherRoot (node.parent, node, shared_distance, distance_to_new_root); |
|
} |
|
|
|
} |
|
|
|
|
|
function loadTreeFromURL(url) { |
|
d3.text(url, function(error, newick) { |
|
|
|
drawATree(newick); |
|
}); |
|
} |
|
|
|
function plotRTT (tree, tag, w, h, auto_root) { |
|
computeRootToTip (tree.get_nodes()[0]); |
|
|
|
if (auto_root) { |
|
|
|
var max_r2 = 0; |
|
var best_node = 0; |
|
tree.traverse_and_compute (function (node) { |
|
if (d3.layout.phylotree.is_leafnode (node)) { |
|
if (node.numeric_date == 0) { |
|
computeRootToTipOtherRoot (node, null, 0, 0); |
|
linear_data = []; |
|
tree.traverse_and_compute (function (node) { |
|
if (d3.layout.phylotree.is_leafnode (node)) { |
|
linear_data.push ([node.numeric_date, node.rtta, node.copy_number]); |
|
} |
|
}); |
|
var fit_with_counts = linear_fit (linear_data)["r2"]; |
|
if (fit_with_counts > max_r2) { |
|
max_r2 = fit_with_counts; |
|
best_node = node; |
|
} |
|
} |
|
} |
|
}); |
|
return best_node; |
|
} |
|
|
|
var margin = {top: 20, right: 80, bottom: 45, left: 65}, |
|
width = w - margin.left - margin.right, |
|
height = h - margin.top - margin.bottom; |
|
|
|
var x = d3.scale.linear() |
|
.range([20, width-20]); |
|
|
|
var y = d3.scale.linear() |
|
.range([height, 0]); |
|
|
|
var xAxis = d3.svg.axis() |
|
.scale(x) |
|
.orient("bottom"); |
|
|
|
var yAxis = d3.svg.axis() |
|
.scale(y) |
|
.orient("left"); |
|
|
|
|
|
var plot_here = d3.select ("#" + tag); |
|
plot_here.attr ("width", w).attr("height", h); |
|
|
|
plot_here.selectAll ("g").remove(); |
|
|
|
var svg = plot_here.append ("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
var plot_data = []; |
|
|
|
var linear_data = []; |
|
|
|
tree.traverse_and_compute (function (node) { |
|
if (d3.layout.phylotree.is_leafnode (node)) { |
|
plot_data.push (node); |
|
linear_data.push ([node.numeric_date, node.rtt, 1]); |
|
} |
|
}); |
|
|
|
xAxis.tickValues (_.keys(_.countBy (linear_data, function (d) {return d[0];})).sort()); |
|
|
|
|
|
|
|
|
|
x.domain(d3.extent(plot_data, function(d) { return d.numeric_date; })).nice(); |
|
y.domain(d3.extent(plot_data, function(d) { return d.rtt; })).nice(); |
|
|
|
svg.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(xAxis) |
|
.append("text") |
|
.attr("class", "label") |
|
.attr("x", width) |
|
.attr("y", 35) |
|
.style("text-anchor", "end") |
|
.text("Time"); |
|
|
|
svg.append("g") |
|
.attr("class", "y axis") |
|
.call(yAxis) |
|
.append("text") |
|
.attr("class", "label") |
|
.attr("transform", "rotate(-90)") |
|
.attr("y", -60) |
|
.attr("dy", ".71em") |
|
.style("text-anchor", "end") |
|
.text("Root-to-tip") ; |
|
|
|
svg.selectAll(".dot") |
|
.data(plot_data) |
|
.enter().append("circle") |
|
.attr("class", "dot") |
|
.attr("r", function (d) {return 2*rescaled_size(tree.node_bubble_size(d));}) |
|
.attr("cx", function(d) { return x(d.numeric_date); }) |
|
.attr("cy", function(d) { |
|
return y(d.rtt); }) |
|
.style("fill", function(d,i) { return "#000000"; }); |
|
|
|
function linear_fit (data) { |
|
|
|
var ss = linear_data.reduce (function (p,c) {return c[2] + p}, 0), // sample count |
|
sx = linear_data.reduce (function (p,c) {return c[2]*c[0] + p}, 0), // sum X |
|
sy = linear_data.reduce (function (p,c) {return c[2]*c[1] + p}, 0) // sum Y |
|
sxoss = sx/ss, |
|
syoss = sy/ss; |
|
|
|
var fitB = 0, |
|
st2 = 0, |
|
vary = 0; |
|
|
|
|
|
data.forEach (function (point) { |
|
|
|
var t = point[0] - sxoss; |
|
st2 += point[2] * t * t; |
|
fitB += point[2] * t * point[1]; |
|
vary += point[2] * (point[1]-syoss)*(point[1]-syoss); |
|
}); |
|
|
|
fitB /= st2; |
|
a = (sy - sx * fitB) / ss; |
|
|
|
var varres = 0; |
|
|
|
data.forEach (function (point) { |
|
var t = point[1] - a - fitB * point[0]; |
|
varres += point[2] * t * t; |
|
}); |
|
|
|
var normvarres = Math.sqrt (varres / (ss - 2)); |
|
|
|
return {'intercept' : a, |
|
'slope' : fitB, |
|
'r2': 1 - varres / vary, |
|
'var (intercept)' : Math.sqrt ((1+sx*sx/(ss*st2))/ss), |
|
'var (slope)' : Math.sqrt (1/st2) |
|
}; |
|
|
|
|
|
}; |
|
|
|
var fit_with_counts = linear_fit (linear_data); |
|
|
|
//console.log (fit_with_counts["R"]); |
|
|
|
|
|
var label_format = d3.format (".2r"); |
|
|
|
function format_line (i, s) { |
|
return label_format (i) + (s >= 0 ? '+' : '') + label_format (s) + '*T'; |
|
} |
|
|
|
|
|
var positive_slope = 0; |
|
|
|
for (s = 0; s < 1000; s += 1) { |
|
fit_without_counts = (linear_fit (linear_data.map (function (d) {return [d[0], d[1], Math.floor (d[2]*(0.05 + 9.95*Math.random (0,1)))];}))); |
|
if (fit_without_counts ["slope"] > 0) { |
|
positive_slope ++; |
|
} |
|
svg.append ("line") |
|
.attr ("x1", x (x.domain()[0])) |
|
.attr ("y1", y (x.domain()[0]*fit_without_counts['slope'] + fit_without_counts ['intercept'])) |
|
.attr ("x2", x (x.domain()[1])) |
|
.attr ("y2", y (x.domain()[1]*fit_without_counts['slope'] + fit_without_counts ['intercept'])) |
|
.attr ("class", "fit fit-no-counts"); |
|
} |
|
|
|
svg.append ("text").attr ("x", x (x.domain()[0])).attr ( y (y.domain [1])).text (d3.format(".2p")(positive_slope/s) + " positive slope"); |
|
|
|
|
|
svg.append ("line") |
|
.attr ("x1", x (x.domain()[0])) |
|
.attr ("y1", y (x.domain()[0]*fit_with_counts['slope'] + fit_with_counts ['intercept'])) |
|
.attr ("x2", x (x.domain()[1])) |
|
.attr ("y2", y (x.domain()[1]*fit_with_counts['slope'] + fit_with_counts ['intercept'])) |
|
.attr ("class", "fit fit-counts"); |
|
|
|
svg.append ("text").attr ("x", x (x.domain()[1])) |
|
.attr ("y", y (x.domain()[1]*fit_with_counts['slope'] + fit_with_counts ['intercept'])) |
|
.text (format_line (fit_with_counts['intercept'],fit_with_counts['slope'])) |
|
.attr ("class", "fit-label") |
|
.attr ("dx", "2em") |
|
.attr ("dy", "-.25 em"); |
|
|
|
|
|
} |
|
|
|
$("#validate_newick").on ("click", function (e) { |
|
var res = d3.layout.newick_parser ( $('textarea[id$="nwk_spec"]').val(), true); |
|
if (res["error"] || ! res["json"]) { |
|
var warning_div = d3.select ("#newick_body").selectAll ("div .alert-danger").data ([res["error"]]) |
|
warning_div.enter ().append ("div"); |
|
warning_div.html (function (d) {return d;}).attr ("class", "alert-danger"); |
|
|
|
} else { |
|
drawATree ($('textarea[id$="nwk_spec"]').val()); |
|
$('#newick_modal').modal('hide'); |
|
} |
|
}); |
|
|
|
$("[data-tree]").each (function () { |
|
$(this).text ($(this).data("tag")); |
|
}); |
|
|
|
$("[data-tree]").on ("click", function (e) { |
|
loadTreeFromURL ($(this).data("tree")); |
|
$("#menu-title").text ($(this).data("tag")); |
|
}); |
|
|
|
$("[data-tree='tm1679-gag.tre']").click(); |
|
</script> |
|
|
|
</body> |
|
|
|
</html> |