hyphy-scope
Version:
Reusable Svelte components for HyPhy analysis visualization
104 lines (103 loc) • 3.15 kB
JavaScript
/**
* FUBAR (Fast Unconstrained Bayesian AppRoximation) utility functions
*/
/**
* Get summary statistics for FUBAR results
*/
export function getFubarSummary(data, posteriorProbability = 0.9) {
if (!data?.MLE?.content) {
return {
positiveSites: 0,
negativeSites: 0,
totalSites: 0
};
}
const flattenedData = Object.values(data.MLE.content).flat();
const positiveSites = flattenedData.filter(row => row[4] > posteriorProbability).length;
const negativeSites = flattenedData.filter(row => row[3] > posteriorProbability).length;
return {
positiveSites,
negativeSites,
totalSites: flattenedData.length
};
}
/**
* Get site-by-site data for FUBAR results
*/
export function getFubarSiteData(data) {
if (!data?.MLE?.content)
return [];
const flattenedData = Object.values(data.MLE.content).flat();
const partitionColumn = getPartitionColumn(data);
return flattenedData.map((row, index) => ({
Site: index + 1,
Partition: partitionColumn[index] + 1,
α: row[0],
β: row[1],
'α-β': row[2],
'Prob[α>β]': row[3],
'Prob[α<β]': row[4]
}));
}
/**
* Get partition column mapping
*/
export function getPartitionColumn(data) {
if (!data?.['data partitions'])
return [];
const flattenedLength = Object.values(data.MLE.content).flat().length;
const partitionColumn = new Array(flattenedLength).fill(0);
Object.entries(data['data partitions']).forEach(([key, val], partitionIndex) => {
val.coverage[0].forEach(siteIndex => {
partitionColumn[siteIndex] = partitionIndex;
});
});
return partitionColumn;
}
/**
* Extract tree newick string from various input formats
*/
export function getTreeNewick(data) {
if (!data?.input?.trees)
return null;
const trees = data.input.trees;
// Handle different tree formats
if (typeof trees === 'string') {
return trees;
}
else if (Array.isArray(trees)) {
return trees[0] || null;
}
else if (typeof trees === 'object') {
const treeKeys = Object.keys(trees);
return treeKeys.length > 0 ? trees[treeKeys[0]] : null;
}
return null;
}
/**
* Get grid data for a specific site
*/
export function getGridDataForSite(data, site) {
if (!data?.posterior || !data?.['data partitions'] || !data.grid) {
return data.grid;
}
// Find partition and index for this site
let partition = 0;
let index = -1;
const partitions = Object.values(data['data partitions']);
for (let p = 0; p < partitions.length; p++) {
const coverage = partitions[p].coverage[0];
const idx = coverage.indexOf(site - 1);
if (idx > -1) {
partition = p;
index = idx;
break;
}
}
if (index === -1)
return data.grid;
// Get site-specific posterior
const sitePosterior = data.posterior[partition][index][0];
// Combine with grid coordinates
return data.grid.map((d, i) => [d[0], d[1], sitePosterior[i]]);
}