Commit 1a3d9e67 authored by Kautsar, Satria's avatar Kautsar, Satria
Browse files

Implements Overview screen & related families view

parent 61521f71
......@@ -1294,6 +1294,12 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
pathBase: folder where GCF files will be deposited
"""
numBGCs = len(bgcs)
family_data = { # will be returned, for use in overview.js
"label": className,
"families_newick": "()",
"families": []
}
simDict = {} # dictionary of dictionaries
# Doing this so it only has to go through the matrix once
......@@ -1646,6 +1652,7 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
newick_trees[exemplar_idx] = newick
### Use the 0.5 distance cutoff to cluster clans by default
bs_similarity_families = []
if clusterClans and cutoff == clanClassificationCutoff:
# Detect if there's only 1 GCF. It makes pySAPC crash
if len(familyIdx) == 1:
......@@ -1684,6 +1691,8 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
# add main diagonal
for family in range(len(familyIdx)):
famSimMatrix[family,family] = 1.0
bs_similarity_families = famSimMatrix.tolist()
#clanLabels = pysapc.SAP(damping=damping, max_iter=500,
#preference='min').fit_predict(famSimMatrix)
......@@ -1698,8 +1707,8 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
clanLabels = []
else:
clanLabels = []
clanLabels = []
if len(clanLabels) > 0:
clansDict = defaultdict(list)
for i in range(len(familyIdx)):
......@@ -1718,6 +1727,14 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
'members': [bgcExt2Int[member] for member in members], }
for family, members in familiesDict.items()]
family_data["families"] = []
family_data["families_newick"] = "()"
for family, members in familiesDict.items():
family_data["families"].append({
"label": "FAM_{:05d}".format(family),
"members": members # use external indexing
})
# Positional alignment information is based on DomainCountGene, which
# does not contain empty genes (i.e. with no domains).
domainGenes2allGenes = {}
......@@ -1825,11 +1842,16 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
for bgc in familiesDict[family]:
clustering_file.write("{}\t{}\n".format(clusterNames[bgc], family))
# get family-family similarity matrix
bs_similarity_families = [[get_composite_bgc_similarities([bgcs[bid] for bid in bs_families[row]["members"]], [bgcs[bid] for bid in bs_families[col]["members"]], simDict) if (row != col) else (1.00, (1.00, bgcs[bs_families[row]["members"][0]], bgcs[bs_families[row]["members"][0]]), (1.00, bgcs[bs_families[row]["members"][0]], bgcs[bs_families[row]["members"][0]])) for col in
range(row+1)] for row in range(len(bs_families))]
## Write bgc_networks.js
with open(os.path.join(module_html_path, "bs_networks.js"), "w") as bs_networks_js:
bs_networks_js.write("var bs_similarity={};\n".format(json.dumps(bs_distances, indent=4, separators=(',', ':'), sort_keys=True)))
bs_networks_js.write("var bs_families={};\n".format(json.dumps(bs_families, indent=4, separators=(',', ':'), sort_keys=True)))
bs_networks_js.write("var bs_families_alignment={};\n".format(json.dumps(bs_families_alignment, indent=4, separators=(',', ':'), sort_keys=True)))
bs_networks_js.write("var bs_similarity_families={};\n".format(json.dumps(bs_similarity_families, indent=4, separators=(',', ':'), sort_keys=True)))
if len(clanLabels) > 0:
bs_networks_js.write("var bs_clans={};\n".format(json.dumps(bs_clans, indent=4, separators=(',', ':'), sort_keys=True)))
......@@ -1844,7 +1866,7 @@ def clusterJsonBatch(bgcs, pathBase, className, matrix, pos_alignments,
for bgc in familiesDict[family]:
clansFile.write("{}\t{}\t{}\n".format(clusterNames[bgc], clan, family))
return
return family_data
class FloatRange(object):
......@@ -2055,6 +2077,8 @@ if __name__=="__main__":
global mode
global run_name
global run_data
run_data = {}
global clusterNames, bgcClassNames
......@@ -2136,8 +2160,12 @@ if __name__=="__main__":
time1 = time.time()
run_name = "{}{}".format(time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime()), run_mode_string)
start_time = time.localtime()
run_name = "{}{}".format(time.strftime("%Y-%m-%d_%H-%M-%S", start_time), run_mode_string)
run_data["start_time"] = time.strftime("%d/%m/%Y %H:%M:%S", start_time)
run_data["parameters"] = " ".join(sys.argv[1:])
run_data["input"] = {}
# Make the following available for possibly deleting entries within parseHmmScan
global genbankDict, gbk_files, sampleDict, clusters, baseNames
......@@ -2644,9 +2672,46 @@ if __name__=="__main__":
clusterNames = tuple(sorted(clusters))
# fetch genome list for overview.js
genomes = []
classes = []
clusterNamesToGenomes = {}
clusterNamesToClasses = {}
for bgc in clusterNames:
# get class info
product = bgc_info[bgc].product
predicted_class = sort_bgc(product)
if predicted_class not in classes:
clusterNamesToClasses[bgc] = len(classes)
classes.append(predicted_class)
else:
clusterNamesToClasses[bgc] = classes.index(predicted_class)
# get identifier info
identifier = ""
if len(bgc_info[bgc].organism) > 1:
identifier = bgc_info[bgc].organism
elif len(bgc_info[bgc].accession_id) > 1:
if (bgc_info[bgc].accession_id[2] == "_"): # is a refseq accession
identifier = bgc_info[bgc].accession_id[2].split(".")[0]
elif len(bgc_info[bgc].accession_id) > 6: # *assume* a genbank WGS accession
# todo: use more robust check / assumption e.g. other types of genbank data?
identifier = bgc_info[bgc].accession_id[0:6]
if len(identifier) < 1:
identifier = "Unknown Genome {}".format(len(genomes))
if identifier not in genomes:
clusterNamesToGenomes[bgc] = len(genomes)
genomes.append(identifier)
else:
clusterNamesToGenomes[bgc] = genomes.index(identifier)
run_data["input"]["accession"] = [{ "id": "genome_{}".format(i), "label": acc } for i, acc in enumerate(genomes)]
run_data["input"]["accession_newick"] = "()" # todo ...
run_data["input"]["classes"] = [{ "label": cl } for cl in classes ] # todo : colors
run_data["input"]["bgc"] = [{ "id": bgc, "acc": clusterNamesToGenomes[bgc], "class": clusterNamesToClasses[bgc] } for bgc in clusterNames]
# create output directory for network files
network_files_folder = os.path.join(network_folder, run_name)
create_directory(network_files_folder, "Network Files", False)
run_data["networks"] = []
# copy html templates
dir_util.copy_tree(os.path.join(os.path.realpath(os.path.dirname(__file__)), "html_template", "output"), output_folder)
......@@ -2752,9 +2817,10 @@ if __name__=="__main__":
pa[int(row[1])] = (int(row[-4]), int(row[-3]), int(row[-2]), reverse)
del network_matrix_mix[:]
html_subs.append({ "name" : "mix", "css" : "Others", "label" : "Mixed"})
clusterJsonBatch(mix_set, pathBase, "mix", reduced_network, pos_alignments,
family_data = clusterJsonBatch(mix_set, pathBase, "mix", reduced_network, pos_alignments,
cutoffs=cutoff_list, clusterClans=options.clans,
clanCutoff=options.clan_cutoff, htmlFolder=network_html_folder)
run_data["networks"].append(family_data)
del mix_set[:]
del reduced_network[:]
......@@ -2854,10 +2920,11 @@ if __name__=="__main__":
del network_matrix[:]
html_subs.append({ "name" : bgc_class, "css" : bgc_class, "label" : bgc_class})
clusterJsonBatch(BGC_classes[bgc_class], pathBase, bgc_class,
family_data = clusterJsonBatch(BGC_classes[bgc_class], pathBase, bgc_class,
reduced_network, pos_alignments, cutoffs=cutoff_list,
clusterClans=options.clans, clanCutoff=options.clan_cutoff,
htmlFolder=network_html_folder)
run_data["networks"].append(family_data)
del BGC_classes[bgc_class][:]
del reduced_network[:]
......@@ -3016,6 +3083,14 @@ if __name__=="__main__":
#del BGC_classes[bgc_class][:]
#del reduced_network[:]
# generate overview data
end_time = time.localtime()
duration = int(time.mktime(end_time)) - int(time.mktime(start_time))
run_data["end_time"] = time.strftime("%d/%m/%Y %H:%M:%S", end_time)
run_data["duration"] = "{}h{}m{}s".format((duration // 3600), ((duration % 3600) // 60), ((duration % 3600) % 60))
with open(os.path.join(network_html_folder, "run_data.js"), "w") as run_data_js:
run_data_js.write("var run_data={};\n".format(json.dumps(run_data, indent=4, separators=(',', ':'), sort_keys=True)))
# update bgc_results.js
add_to_bigscape_results_js(run_name, html_subs, os.path.join(output_folder, "html_content", "js", "bigscape_results.js"))
......
......@@ -552,3 +552,20 @@ def add_to_bigscape_results_js(module_name, subs, result_js_file):
bigscape_results.append({ "label" : module_name, "networks" : subs })
with open(result_js_file, "w") as bs_js:
bs_js.write("var bigscape_results = {};".format(json.dumps(bigscape_results, indent=4, separators=(',', ':'), sort_keys=True)))
def get_composite_bgc_similarities(bgcs_1, bgcs_2, sim_matrix):
num_pairs = 0
sum_sim = 0.00
min_sim = (1.00, -1, -1)
max_sim = (0.00, -1, -1)
for bgc_1 in bgcs_1:
for bgc_2 in bgcs_2:
sim = 0.00 if (bgc_1 == bgc_2) else (sim_matrix[bgc_1][bgc_2] if ((bgc_1 in sim_matrix) and (bgc_2 in sim_matrix[bgc_1])) else sim_matrix[bgc_2][bgc_1])
sum_sim += sim
if (sim < min_sim[0]):
min_sim = (sim, bgc_1, bgc_2) if (bgc_2 > bgc_1) else (sim, bgc_2, bgc_1)
if (sim > max_sim[0]):
max_sim = (sim, bgc_1, bgc_2) if (bgc_2 > bgc_1) else (sim, bgc_2, bgc_1)
num_pairs += 1
return ((sum_sim / num_pairs), min_sim, max_sim) # let it throw infinite division error by itself
\ No newline at end of file
......@@ -940,4 +940,57 @@ table {
}
.hidden {
display: none;
}
/* Overview page */
.overviewpage {
}
.overviewleft {
width: 600px;
float: left;
}
.overviewright {
width: 600px;
float: left;
}
.infocontainer {
margin: 5px;
}
.infocontainer h3 {
border-radius: 10px;
padding: 5px;
margin: 0px;
background-color: rgba(234, 234, 233, 1);
}
.infobar {
margin: 5px 10px;
width: 550px;
height: 1.2em;
clear: both;
font-size: small;
}
.infobar .infoleft {
width: 200px;
display: block;
float: left;
}
.infobar .inforight {
width: 350px;
display: block;
float: right;
text-align: right;
}
.network-overview .tablink {
width: 6.5em;
float: left;
font-size: smaller;
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -303,7 +303,7 @@ function Bigscape(bs_data, bs_families, bs_alignment, bs_similarity, network_con
this.setHighlightedNodes = function(ids) { highlighted_nodes = ids; };
this.getHighlightedNodes = function() { return highlighted_nodes; };
var updateDescription = function(ids = highlighted_nodes) {
BigscapeFunc.updateDescription(ids, bs_svg, bs_data, bs_to_cl, bs_families, bs_alignment, desc_ui, nav_ui, det_ui, bigscape);
BigscapeFunc.updateDescription(ids, bs_svg, bs_data, bs_to_cl, bs_families, bs_similarity, bs_alignment, desc_ui, nav_ui, det_ui, bigscape);
};
this.updateDescription = updateDescription;
......@@ -373,7 +373,7 @@ function Bigscape(bs_data, bs_families, bs_alignment, bs_similarity, network_con
updateDescription(highlighted_nodes);
handler.stopPropagation();
});
$(ui).contextmenu({id: node.id, bs_svg: bs_svg, bs_data: bs_data, bs_families: bs_families, bs_to_cl: bs_to_cl, det_ui: det_ui, context_ui: context_ui}, function(handler) {
$(ui).contextmenu({id: node.id, bs_svg: bs_svg, bs_data: bs_data, bs_families: bs_families, bs_similarity: bs_similarity, bs_to_cl: bs_to_cl, det_ui: det_ui, context_ui: context_ui}, function(handler) {
var ul = $("<ul>");
//
var aShowDetail = $("<a href='##'>Show details</a>");
......@@ -390,8 +390,8 @@ function Bigscape(bs_data, bs_families, bs_alignment, bs_similarity, network_con
($("<li>").appendTo(ul)).append(aShowDetail);
//
var aShowFamDetail = $("<a href='##'>Show family details</a>");
aShowFamDetail.click({id: handler.data.id, id_fam: bs_to_cl[handler.data.id], bs_svg: handler.data.bs_svg, bs_data: handler.data.bs_data, bs_families: handler.data.bs_families, bs_to_cl: handler.data.bs_to_cl, det_ui: handler.data.det_ui, context_ui: handler.data.context_ui}, function(handler){
BigscapeFunc.openFamDetail(handler.data.id_fam, [handler.data.id], handler.data.bs_svg, handler.data.bs_data, handler.data.bs_to_cl, handler.data.bs_families, handler.data.det_ui);;
aShowFamDetail.click({id: handler.data.id, id_fam: bs_to_cl[handler.data.id], bs_svg: handler.data.bs_svg, bs_data: handler.data.bs_data, bs_families: handler.data.bs_families, bs_similarity: handler.data.bs_similarity, bs_to_cl: handler.data.bs_to_cl, det_ui: handler.data.det_ui, context_ui: handler.data.context_ui}, function(handler){
BigscapeFunc.openFamDetail(handler.data.id_fam, [handler.data.id], handler.data.bs_svg, handler.data.bs_data, handler.data.bs_to_cl, handler.data.bs_families, handler.data.bs_similarity, handler.data.det_ui);;
handler.data.context_ui.addClass("hidden");
handler.data.det_ui.parent().removeClass("hidden");
handler.data.det_ui.find("svg.arrower-svg").each(function(){
......@@ -494,7 +494,7 @@ BigscapeFunc.showSingletons = function(graph, graphics, net_ui, isOn) {
}
// ...
BigscapeFunc.updateDescription = function(ids, bs_svg, bs_data, bs_to_cl, bs_families, bs_alignment, desc_ui, nav_ui, det_ui, bigscape) {
BigscapeFunc.updateDescription = function(ids, bs_svg, bs_data, bs_to_cl, bs_families, bs_similarity, bs_alignment, desc_ui, nav_ui, det_ui, bigscape) {
if (desc_ui.children().length < 1) {
// first time rendering desc_ui
desc_ui.html("");
......@@ -527,8 +527,8 @@ BigscapeFunc.updateDescription = function(ids, bs_svg, bs_data, bs_to_cl, bs_fam
var li = $("<li id='bs-desc_ui-li_fam-" + i + "'>");
li.append("<a href='##' class='li-check'></a>");
li.append("<a href='##' class='li-opendetail'>" + bs_families[i]["id"] + "</a>");
li.find("a.li-opendetail").click({id_fam: i, ids_highlighted: ids, bs_svg: bs_svg, bs_data: bs_data, bs_families: bs_families, bs_to_cl: bs_to_cl, det_ui: det_ui}, function(handler){
BigscapeFunc.openFamDetail(handler.data.id_fam, handler.data.ids_highlighted, handler.data.bs_svg, handler.data.bs_data, handler.data.bs_to_cl, handler.data.bs_families, handler.data.det_ui);
li.find("a.li-opendetail").click({id_fam: i, ids_highlighted: ids, bs_svg: bs_svg, bs_data: bs_data, bs_families: bs_families, bs_to_cl: bs_to_cl, det_ui: det_ui, bs_similarity: bs_similarity}, function(handler){
BigscapeFunc.openFamDetail(handler.data.id_fam, handler.data.ids_highlighted, handler.data.bs_svg, handler.data.bs_data, handler.data.bs_to_cl, handler.data.bs_families, handler.data.bs_similarity, handler.data.det_ui);
handler.data.det_ui.parent().removeClass("hidden");
handler.data.det_ui.find("svg.arrower-svg").each(function(){
$(this).attr("width", $(this).find("g")[0].getBoundingClientRect().width);
......@@ -802,10 +802,66 @@ BigscapeFunc.openCompDetail = function(ids, bs_svg, bs_data, bs_to_cl, bs_famili
}
// ...
BigscapeFunc.openFamDetail = function(id_fam, ids_highlighted, bs_svg, bs_data, bs_to_cl, bs_families, det_ui) {
BigscapeFunc.openFamDetail = function(id_fam, ids_highlighted, bs_svg, bs_data, bs_to_cl, bs_families, bs_similarity, det_ui) {
det_ui.html("");
det_ui.append("<h2>" + bs_families[id_fam]["id"] + "<h2>");
var treeContainer = $("<div><h3>Members</h3></div>").appendTo(det_ui);
treeContainer.css({
"margin-left": 10
});
var relatedFamily = $("<div><h3>Related Families</h3></div").appendTo(det_ui);
relatedFamily.css({
"margin-left": 10
});
if ((id_fam > -1) && (id_fam < bs_families.length)) {
// get clan info
var clanTab = $("<table><thead><tr><th>Family</th><th>Members</th><th>Closest distance</th><th>Furthest distance</th><th>Average distance</th></tr></thead><tbody></tbody></table>").appendTo(relatedFamily);
clanTab.css({
"border": "1px solid black",
"width": "100%"
});
if (true) {//(bs_families[id_fam].hasOwnProperty("clan")) {
var related_families = [];
for (var i in bs_families) {
if (bs_families[i]["id"] !== bs_families[id_fam]["id"]) {
if (true) {//(bs_families[i].hasOwnProperty("clan")) {
if (true) {//(bs_families[i]["clan"] === bs_families[id_fam]["clan"]) {
var bs_sim = (i < id_fam)? bs_similarity_families[id_fam][i]:bs_similarity_families[i][id_fam];
related_families.push({
"idx": i,
"id": bs_families[i]["id"],
"members": bs_families[i]["members"].length,
"shortest": bs_sim[2],
"longest": bs_sim[1],
"average": bs_sim[0]
});
}
}
}
}
related_families = related_families.sort(function(a, b) { return b["average"] - a["average"] });
for (var i in related_families) {
if (related_families[i]["average"] > 0.5) {
var famLink = $("<a href='##'>" + related_families[i]["id"] +"</a>");
famLink.click({id_fam: related_families[i]["idx"], bs_svg: bs_svg, bs_data: bs_data, bs_families: bs_families, bs_to_cl: bs_to_cl, det_ui: det_ui, bs_similarity: bs_similarity}, function(handler){
BigscapeFunc.openFamDetail(handler.data.id_fam, [], handler.data.bs_svg, handler.data.bs_data, handler.data.bs_to_cl, handler.data.bs_families, handler.data.bs_similarity, handler.data.det_ui);;
handler.data.det_ui.parent().removeClass("hidden");
handler.data.det_ui.find("svg.arrower-svg").each(function(){
$(this).attr("width", $(this).find("g")[0].getBoundingClientRect().width);
$(this).attr("height", $(this).find("g")[0].getBoundingClientRect().height);
});
handler.stopPropagation();
});
$("<tr>").appendTo(clanTab.find("tbody"))
.append($("<td>").append(famLink))
.append("<td>" + related_families[i]["members"] + "</td>")
.append("<td>" + (1.00 - related_families[i]["shortest"][0]).toFixed(2) + "</td>")
.append("<td>" + (1.00 - related_families[i]["longest"][0]).toFixed(2) + "</td>")
.append("<td>" + (1.00 - related_families[i]["average"]).toFixed(2) + "</td>");
}
}
}
// get tree info
var fam_aln = bs_families_alignment[id_fam];
/* FUNCTION BLOCK, DRAWING THE TREE */
function getBGCOffset(bgc_ref, bgc, genes_ref, aln) {
......@@ -829,7 +885,7 @@ BigscapeFunc.openFamDetail = function(id_fam, ids_highlighted, bs_svg, bs_data,
}
var treeData = new Tree();
treeData.Parse(fam_aln["newick"]);
var treeSVG = $("<svg id='det_fam_tree' width='3000' height='" + ((bs_families[id_fam]["members"].length * 40) + 50) + "'></svg>").appendTo(det_ui);
var treeSVG = $("<svg id='det_fam_tree' width='3000' height='" + ((bs_families[id_fam]["members"].length * 20) + 30) + "'></svg>").appendTo(treeContainer);
var treeDrawer = new PhylogramTreeDrawer();
treeDrawer.Init(treeData, { svg_id: 'det_fam_tree', height: ((treeData.num_leaves - 1) * 40), width: 400 } );
treeDrawer.draw_scale_bar = false;
......
var bigscape_results = [
];
\ No newline at end of file
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* Extended Newick format parser in JavaScript.
*
* Copyright (c) Miguel Pignatelli 2014 based on Jason Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Example tree (from http://en.wikipedia.org/wiki/Newick_format):
*
* +--0.1--A
* F-----0.2-----B +-------0.3----C
* +------------------0.5-----E
* +---------0.4------D
*
* Newick format:
* (A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;
*
* Converted to JSON:
* {
* name: "F",
* children: [
* {name: "A", branch_length: 0.1},
* {name: "B", branch_length: 0.2},
* {
* name: "E",
* length: 0.5,
* children: [
* {name: "C", branch_length: 0.3},
* {name: "D", branch_length: 0.4}
* ]
* }
* ]
* }
*
* Converted to JSON, but with no names or lengths:
* {
* children: [
* {}, {}, {
* children: [{}, {}]
* }
* ]
* }
*/
module.exports = parse_nhx = function(s) {
var ancestors = [];
var tree = {};
// var tokens = s.split(/\s*(;|\(|\)|,|:)\s*/);
//[&&NHX:D=N:G=ENSG00000139618:T=9606]
var tokens = s.split( /\s*(;|\(|\)|\[|\]|,|:|=)\s*/ );
for (var i=0; i<tokens.length; i++) {
var token = tokens[i];
switch (token) {
case '(': // new children
var subtree = {};
tree.children = [subtree];
ancestors.push(tree);
tree = subtree;
break;
case ',': // another branch
var subtree = {};
ancestors[ancestors.length-1].children.push(subtree);
tree = subtree;
break;
case ')': // optional name next
tree = ancestors.pop();
break;
case ':': // optional length next
break;
default:
var x = tokens[i-1];
// var x2 = tokens[i-2];
if (x == ')' || x == '(' || x == ',') {
tree.name = token;
}
else if (x == ':') {
var test_type = typeof token;
if(!isNaN(token)){
tree.branch_length = parseFloat(token);
}
// tree.length = parseFloat(token);
}
else if (x == '='){
var x2 = tokens[i-2];
switch(x2){
case 'D':
tree.duplication = token;
break;
case 'G':
tree.gene_id = token;
break;
case 'T':
tree.taxon_id = token;
break;
}
}
else {
var test;
}
}
}
return tree;
};
},{}],"H99CHA":[function(require,module,exports){
module.exports = require('./newick');
module.exports.parse_nhx = require('./extended_newick');
},{"./extended_newick":1,"./newick":4}],"biojs-io-newick":[function(require,module,exports){
module.exports=require('H99CHA');
},{}],4:[function(require,module,exports){
/**
* Newick format parser in JavaScript.
*
* Copyright (c) edited by Miguel Pignatelli 2014, based on Jason Davies 2010.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Example tree (from http://en.wikipedia.org/wiki/Newick_format):
*
* +--0.1--A
* F-----0.2-----B +-------0.3----C
* +------------------0.5-----E
* +---------0.4------D
*
* Newick format:
* (A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;
*
* Converted to JSON:
* {
* name: "F",
* children: [
* {name: "A", branch_length: 0.1},
* {name: "B", branch_length: 0.2},
* {
* name: "E",
* length: 0.5,