Skip to content

Commit

Permalink
allow newick files to be dragged & dropped
Browse files Browse the repository at this point in the history
  • Loading branch information
jameshadfield committed Apr 30, 2019
1 parent ae3b4f3 commit bdb4a2f
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 2 deletions.
8 changes: 6 additions & 2 deletions auspice.us/client-customisations/handleDroppedFiles.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createStateFromQueryOrJSONs } from "@auspice/actions/recomputeReduxState";

import newickToAuspiceJson from "./newickToAuspiceJson";

export const handleDroppedFiles = (dispatch, files) => {
const file = files[0];
Expand All @@ -19,7 +19,11 @@ export const handleDroppedFiles = (dispatch, files) => {
if (file.type === "application/json") {
jsonData = JSON.parse(fileReader.result);
} else if (file.name.endsWith(".new") || file.name.endsWith(".newick") || file.name.endsWith(".nwk")) {
console.log("attempting to parse a newick tree");
try {
jsonData = newickToAuspiceJson(file.name, fileReader.result);
} catch (err) {
return errorCB(err);
}
} else {
return errorCB("Unknown filetype");
}
Expand Down
95 changes: 95 additions & 0 deletions auspice.us/client-customisations/newickToAuspiceJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Newick format parser in JavaScript.
*
* Copyright (c) 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.
*/
const parseNewick = (nwk) => {
const ancestors = [];
let tree = {};
const tokens = nwk.split(/\s*(;|\(|\)|,|:)\s*/);
for (let i=0; i<tokens.length; i++) {
const token = tokens[i];
const subtree = {};
switch (token) {
case '(': // new child nodes up next
tree.children = [subtree];
ancestors.push(tree);
tree = subtree;
break;
case ',': // next node: another child of the last ancestor
ancestors[ancestors.length-1].children.push(subtree);
tree = subtree;
break;
case ')': // optional name next
tree = ancestors.pop();
break;
case ':': // optional length next
break;
default:
const x = tokens[i-1];
if (x === ')' || x === '(' || x === ',') {
tree.strain = token;
} else if (x === ':') {
tree.div = parseFloat(token);
}
}
}
return tree;
};

const getTreeStruct = (nwk) => {
const tree = parseNewick(nwk);

/* ensure every node has a strain name */
let count = 10000;
const addNodeName = (node) => {
if (!node.strain) {
node.strain=`NODE${count}`;
count++;
}
if (node.children) {
node.children.forEach((child) => addNodeName(child));
}
};
addNodeName(tree);

/* div should be cumulative! */
const cumulativeDivs = (node, soFar=0) => {
node.div += soFar;
if (node.children) {
node.children.forEach((child) => cumulativeDivs(child, node.div));
}
};
cumulativeDivs(tree);


return tree;
};

/**
* Convert a newick string to an auspice (v2) JSON
* @param {string} nwk newick string
* @returns {object} auspice JSON
*/
const newickToAuspiceJson = (name, nwk) => {
const json = {
title: name,
tree: getTreeStruct(nwk),
panels: ["tree"],
version: "2.0"
};
return json;
};


export default newickToAuspiceJson;

0 comments on commit bdb4a2f

Please sign in to comment.