UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

97 lines (96 loc) 3.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.euclideanDistance = euclideanDistance; exports.averageDistance = averageDistance; exports.clusterData = clusterData; const stopToken_1 = require("@jbrowse/core/util/stopToken"); function toP(n) { return Number.parseFloat((n * 100).toFixed(1)); } function euclideanDistance(a, b) { const size = Math.min(a.length, b.length); let sum = 0; for (let index = 0; index < size; index++) { sum += (a[index] - b[index]) * (a[index] - b[index]); } return Math.sqrt(sum); } function averageDistance(setA, setB, distances) { let distance = 0; const lenA = setA.length; const lenB = setB.length; for (let i = 0; i < lenA; i++) { for (let j = 0; j < lenB; j++) { distance += distances[setA[i]][setB[j]]; } } return distance / setA.length / setB.length; } function clusterData({ data, distance = euclideanDistance, linkage = averageDistance, onProgress, stopToken, }) { let start = performance.now(); const distances = []; for (let i = 0; i < data.length; i++) { if (performance.now() - start > 400) { (0, stopToken_1.checkStopToken)(stopToken); start = performance.now(); } if (onProgress) { onProgress(`Making distance matrix: ${toP(i / (data.length - 1))}%`); } const row = []; for (let j = 0; j < data.length; j++) { row.push(distance(data[i], data[j])); } distances.push(row); } const clusters = data.map((_datum, index) => ({ height: 0, indexes: [Number(index)], })); let clustersGivenK = []; start = performance.now(); for (let iteration = 0; iteration < data.length; iteration++) { if (performance.now() - start > 400) { (0, stopToken_1.checkStopToken)(stopToken); start = performance.now(); } if (onProgress) { onProgress(`Clustering: ${toP((iteration + 1) / data.length)}%`); } clustersGivenK.push(clusters.map(cluster => cluster.indexes)); if (iteration >= data.length - 1) { break; } let nearestDistance = Infinity; let nearestRow = 0; let nearestCol = 0; for (let row = 0; row < clusters.length; row++) { for (let col = row + 1; col < clusters.length; col++) { const distance = linkage(clusters[row].indexes, clusters[col].indexes, distances); if (distance < nearestDistance) { nearestDistance = distance; nearestRow = row; nearestCol = col; } } } const newCluster = { indexes: [ ...clusters[nearestRow].indexes, ...clusters[nearestCol].indexes, ], height: nearestDistance, children: [clusters[nearestRow], clusters[nearestCol]], }; clusters.splice(Math.max(nearestRow, nearestCol), 1); clusters.splice(Math.min(nearestRow, nearestCol), 1); clusters.push(newCluster); } clustersGivenK = [[], ...clustersGivenK.reverse()]; return { clusters: clusters[0], distances: distances, order: clusters[0].indexes, clustersGivenK: clustersGivenK, }; }