UNPKG

phylojs

Version:

A simple typescript library for phylogenetic trees

108 lines (107 loc) 3.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readTreesFromNexus = exports.readNexus = exports.getTranslateFromNexus = void 0; const error_1 = require("../../utils/error"); const newick_1 = require("./newick"); // Function to extract the translate mapping function getTranslateFromNexus(nexus) { const tmap = {}; const lines = nexus.split('\n'); let fullLine = ''; for (let i = 1; i < lines.length; i++) { fullLine += lines[i].trim(); // Remove comments fullLine = fullLine.replace(/\[[^&][^\]]*\]/g, '').trim(); // Parse translate line if (fullLine.toLowerCase().startsWith('translate')) { const tStringArray = fullLine.slice(9, fullLine.length - 1).split(','); for (let j = 0; j < tStringArray.length; j++) { const tvec = tStringArray[j].trim().split(/\s+/); const tkey = tvec[0]; let tval = tvec.slice(1).join(' '); tval = tval.replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'); tmap[tkey] = tval; } break; } } return tmap; } exports.getTranslateFromNexus = getTranslateFromNexus; function translateTree(tree, tmap) { // traverse nodes tree.root.applyPreOrder(node => { // If node's identifier exists in tmap, replace it if (node.label && tmap[node.label]) { node.label = tmap[node.label]; } }); return tree; } function _getTreesFromNexus(nexus, singleTree) { const trees = []; const lines = nexus.split('\n'); let inTrees = false; let fullLine = ''; const tmap = getTranslateFromNexus(nexus); // Retrieve the translation mapping for (let i = 1; i < lines.length; i++) { fullLine += lines[i].trim(); if (fullLine[fullLine.length - 1] !== ';') continue; // Remove comments fullLine = fullLine.replace(/\[[^&][^\]]*\]/g, '').trim(); if (!inTrees) { if (fullLine.toLowerCase() === 'begin trees;') inTrees = true; fullLine = ''; continue; } if (fullLine.toLowerCase() === 'end;') break; // Parse tree line const matches = /tree (\w|\.)+ *(\[&[^\]]*] *)* *= *(\[&[^\]]*] *)* */.exec(fullLine.toLowerCase()); if (matches !== null) { const eqIdx = matches[0].length; try { let tree = (0, newick_1.readNewick)(fullLine.slice(eqIdx)); tree = translateTree(tree, tmap); // Use the translation map here trees.push(tree); if (singleTree) return trees; // If only one tree is requested, return immediately } catch (e) { if (e instanceof error_1.SkipTreeException) { console.log('Skipping Nexus tree: ' + e.message); } else { throw e; } } } fullLine = ''; } return trees; } /** * Reads a tree from nexus format. Currently does not support custom annotation parsing. * @param {string} nexus * @returns {Tree} */ function readNexus(nexus) { const trees = _getTreesFromNexus(nexus, true); if (trees.length === 0) { throw new Error('No trees found in Nexus.'); } return trees[0]; } exports.readNexus = readNexus; /** * Reads trees from from nexus format. * @param {string} nexus * @returns {Tree[]} */ function readTreesFromNexus(nexus) { const trees = _getTreesFromNexus(nexus, false); return trees; } exports.readTreesFromNexus = readTreesFromNexus;