igv 2.15.0 → 2.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/igv.esm.js +689 -175
- package/dist/igv.esm.min.js +6 -6
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +689 -175
- package/dist/igv.min.js +6 -6
- package/dist/igv.min.js.map +1 -1
- package/package.json +2 -2
package/dist/igv.esm.js
CHANGED
|
@@ -18656,6 +18656,8 @@ class IGVXhr {
|
|
|
18656
18656
|
|
|
18657
18657
|
async _loadURL(url, options) {
|
|
18658
18658
|
|
|
18659
|
+
const self = this;
|
|
18660
|
+
|
|
18659
18661
|
//console.log(`${Date.now()} ${url}`)
|
|
18660
18662
|
url = mapUrl$1(url);
|
|
18661
18663
|
|
|
@@ -18745,7 +18747,7 @@ class IGVXhr {
|
|
|
18745
18747
|
// For small files a range starting at 0 can return the whole file => 200
|
|
18746
18748
|
// Provide just the slice we asked for, throw out the rest quietly
|
|
18747
18749
|
// If file is large warn user
|
|
18748
|
-
if (xhr.response.length > 100000 && !
|
|
18750
|
+
if (xhr.response.length > 100000 && !self.RANGE_WARNING_GIVEN) {
|
|
18749
18751
|
alert(`Warning: Range header ignored for URL: ${url}. This can have severe performance impacts.`);
|
|
18750
18752
|
}
|
|
18751
18753
|
resolve(xhr.response.slice(range.start, range.start + range.size));
|
|
@@ -18774,8 +18776,9 @@ class IGVXhr {
|
|
|
18774
18776
|
xhr.onerror = function (event) {
|
|
18775
18777
|
if (isGoogleURL(url) && !options.retries) {
|
|
18776
18778
|
tryGoogleAuth();
|
|
18779
|
+
} else {
|
|
18780
|
+
handleError("Error accessing resource: " + url + " Status: " + xhr.status);
|
|
18777
18781
|
}
|
|
18778
|
-
handleError("Error accessing resource: " + url + " Status: " + xhr.status);
|
|
18779
18782
|
};
|
|
18780
18783
|
|
|
18781
18784
|
xhr.ontimeout = function (event) {
|
|
@@ -18790,7 +18793,11 @@ class IGVXhr {
|
|
|
18790
18793
|
try {
|
|
18791
18794
|
xhr.send(sendData);
|
|
18792
18795
|
} catch (e) {
|
|
18793
|
-
|
|
18796
|
+
if (isGoogleURL(url) && !options.retries) {
|
|
18797
|
+
tryGoogleAuth();
|
|
18798
|
+
} else {
|
|
18799
|
+
handleError(e);
|
|
18800
|
+
}
|
|
18794
18801
|
}
|
|
18795
18802
|
|
|
18796
18803
|
|
|
@@ -18807,7 +18814,7 @@ class IGVXhr {
|
|
|
18807
18814
|
const accessToken = await fetchGoogleAccessToken(url);
|
|
18808
18815
|
options.retries = 1;
|
|
18809
18816
|
options.oauthToken = accessToken;
|
|
18810
|
-
const response = await
|
|
18817
|
+
const response = await self.load(url, options);
|
|
18811
18818
|
resolve(response);
|
|
18812
18819
|
} catch (e) {
|
|
18813
18820
|
if (e.error) {
|
|
@@ -18953,14 +18960,16 @@ function addTeamDrive(url) {
|
|
|
18953
18960
|
*/
|
|
18954
18961
|
function mapUrl$1(url) {
|
|
18955
18962
|
|
|
18956
|
-
if (url.
|
|
18963
|
+
if (url.startsWith("https://www.dropbox.com")) {
|
|
18957
18964
|
return url.replace("//www.dropbox.com", "//dl.dropboxusercontent.com")
|
|
18958
|
-
} else if (url.
|
|
18965
|
+
} else if (url.startsWith("https://drive.google.com")) {
|
|
18959
18966
|
return getDriveDownloadURL(url)
|
|
18960
18967
|
} else if (url.includes("//www.broadinstitute.org/igvdata")) {
|
|
18961
18968
|
return url.replace("//www.broadinstitute.org/igvdata", "//data.broadinstitute.org/igvdata")
|
|
18962
18969
|
} else if (url.includes("//igvdata.broadinstitute.org")) {
|
|
18963
|
-
return url.replace("//igvdata.broadinstitute.org", "
|
|
18970
|
+
return url.replace("//igvdata.broadinstitute.org", "//s3.amazonaws.com/igv.broadinstitute.org")
|
|
18971
|
+
} else if (url.includes("//igv.genepattern.org")) {
|
|
18972
|
+
return url.replace("//igv.genepattern.org", "//igv-genepattern-org.s3.amazonaws.com")
|
|
18964
18973
|
} else if (url.startsWith("ftp://ftp.ncbi.nlm.nih.gov/geo")) {
|
|
18965
18974
|
return url.replace("ftp://", "https://")
|
|
18966
18975
|
} else {
|
|
@@ -23922,7 +23931,7 @@ const Cytoband = function (start, end, name, typestain) {
|
|
|
23922
23931
|
}
|
|
23923
23932
|
};
|
|
23924
23933
|
|
|
23925
|
-
const _version = "2.15.
|
|
23934
|
+
const _version = "2.15.2";
|
|
23926
23935
|
function version() {
|
|
23927
23936
|
return _version
|
|
23928
23937
|
}
|
|
@@ -25759,15 +25768,15 @@ function decodeGTF(tokens, header) {
|
|
|
25759
25768
|
* @param keyValueDelim
|
|
25760
25769
|
* @returns {[]}
|
|
25761
25770
|
*/
|
|
25762
|
-
function parseAttributeString(attributeString, keyValueDelim) {
|
|
25771
|
+
function parseAttributeString(attributeString, keyValueDelim, relaxed = false) {
|
|
25763
25772
|
// parse 'attributes' string (see column 9 docs in https://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md)
|
|
25764
25773
|
var attributes = [];
|
|
25765
25774
|
for (let kv of attributeString.split(';')) {
|
|
25766
25775
|
kv = kv.trim();
|
|
25767
25776
|
const idx = kv.indexOf(keyValueDelim);
|
|
25768
25777
|
if (idx > 0 && idx < kv.length - 1) {
|
|
25769
|
-
const key = kv.substring(0, idx);
|
|
25770
|
-
let value = stripQuotes(decodeGFFAttribute(kv.substring(idx + 1).trim()));
|
|
25778
|
+
const key = stripQuotes(decodeGFFAttribute(kv.substring(0, idx).trim(), relaxed));
|
|
25779
|
+
let value = stripQuotes(decodeGFFAttribute(kv.substring(idx + 1).trim(), relaxed));
|
|
25771
25780
|
attributes.push([key, value]);
|
|
25772
25781
|
}
|
|
25773
25782
|
}
|
|
@@ -25806,11 +25815,14 @@ const encodings = new Map([
|
|
|
25806
25815
|
["%2C", ","]
|
|
25807
25816
|
]);
|
|
25808
25817
|
|
|
25809
|
-
function decodeGFFAttribute(str) {
|
|
25818
|
+
function decodeGFFAttribute(str, relaxed = false) {
|
|
25810
25819
|
|
|
25811
25820
|
if (!str.includes("%")) {
|
|
25812
25821
|
return str
|
|
25813
25822
|
}
|
|
25823
|
+
if (relaxed) {
|
|
25824
|
+
return decodeURIComponent(str);
|
|
25825
|
+
}
|
|
25814
25826
|
let decoded = "";
|
|
25815
25827
|
for (let i = 0; i < str.length; i++) {
|
|
25816
25828
|
|
|
@@ -25868,7 +25880,7 @@ function decodeBed(tokens, header) {
|
|
|
25868
25880
|
|
|
25869
25881
|
// Potentially parse name field as GFF column 9 style streng.
|
|
25870
25882
|
if (tokens[3].indexOf(';') > 0 && tokens[3].indexOf('=') > 0) {
|
|
25871
|
-
const attributeKVs = parseAttributeString(tokens[3], '=');
|
|
25883
|
+
const attributeKVs = parseAttributeString(tokens[3], '=', true);
|
|
25872
25884
|
feature.attributes = {};
|
|
25873
25885
|
for (let kv of attributeKVs) {
|
|
25874
25886
|
feature.attributes[kv[0]] = kv[1];
|
|
@@ -25916,7 +25928,25 @@ function decodeBed(tokens, header) {
|
|
|
25916
25928
|
}
|
|
25917
25929
|
|
|
25918
25930
|
if (tokens.length > 11) {
|
|
25919
|
-
const
|
|
25931
|
+
const exonCount = parseInt(tokens[9]);
|
|
25932
|
+
// Some basic validation
|
|
25933
|
+
if (exonCount > 1000) {
|
|
25934
|
+
// unlikely
|
|
25935
|
+
return feature
|
|
25936
|
+
}
|
|
25937
|
+
|
|
25938
|
+
const exonSizes = tokens[10].replace(/,$/, '').split(',');
|
|
25939
|
+
const exonStarts = tokens[11].replace(/,$/, '').split(',');
|
|
25940
|
+
if (!(exonSizes.length === exonStarts.length && exonCount === exonSizes.length)) {
|
|
25941
|
+
return feature
|
|
25942
|
+
}
|
|
25943
|
+
|
|
25944
|
+
const exons = [];
|
|
25945
|
+
for (let i = 0; i < exonCount; i++) {
|
|
25946
|
+
const eStart = start + parseInt(exonStarts[i]);
|
|
25947
|
+
const eEnd = eStart + parseInt(exonSizes[i]);
|
|
25948
|
+
exons.push({start: eStart, end: eEnd});
|
|
25949
|
+
}
|
|
25920
25950
|
if (exons.length > 0) {
|
|
25921
25951
|
findUTRs$1(exons, feature.cdStart, feature.cdEnd);
|
|
25922
25952
|
feature.exons = exons;
|
|
@@ -25940,7 +25970,6 @@ function decodeBed(tokens, header) {
|
|
|
25940
25970
|
}
|
|
25941
25971
|
|
|
25942
25972
|
return feature
|
|
25943
|
-
|
|
25944
25973
|
}
|
|
25945
25974
|
|
|
25946
25975
|
/**
|
|
@@ -27252,6 +27281,8 @@ class TrackBase {
|
|
|
27252
27281
|
}
|
|
27253
27282
|
tracklineConfg.autoscale = false;
|
|
27254
27283
|
tracklineConfg.dataRange = {min, max};
|
|
27284
|
+
this.viewLimitMin = min;
|
|
27285
|
+
this.viewLimitMax = max;
|
|
27255
27286
|
}
|
|
27256
27287
|
case "name":
|
|
27257
27288
|
tracklineConfg[key] = properties[key];
|
|
@@ -29150,9 +29181,9 @@ function optimizeChunks(chunks, lowest) {
|
|
|
29150
29181
|
* @returns {boolean|boolean}
|
|
29151
29182
|
*/
|
|
29152
29183
|
function canMerge(chunk1, chunk2) {
|
|
29153
|
-
|
|
29184
|
+
chunk2.minv.block - chunk1.maxv.block;
|
|
29154
29185
|
const sizeEstimate = chunk1.maxv.block - chunk1.minv.block;
|
|
29155
|
-
return
|
|
29186
|
+
return sizeEstimate < 5000000
|
|
29156
29187
|
}
|
|
29157
29188
|
|
|
29158
29189
|
// Represents a CSI Bam or Tabix index
|
|
@@ -40775,8 +40806,8 @@ class FeatureTrack extends TrackBase {
|
|
|
40775
40806
|
color = IGVColor.addAlpha(color, feature.alpha);
|
|
40776
40807
|
} else if (this.useScore && feature.score && !Number.isNaN(feature.score)) {
|
|
40777
40808
|
// UCSC useScore option, for scores between 0-1000. See https://genome.ucsc.edu/goldenPath/help/customTrack.html#TRACK
|
|
40778
|
-
const min = this.config.min ? this.config.min : 0;
|
|
40779
|
-
const max = this.config.max ? this.config.max : 1000;
|
|
40809
|
+
const min = this.config.min ? this.config.min : this.viewLimitMin ? this.viewLimitMin : 0;
|
|
40810
|
+
const max = this.config.max ? this.config.max : this.viewLimitMax ? this.viewLimitMax : 1000;
|
|
40780
40811
|
const alpha = getAlpha(min, max, feature.score);
|
|
40781
40812
|
feature.alpha = alpha; // Avoid computing again
|
|
40782
40813
|
color = IGVColor.addAlpha(color, alpha);
|
|
@@ -54145,11 +54176,13 @@ class HDF5Reader {
|
|
|
54145
54176
|
|
|
54146
54177
|
// console.log(h5_obj_keys)
|
|
54147
54178
|
let signal_bin = new ParseSignals(h5_obj_keys);
|
|
54148
|
-
|
|
54179
|
+
let rd_bins = signal_bin.get_rd_bins();
|
|
54180
|
+
let snp_bins = signal_bin.get_snp_bins();
|
|
54181
|
+
this.available_bins = [...new Set(rd_bins, snp_bins)];
|
|
54149
54182
|
|
|
54150
54183
|
// let bin_size = this.bin_size
|
|
54151
|
-
if(! this.
|
|
54152
|
-
bin_size = this.
|
|
54184
|
+
if(! this.available_bins.includes(bin_size)){
|
|
54185
|
+
bin_size = this.available_bins.at(-1);
|
|
54153
54186
|
}
|
|
54154
54187
|
|
|
54155
54188
|
const chr_ds = await h5_obj.get("rd_chromosomes");
|
|
@@ -54193,6 +54226,9 @@ class HDF5Reader {
|
|
|
54193
54226
|
let signal_baf_1 = `snp_likelihood_${chrom}_${bin_size}_mask`;
|
|
54194
54227
|
let chr_wig_bafs = await this.get_baf_signals(h5_obj, h5_obj_keys, chrom, bin_size, signal_baf_1);
|
|
54195
54228
|
|
|
54229
|
+
// let signal_baf_1 = `snp_i1_${chrom}_${bin_size}_mask`
|
|
54230
|
+
// let chr_wig_bafs = await this.get_baf_signals_v2(h5_obj, h5_obj_keys, chrom, bin_size, signal_baf_1)
|
|
54231
|
+
|
|
54196
54232
|
wigFeatures_baf1 = wigFeatures_baf1.concat(chr_wig_bafs[0]);
|
|
54197
54233
|
wigFeatures_baf2 = wigFeatures_baf2.concat(chr_wig_bafs[1]);
|
|
54198
54234
|
// this.rd_call_combined(h5_obj, h5_obj_keys, chrom, bin_size, rd_stat)
|
|
@@ -54317,6 +54353,28 @@ class HDF5Reader {
|
|
|
54317
54353
|
}
|
|
54318
54354
|
return [chr_wig_1, chr_wig_2]
|
|
54319
54355
|
}
|
|
54356
|
+
|
|
54357
|
+
async get_baf_signals_v2(h5_obj, h5_obj_keys, chrom, bin_size, signal_name){
|
|
54358
|
+
|
|
54359
|
+
/* return two list of dictionary*/
|
|
54360
|
+
let chr_wig_1 = [];
|
|
54361
|
+
let chr_wig_2 = [];
|
|
54362
|
+
if (h5_obj_keys.includes(signal_name)){
|
|
54363
|
+
let chrom_dataset = await h5_obj.get(signal_name);
|
|
54364
|
+
let chrom_data = await chrom_dataset.to_array(); //create_nested_array(value, shape)
|
|
54365
|
+
chrom_data.forEach((lh, bin_idx) => {
|
|
54366
|
+
if (!isNaN(lh)){
|
|
54367
|
+
chr_wig_1.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: -2 * ( 0.5 - lh )});
|
|
54368
|
+
if(lh != 0.5){
|
|
54369
|
+
chr_wig_2.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: -2 * ( 0.5 + lh )});
|
|
54370
|
+
}
|
|
54371
|
+
}
|
|
54372
|
+
});
|
|
54373
|
+
}
|
|
54374
|
+
console.log(chrom, chr_wig_1, chr_wig_2);
|
|
54375
|
+
return [chr_wig_1, chr_wig_2]
|
|
54376
|
+
|
|
54377
|
+
}
|
|
54320
54378
|
}
|
|
54321
54379
|
|
|
54322
54380
|
class ParseSignals{
|
|
@@ -54357,6 +54415,53 @@ class ParseSignals{
|
|
|
54357
54415
|
}
|
|
54358
54416
|
}
|
|
54359
54417
|
|
|
54418
|
+
class GetFit {
|
|
54419
|
+
constructor(allBins) {
|
|
54420
|
+
this.allBins = allBins;
|
|
54421
|
+
}
|
|
54422
|
+
getValues() {
|
|
54423
|
+
const bins = Object.values(this.allBins).reduce(
|
|
54424
|
+
(binResult, bin) => { return binResult.concat(bin.filter(a => a.binScore > 0).map(a => a.binScore)) }, []);
|
|
54425
|
+
return bins
|
|
54426
|
+
}
|
|
54427
|
+
getMean(data) {
|
|
54428
|
+
return (data.reduce(function (a, b) { return a + b; }) / data.length);
|
|
54429
|
+
}
|
|
54430
|
+
fit_data() {
|
|
54431
|
+
let rd_list = this.getValues();
|
|
54432
|
+
let distParmas = getDistParams(rd_list);
|
|
54433
|
+
return distParmas
|
|
54434
|
+
}
|
|
54435
|
+
|
|
54436
|
+
histogram(data, bins) {
|
|
54437
|
+
const step = bins[1] - bins[0];
|
|
54438
|
+
const hist_bins = [];
|
|
54439
|
+
|
|
54440
|
+
data.forEach((value, index) => {
|
|
54441
|
+
bins.forEach((bin_value, bin_index) => {
|
|
54442
|
+
if (!hist_bins[bin_value]) {
|
|
54443
|
+
hist_bins[bin_value] = { count: 0 };
|
|
54444
|
+
}
|
|
54445
|
+
if (bin_value <= value && value < bin_value + step) {
|
|
54446
|
+
hist_bins[bin_value].count++;
|
|
54447
|
+
return false;
|
|
54448
|
+
}
|
|
54449
|
+
});
|
|
54450
|
+
});
|
|
54451
|
+
const dist_p = [];
|
|
54452
|
+
hist_bins.forEach((bin, index) => { dist_p.push(bin.count); });
|
|
54453
|
+
return dist_p
|
|
54454
|
+
}
|
|
54455
|
+
|
|
54456
|
+
}
|
|
54457
|
+
|
|
54458
|
+
function range_function(start, stop, step) {
|
|
54459
|
+
const data_array = Array(Math.ceil((stop - start) / step))
|
|
54460
|
+
.fill(start)
|
|
54461
|
+
.map((x, y) => x + y * step);
|
|
54462
|
+
return data_array;
|
|
54463
|
+
}
|
|
54464
|
+
|
|
54360
54465
|
function filterOutliers(someArray) {
|
|
54361
54466
|
|
|
54362
54467
|
if (someArray.length < 4)
|
|
@@ -54389,6 +54494,21 @@ function getDistParams(bins) {
|
|
|
54389
54494
|
return [mean, std]
|
|
54390
54495
|
}
|
|
54391
54496
|
|
|
54497
|
+
function linspace(a, b, n) {
|
|
54498
|
+
if (typeof n === "undefined") n = Math.max(Math.round(b - a) + 1, 1);
|
|
54499
|
+
if (n < 2) {
|
|
54500
|
+
return n === 1 ? [a] : [];
|
|
54501
|
+
}
|
|
54502
|
+
var ret = Array(n);
|
|
54503
|
+
n--;
|
|
54504
|
+
for (let i = n; i >= 0; i--) {
|
|
54505
|
+
ret[i] = (i * b + (n - i) * a) / n;
|
|
54506
|
+
}
|
|
54507
|
+
return ret;
|
|
54508
|
+
}
|
|
54509
|
+
|
|
54510
|
+
var g_utils = { range_function, getDistParams, linspace, GetFit};
|
|
54511
|
+
|
|
54392
54512
|
/**
|
|
54393
54513
|
* Evaluates the cumulative distribution function (CDF) for a Student's t distribution with degrees of freedom `v` at a value `t`.
|
|
54394
54514
|
*
|
|
@@ -54533,48 +54653,507 @@ function lgamma(xg){
|
|
|
54533
54653
|
return Math.log(gamma(xg))
|
|
54534
54654
|
}
|
|
54535
54655
|
|
|
54536
|
-
|
|
54656
|
+
function t_test_1_sample$1(mean, m, s, n) {
|
|
54657
|
+
if (s == 0) s = 1;
|
|
54658
|
+
var t = ((mean - m) / s) * Math.sqrt(n);
|
|
54659
|
+
var p = 1.0 - TdistributionCDF(Math.abs(t), (n - 1));
|
|
54660
|
+
return p
|
|
54661
|
+
}
|
|
54537
54662
|
|
|
54538
|
-
|
|
54539
|
-
|
|
54540
|
-
|
|
54541
|
-
|
|
54542
|
-
|
|
54543
|
-
|
|
54544
|
-
|
|
54545
|
-
|
|
54663
|
+
function t_test_2_samples$1(m1, s1, n1, m2, s2, n2) {
|
|
54664
|
+
if (s1 == 0) s1 = 1;
|
|
54665
|
+
if (s2 == 0) s2 = 1;
|
|
54666
|
+
var t = (m1 - m2) / Math.sqrt(s1 ** 2 / n1 + s2 ** 2 / n2);
|
|
54667
|
+
var df = ((s1 ** 2 / n1 + s2 ** 2 / n2) ** 2 * (n1 - 1) * (n2 - 1)) /
|
|
54668
|
+
((s1 ** 4 * (n2 - 1)) / n1 ** 2 + (s2 ** 4 * (n1 - 1)) / n2 ** 2);
|
|
54669
|
+
|
|
54670
|
+
var p = 1.0 - TdistributionCDF(Math.abs(t), parseInt(df + 0.5));
|
|
54671
|
+
|
|
54672
|
+
return p
|
|
54673
|
+
}
|
|
54674
|
+
|
|
54675
|
+
var t_dist = {TdistributionCDF, gamma, t_test_1_sample: t_test_1_sample$1, t_test_2_samples: t_test_2_samples$1};
|
|
54676
|
+
|
|
54677
|
+
class CombinedCaller{
|
|
54678
|
+
constructor(wigFeatures, binSize) {
|
|
54679
|
+
this.wigFeatures = wigFeatures;
|
|
54680
|
+
this.binSize = binSize;
|
|
54681
|
+
// let fit_obj = this.get_fit()
|
|
54682
|
+
// this.globalMean = fit_obj.globalMean
|
|
54683
|
+
// this.globalStd = fit_obj.globalStd
|
|
54546
54684
|
}
|
|
54547
|
-
|
|
54548
|
-
|
|
54685
|
+
get_fit(){
|
|
54686
|
+
var fit_info = new g_utils.GetFit(this.wigFeatures);
|
|
54687
|
+
var [globalMean, globalStd] = fit_info.fit_data();
|
|
54688
|
+
|
|
54689
|
+
return {globalMean:globalMean, globalStd:globalStd}
|
|
54690
|
+
|
|
54549
54691
|
}
|
|
54550
|
-
|
|
54551
|
-
|
|
54552
|
-
let
|
|
54553
|
-
|
|
54692
|
+
async call_2d(omin=null, mcount=null, event_type="both", max_distance=0.1, baf_threshold=0, max_copy_number=10, min_cell_fraction=0.0){
|
|
54693
|
+
|
|
54694
|
+
let fit_obj = this.get_fit();
|
|
54695
|
+
this.globalMean = fit_obj.globalMean;
|
|
54696
|
+
this.globalStd = fit_obj.globalStd;
|
|
54697
|
+
|
|
54698
|
+
let overlap_min = omin==null ? 0.05 * this.binSize / 3e9: omin ;
|
|
54699
|
+
let min_count = mcount == null ? parseInt(this.binSize / 10000) : mcount ;
|
|
54700
|
+
|
|
54701
|
+
let gstat_rd0 = [];
|
|
54702
|
+
let gstat_rd_all = [];
|
|
54703
|
+
let gstat_rd = [];
|
|
54704
|
+
let gstat_error = [];
|
|
54705
|
+
let gstat_lh = [];
|
|
54706
|
+
let gstat_n = [];
|
|
54707
|
+
|
|
54708
|
+
for (const [chr, wig] of Object.entries(this.wigFeatures)) {
|
|
54709
|
+
let segments = [];
|
|
54710
|
+
let levels = [];
|
|
54711
|
+
let likelihoods = [];
|
|
54712
|
+
|
|
54713
|
+
wig.forEach((bin, bin_idx) => {
|
|
54714
|
+
if (bin.hets_count > 4 ){
|
|
54715
|
+
|
|
54716
|
+
if( bin.dp_count > min_count ){
|
|
54717
|
+
segments.push([bin_idx]);
|
|
54718
|
+
levels.push(bin.binScore);
|
|
54719
|
+
likelihoods.push(bin.likelihood_score);
|
|
54720
|
+
delete bin.likelihood_score;
|
|
54721
|
+
|
|
54722
|
+
}
|
|
54723
|
+
}
|
|
54724
|
+
});
|
|
54725
|
+
|
|
54726
|
+
let diff_level = [];
|
|
54727
|
+
for(let i=1; i<levels.length; i++){
|
|
54728
|
+
diff_level.push(Math.abs(levels[i] - levels[i-1]));
|
|
54729
|
+
}
|
|
54730
|
+
let min_flank = [0];
|
|
54731
|
+
for(let i=1; i<diff_level.length; i++){
|
|
54732
|
+
min_flank.push(Math.min(diff_level[i-1], diff_level[i]));
|
|
54733
|
+
}
|
|
54734
|
+
min_flank.push(0);
|
|
54735
|
+
|
|
54736
|
+
let error = levels.map((x, x_idx) => {return Math.sqrt(Math.sqrt(x) ** 2 + this.globalStd ** 2 + Math.pow(min_flank[x_idx]/2, 2));});
|
|
54737
|
+
|
|
54738
|
+
let overlaps = [];
|
|
54739
|
+
|
|
54740
|
+
for(let i=0; i< segments.length-1; i++){
|
|
54741
|
+
|
|
54742
|
+
let lh_overlap = 0;
|
|
54743
|
+
try{
|
|
54744
|
+
lh_overlap = likelihood_overlap(likelihoods[i], likelihoods[i+1]);
|
|
54745
|
+
}catch{
|
|
54746
|
+
console.log("Overlap failed: ", i, likelihoods[i], segments[i+1], likelihoods[i+1]);
|
|
54747
|
+
}
|
|
54748
|
+
|
|
54749
|
+
let rd_overlap = normal_overlap_approx(levels[i], error[i], levels[i+1], error[i+1]);
|
|
54750
|
+
overlaps.push(rd_overlap * lh_overlap);
|
|
54751
|
+
|
|
54752
|
+
}
|
|
54753
|
+
|
|
54754
|
+
while(overlaps.length >0) {
|
|
54755
|
+
overlaps = overlaps.filter(num => typeof num === "number");
|
|
54756
|
+
|
|
54757
|
+
let max_overlap = arrayMax(overlaps);
|
|
54758
|
+
if(isNaN(max_overlap)){
|
|
54759
|
+
console.log('NaN value', overlaps);
|
|
54760
|
+
}
|
|
54761
|
+
if(max_overlap < overlap_min){
|
|
54762
|
+
// console.log("maxoverlap ",max_overlap, "is smaller than overlap min")
|
|
54763
|
+
break
|
|
54764
|
+
}
|
|
54765
|
+
let i = overlaps.indexOf(max_overlap);
|
|
54766
|
+
|
|
54767
|
+
let merge_level = normal_merge(levels[i], error[i], levels[i + 1], error[i + 1]);
|
|
54768
|
+
|
|
54769
|
+
let nlh;
|
|
54770
|
+
let nlh_sum;
|
|
54771
|
+
try{
|
|
54772
|
+
nlh = likelihoods[i].map((l_value, l_idx) => { return l_value * likelihoods[i+1][l_idx]});
|
|
54773
|
+
|
|
54774
|
+
nlh_sum = nlh.reduce((a, c_value) => {return a + c_value});
|
|
54775
|
+
|
|
54776
|
+
}catch{
|
|
54777
|
+
console.log(likelihoods);
|
|
54778
|
+
console.log('max_overlap:', max_overlap, i, overlaps.length);
|
|
54779
|
+
console.log('likelihood: ', i ,likelihoods[i], likelihoods[i+1]);
|
|
54780
|
+
console.log('nlh: ', nlh_sum);
|
|
54781
|
+
}
|
|
54782
|
+
// nlh_sum = nlh.reduce((a, c_value) => {return a + c_value});
|
|
54783
|
+
|
|
54784
|
+
levels[i] = merge_level.nl;
|
|
54785
|
+
error[i] = merge_level.ne;
|
|
54786
|
+
|
|
54787
|
+
likelihoods[i] = nlh.map(function(item) { return item/nlh_sum } );
|
|
54788
|
+
|
|
54789
|
+
segments[i].push(...segments[i+1]);
|
|
54790
|
+
|
|
54791
|
+
levels.splice(i + 1, 1);
|
|
54792
|
+
error.splice(i + 1, 1);
|
|
54793
|
+
segments.splice(i + 1, 1);
|
|
54794
|
+
likelihoods.splice(i + 1, 1);
|
|
54795
|
+
overlaps.splice(i, 1);
|
|
54796
|
+
|
|
54797
|
+
if(i < overlaps.length){
|
|
54798
|
+
|
|
54799
|
+
let rd_overlap = normal_overlap_approx(levels[i], error[i], levels[i+1], error[i+1]);
|
|
54800
|
+
let new_overlap = rd_overlap * likelihood_overlap(likelihoods[i], likelihoods[i + 1]);
|
|
54801
|
+
|
|
54802
|
+
overlaps[i] = new_overlap;
|
|
54803
|
+
}
|
|
54804
|
+
if(i > 0){
|
|
54805
|
+
let new_overlap = normal_overlap_approx(levels[i - 1], error[i - 1], levels[i], error[i])
|
|
54806
|
+
* likelihood_overlap(likelihoods[i - 1], likelihoods[i]);
|
|
54807
|
+
overlaps[i - 1] = new_overlap;
|
|
54808
|
+
}
|
|
54809
|
+
|
|
54810
|
+
}
|
|
54811
|
+
let ons = -1;
|
|
54812
|
+
while(true){
|
|
54813
|
+
overlaps = [];
|
|
54814
|
+
for(let i=0; i< levels.length; i++){
|
|
54815
|
+
for(let j=i; j<levels.length; j++){
|
|
54816
|
+
if(segments[j][0] - segments[i].at(-1) < max_distance * (segments[i].length + segments[j].length)){
|
|
54817
|
+
overlaps.push(normal_overlap_approx(levels[i], error[i], levels[j], error[j]) * likelihood_overlap(likelihoods[i], likelihoods[j]));
|
|
54818
|
+
}
|
|
54819
|
+
}
|
|
54820
|
+
}
|
|
54821
|
+
|
|
54822
|
+
if(overlaps.length == 0){
|
|
54823
|
+
break
|
|
54824
|
+
}
|
|
54825
|
+
let max_overlap = arrayMax(overlaps);
|
|
54826
|
+
if(max_overlap < overlap_min){
|
|
54827
|
+
break
|
|
54828
|
+
}
|
|
54829
|
+
let i = 0;
|
|
54830
|
+
let j = 1;
|
|
54831
|
+
while (i < segments.length - 1){
|
|
54832
|
+
let overlap_value = normal_overlap_approx(levels[i], error[i], levels[j], error[j]) * likelihood_overlap(likelihoods[i], likelihoods[j]);
|
|
54833
|
+
|
|
54834
|
+
if((segments[j][0] - segments[i].at(-1)) < max_distance * (segments[i].length + segments[j].length) && overlap_value == max_overlap){
|
|
54835
|
+
let merge_level = normal_merge(levels[i], error[i], levels[i + 1], error[i + 1]);
|
|
54836
|
+
|
|
54837
|
+
levels[i] = merge_level.nl;
|
|
54838
|
+
error[i] = merge_level.ne;
|
|
54839
|
+
let nlh = likelihoods[i].map((l_value, l_idx) => { return l_value * likelihoods[i+1][l_idx]});
|
|
54840
|
+
let nlh_sum = nlh.reduce((a, c_value) => {return a + c_value});
|
|
54841
|
+
likelihoods[i] = nlh.map(function(item) { return item/nlh_sum } );
|
|
54842
|
+
|
|
54843
|
+
|
|
54844
|
+
segments[i].push(...segments[i+1]);
|
|
54845
|
+
segments[i] = segments[i].sort((a,b) => a-b);
|
|
54846
|
+
|
|
54847
|
+
levels.splice(j, 1);
|
|
54848
|
+
error.splice(j, 1);
|
|
54849
|
+
segments.splice(j, 1);
|
|
54850
|
+
likelihoods.splice(j, 1);
|
|
54851
|
+
|
|
54852
|
+
if(j >= segments.length){
|
|
54853
|
+
i += 1;
|
|
54854
|
+
j = i + 1;
|
|
54855
|
+
}
|
|
54856
|
+
|
|
54857
|
+
}else {
|
|
54858
|
+
j += 1;
|
|
54859
|
+
if(j >= segments.length){
|
|
54860
|
+
i += 1;
|
|
54861
|
+
j = i + 1;
|
|
54862
|
+
}
|
|
54863
|
+
}
|
|
54864
|
+
}
|
|
54865
|
+
if(ons == segments.length){
|
|
54866
|
+
break
|
|
54867
|
+
}
|
|
54868
|
+
ons = segments.length;
|
|
54869
|
+
}
|
|
54870
|
+
// console.log('final segments', segments)
|
|
54871
|
+
|
|
54872
|
+
segments.forEach((seg_value, seg_idx) => {
|
|
54873
|
+
let baf_info = likelihood_baf_pval(likelihoods[seg_idx]);
|
|
54874
|
+
if(seg_value.length > 1){
|
|
54875
|
+
|
|
54876
|
+
seg_value.forEach((bin, bin_idx) =>{
|
|
54877
|
+
gstat_rd_all.push(wig[bin]);
|
|
54878
|
+
if(baf_info.mean <= baf_threshold){
|
|
54879
|
+
gstat_rd0.push(wig[bin]);
|
|
54880
|
+
}
|
|
54881
|
+
wig[bin].segment_score = levels[seg_idx];
|
|
54882
|
+
});
|
|
54883
|
+
gstat_rd.push(levels[seg_idx]);
|
|
54884
|
+
gstat_error.push(error[seg_idx]);
|
|
54885
|
+
gstat_lh.push(likelihoods[seg_idx]);
|
|
54886
|
+
|
|
54887
|
+
}
|
|
54888
|
+
|
|
54889
|
+
});
|
|
54890
|
+
|
|
54891
|
+
continue
|
|
54892
|
+
}
|
|
54893
|
+
|
|
54894
|
+
// Third stage for call
|
|
54895
|
+
|
|
54896
|
+
// let data = gstat_rd0.lengthn == 0 ? gstat_rd_all: gstat_rd0 ;
|
|
54897
|
+
|
|
54898
|
+
let points = parseInt(1000 * (1 - min_cell_fraction));
|
|
54899
|
+
if(points == 0){
|
|
54900
|
+
points = 1;
|
|
54901
|
+
}
|
|
54902
|
+
let x = g_utils.linspace(min_cell_fraction, 1, points);
|
|
54903
|
+
let master_lh = {};
|
|
54904
|
+
let germline_lh = {};
|
|
54905
|
+
for(let cn=10; cn > -1; cn--){
|
|
54906
|
+
for(let h1=0; h1 < (cn/2+1); h1++){
|
|
54907
|
+
let h2 = cn - h1;
|
|
54908
|
+
let mrd = x.map((v, idx) => {return 1-v +v*cn/2});
|
|
54909
|
+
let g_mrd = cn / 2;
|
|
54910
|
+
let g_mbaf;
|
|
54911
|
+
let mbaf;
|
|
54912
|
+
if(cn > 0){
|
|
54913
|
+
g_mbaf = 0.5 - (h1 / (h1 + h2));
|
|
54914
|
+
mbaf = x.map((v, idx) => {return 0.5 - (1 - v + v * h1) / (2 - 2 * v + (h1 + h2) * v)});
|
|
54915
|
+
|
|
54916
|
+
}else {
|
|
54917
|
+
g_mbaf = 0;
|
|
54918
|
+
mbaf = x.map((v, idx) => {return 0*v});
|
|
54919
|
+
}
|
|
54920
|
+
|
|
54921
|
+
for( let ei=0; ei < gstat_rd.length; ei++){
|
|
54922
|
+
|
|
54923
|
+
let g_lh = normal(g_mrd * this.globalMean, 1, gstat_rd[ei], gstat_error[ei]) * likelihood_of_baf(gstat_lh[ei], 0.5 + g_mbaf);
|
|
54924
|
+
if(ei in germline_lh){
|
|
54925
|
+
germline_lh[ei].push([cn, h1, h2, g_lh, 1.0]);
|
|
54926
|
+
}else {
|
|
54927
|
+
germline_lh[ei] = [cn, h1, h2, g_lh, 1.0];
|
|
54928
|
+
}
|
|
54929
|
+
let slh = 0;
|
|
54930
|
+
let max_lh = 0;
|
|
54931
|
+
let max_x = 0;
|
|
54932
|
+
mrd.forEach((mi, idx) => {
|
|
54933
|
+
if(!isNaN(mbaf[idx])){
|
|
54934
|
+
let tmpl = normal(mi * this.globalMean, 1, gstat_rd[ei], gstat_error[ei]) * likelihood_of_baf(gstat_lh[ei], 0.5 + mbaf[idx]);
|
|
54935
|
+
slh += tmpl;
|
|
54936
|
+
if(tmpl > max_lh){
|
|
54937
|
+
max_lh = tmpl;
|
|
54938
|
+
max_x = x[idx];
|
|
54939
|
+
}
|
|
54940
|
+
}
|
|
54941
|
+
});
|
|
54942
|
+
if(ei in master_lh){
|
|
54943
|
+
master_lh[ei].push([cn, h1, h2, slh / x.length, max_x]);
|
|
54944
|
+
}else {
|
|
54945
|
+
master_lh[ei] = [cn, h1, h2, slh / x.length, max_x];
|
|
54946
|
+
}
|
|
54947
|
+
}
|
|
54948
|
+
|
|
54949
|
+
for( let ei=0; ei < gstat_rd.length; ei++){
|
|
54950
|
+
if(event_type == "germline"){
|
|
54951
|
+
master_lh[ei].sort((a, b) => a[3] - b[3]);
|
|
54952
|
+
}
|
|
54953
|
+
else {
|
|
54954
|
+
master_lh[ei].sort((a, b) => a[3] - b[3]);
|
|
54955
|
+
if(event_type == "both"){
|
|
54956
|
+
|
|
54957
|
+
germline_lh[ei].sort((a, b) => a[3] - b[3]);
|
|
54958
|
+
if(germline_lh[ei][0][3] > master_lh[ei][0][3]){
|
|
54959
|
+
//let tmp_list = list(filter( lambda x: x[0] != germline_lh[ei][0][0] and x[1] != germline_lh[ei][0][1], master_lh[ei]))
|
|
54960
|
+
let tmp_list = master_lh[ei].filter((x) => (x[0] != germline_lh[ei][0][0]) && (x[1] <= germline_lh[ei][0][1]));
|
|
54961
|
+
// console.log('tmp_list', tmp_list)
|
|
54962
|
+
// master_lh[ei] = [germline_lh[ei][0]] + tmp_list
|
|
54963
|
+
master_lh[ei] = [germline_lh[ei][0]].push(...tmp_list);
|
|
54964
|
+
}
|
|
54965
|
+
}
|
|
54966
|
+
}
|
|
54967
|
+
}
|
|
54968
|
+
for( let ei=0; ei < gstat_rd.length; ei++){
|
|
54969
|
+
if(master_lh[ei][0][0] > 2);
|
|
54970
|
+
if(master_lh[ei][0][0] < 2);
|
|
54971
|
+
gstat_rd[ei] / this.globalMean;
|
|
54972
|
+
t_dist.t_test_1_sample(this.globalMean, gstat_rd[ei], gstat_error[ei], gstat_n[ei]);
|
|
54973
|
+
// console.log(etype)
|
|
54974
|
+
|
|
54975
|
+
}
|
|
54976
|
+
|
|
54977
|
+
|
|
54978
|
+
// break
|
|
54979
|
+
}
|
|
54980
|
+
|
|
54981
|
+
}
|
|
54982
|
+
|
|
54983
|
+
var rawbinScore = this.formatDataStructure(this.wigFeatures, 'binScore', this.globalMean);
|
|
54984
|
+
var callScore = this.formatDataStructure(this.wigFeatures, 'segment_score', this.globalMean);
|
|
54985
|
+
|
|
54986
|
+
return {binScore: rawbinScore, segment_score: callScore}
|
|
54987
|
+
|
|
54554
54988
|
}
|
|
54555
54989
|
|
|
54556
|
-
|
|
54557
|
-
const
|
|
54558
|
-
const
|
|
54990
|
+
formatDataStructure(wigFeatures, feature_column, scaling_factor = 1) {
|
|
54991
|
+
const results = [];
|
|
54992
|
+
for (const [chr, wig] of Object.entries(wigFeatures)) {
|
|
54559
54993
|
|
|
54560
|
-
|
|
54561
|
-
|
|
54562
|
-
if (
|
|
54563
|
-
|
|
54994
|
+
wig.forEach(sample => {
|
|
54995
|
+
var new_sample = { ...sample };
|
|
54996
|
+
if (scaling_factor != 1) {
|
|
54997
|
+
new_sample.value = sample[feature_column] / scaling_factor * 2;
|
|
54564
54998
|
}
|
|
54565
|
-
|
|
54566
|
-
|
|
54567
|
-
|
|
54999
|
+
results.push(new_sample);
|
|
55000
|
+
});
|
|
55001
|
+
}
|
|
55002
|
+
|
|
55003
|
+
return results
|
|
55004
|
+
}
|
|
55005
|
+
|
|
55006
|
+
formatDataStructure_BAF(feature_column, scaling_factor = 2) {
|
|
55007
|
+
const baf1 = [];
|
|
55008
|
+
const baf2 = [];
|
|
55009
|
+
for (const [chr, wig] of Object.entries(this.wigFeatures)) {
|
|
55010
|
+
|
|
55011
|
+
wig.forEach(sample => {
|
|
55012
|
+
|
|
55013
|
+
var baf1_value = { ...sample };
|
|
55014
|
+
var baf2_value = { ...sample };
|
|
55015
|
+
|
|
55016
|
+
let value = sample[feature_column];
|
|
55017
|
+
if (value != 0.5){
|
|
55018
|
+
baf2_value.value = -2 * (1 - value);
|
|
55019
|
+
baf2.push(baf2_value);
|
|
54568
55020
|
}
|
|
55021
|
+
baf1_value.value = -2 * value;
|
|
55022
|
+
baf1.push(baf1_value);
|
|
55023
|
+
|
|
54569
55024
|
});
|
|
54570
|
-
}
|
|
54571
|
-
|
|
54572
|
-
|
|
54573
|
-
return
|
|
55025
|
+
}
|
|
55026
|
+
|
|
55027
|
+
|
|
55028
|
+
return [baf1, baf2]
|
|
54574
55029
|
}
|
|
55030
|
+
}
|
|
54575
55031
|
|
|
55032
|
+
function arrayMax(arr) {
|
|
55033
|
+
return arr.reduce(function (p, v) {
|
|
55034
|
+
return ( p > v ? p : v );
|
|
55035
|
+
});
|
|
55036
|
+
}
|
|
55037
|
+
|
|
55038
|
+
/**
|
|
55039
|
+
* Normal distribution.
|
|
55040
|
+
*
|
|
55041
|
+
* @param {float} x - Variable.
|
|
55042
|
+
* @param {float} a - area
|
|
55043
|
+
* @param {float} x0 - Mean value
|
|
55044
|
+
* @param {float} sigma - Sigma
|
|
55045
|
+
* @returns {float} - Value of distribution in x.
|
|
55046
|
+
*/
|
|
55047
|
+
function normal(x, a, x0, sigma){
|
|
55048
|
+
|
|
55049
|
+
return a * Math.exp(-1* (x - x0) ** 2 / (2 * sigma ** 2)) / Math.sqrt(2 * Math.PI) / sigma
|
|
55050
|
+
|
|
55051
|
+
}
|
|
55052
|
+
|
|
55053
|
+
/**
|
|
55054
|
+
* Calculates two normal distributions overlap area.
|
|
55055
|
+
*
|
|
55056
|
+
* @param {float} m1 - Mean value of the first distribution
|
|
55057
|
+
* @param {float} s1 - Sigma of the first distribution
|
|
55058
|
+
* @param {float} m2 - Mean value for second distribution
|
|
55059
|
+
* @param {float} s2 - Sigma of the second distribution
|
|
55060
|
+
*
|
|
55061
|
+
* @returns {float} area - Area of overlap
|
|
55062
|
+
*/
|
|
55063
|
+
function normal_overlap_approx(m1, s1, m2, s2){
|
|
55064
|
+
|
|
55065
|
+
return Math.exp(-1* (m1-m2)**2/ (s1**2+s2**2))
|
|
55066
|
+
}
|
|
55067
|
+
|
|
55068
|
+
|
|
55069
|
+
/**
|
|
55070
|
+
* Returns overlap area of two likelihood functions.
|
|
55071
|
+
*
|
|
55072
|
+
* @param {*} lk1 - First likelihood function.
|
|
55073
|
+
* @param {*} lk2 - Second likelihood function.
|
|
55074
|
+
*
|
|
55075
|
+
* @returns {float} - Overlap area.
|
|
55076
|
+
*/
|
|
55077
|
+
function likelihood_overlap(likelihood_1, likelihood_2){
|
|
55078
|
+
let sum;
|
|
55079
|
+
try{
|
|
55080
|
+
sum = likelihood_1.reduce((accumulator, currentValue, currentIndex) => {return accumulator + Math.min(currentValue, likelihood_2[currentIndex])});
|
|
55081
|
+
}catch{
|
|
55082
|
+
console.log("Failed to find likelihood overlap: ", likelihood_1, likelihood_2);
|
|
55083
|
+
return 0
|
|
55084
|
+
}
|
|
55085
|
+
|
|
55086
|
+
return sum
|
|
54576
55087
|
}
|
|
54577
55088
|
|
|
55089
|
+
/**
|
|
55090
|
+
* Calculates normal distribution that is product of two given normal distributions.
|
|
55091
|
+
*
|
|
55092
|
+
* @param {float} m1 - Mean value of the first distribution
|
|
55093
|
+
* @param {float} s1 - Sigma of the first distribution
|
|
55094
|
+
* @param {float} m2 - Mean value for second distribution
|
|
55095
|
+
* @param {float} s2 - Sigma of the second distribution
|
|
55096
|
+
* @returns {Object} An object representing the first distribution
|
|
55097
|
+
* @property {float} nl - Mean value of the first distribution
|
|
55098
|
+
* @property {float} ne - Sigma of the first distribution
|
|
55099
|
+
*/
|
|
55100
|
+
function normal_merge(m1, s1, m2, s2){
|
|
55101
|
+
|
|
55102
|
+
if((s1 == 0) && (s2 == 0)){
|
|
55103
|
+
return {nl: 0.5 * (m1 + m2), ne: 0}
|
|
55104
|
+
}
|
|
55105
|
+
else {
|
|
55106
|
+
return {nl: (m1 * s2 * s2 + m2 * s1 * s1) / (s1 * s1 + s2 * s2), ne: Math.sqrt(s1 * s1 * s2 * s2 / (s1 * s1 + s2 * s2))}
|
|
55107
|
+
}
|
|
55108
|
+
}
|
|
55109
|
+
|
|
55110
|
+
/**
|
|
55111
|
+
* Calculates likelihood for given baf
|
|
55112
|
+
* @param {*} likelihood
|
|
55113
|
+
* @param {*} baf
|
|
55114
|
+
* @returns {float} likelihood value
|
|
55115
|
+
*/
|
|
55116
|
+
function likelihood_of_baf(likelihood, baf){
|
|
55117
|
+
|
|
55118
|
+
let bin = parseInt(baf * (likelihood.length - 1));
|
|
55119
|
+
let fr = baf * (likelihood.length - 1) - bin;
|
|
55120
|
+
if(bin < likelihood.length - 1){
|
|
55121
|
+
return likelihood[bin] * (1 - fr) + likelihood[bin + 1] * fr
|
|
55122
|
+
}
|
|
55123
|
+
else {
|
|
55124
|
+
return likelihood[bin]
|
|
55125
|
+
}
|
|
55126
|
+
}
|
|
55127
|
+
|
|
55128
|
+
/**
|
|
55129
|
+
*
|
|
55130
|
+
* Calculates baf level and p-value for given likelihood function.
|
|
55131
|
+
*
|
|
55132
|
+
* @param {*} likelihood
|
|
55133
|
+
* @returns {Object} An object representing BAF
|
|
55134
|
+
* @property {float} mean BAF level (difference from 1/2)
|
|
55135
|
+
* @property {float} p p-value for event different than 1/2
|
|
55136
|
+
*/
|
|
55137
|
+
function likelihood_baf_pval(likelihood) {
|
|
55138
|
+
const res = likelihood.length;
|
|
55139
|
+
const max_lh = Math.max(...likelihood);
|
|
55140
|
+
let ix = likelihood.indexOf(max_lh);
|
|
55141
|
+
if (ix > Math.floor(res / 2)) {
|
|
55142
|
+
ix = res - 1 - ix;
|
|
55143
|
+
}
|
|
55144
|
+
const b = (res / 2 - ix) / (res + 1);
|
|
55145
|
+
|
|
55146
|
+
const ix1 = Math.floor((res / 2 + ix) / 2);
|
|
55147
|
+
const ix2 = res - 1 - ix1;
|
|
55148
|
+
let p = likelihood.slice(ix1, ix2 + 1).reduce((acc, val) => acc + val, 0) / likelihood.reduce((acc, val) => acc + val, 0);
|
|
55149
|
+
if (ix === Math.floor(res / 2)) {
|
|
55150
|
+
p = 1.0;
|
|
55151
|
+
}
|
|
55152
|
+
return {mean:b, p:p};
|
|
55153
|
+
}
|
|
55154
|
+
|
|
55155
|
+
var combined_caller = {CombinedCaller};
|
|
55156
|
+
|
|
54578
55157
|
function erf(x) {
|
|
54579
55158
|
var m = 1.0, s = 1.0, sum = x * 1.0;
|
|
54580
55159
|
for (var i = 1; i < 50; i++) {
|
|
@@ -55222,6 +55801,10 @@ class Partition {
|
|
|
55222
55801
|
}
|
|
55223
55802
|
}
|
|
55224
55803
|
|
|
55804
|
+
|
|
55805
|
+
|
|
55806
|
+
var read_depth_caller = { Partition };
|
|
55807
|
+
|
|
55225
55808
|
class CNVpytorVCF {
|
|
55226
55809
|
constructor(allVariants, binSize) {
|
|
55227
55810
|
this.allVariants = allVariants;
|
|
@@ -55349,13 +55932,11 @@ class CNVpytorVCF {
|
|
|
55349
55932
|
readDepthMeanshift(wigFeatures) {
|
|
55350
55933
|
|
|
55351
55934
|
// Get global mean and standrad deviation
|
|
55352
|
-
var fit_info = new GetFit(wigFeatures);
|
|
55935
|
+
var fit_info = new g_utils.GetFit(wigFeatures);
|
|
55353
55936
|
var [globamMean, globalStd] = fit_info.fit_data();
|
|
55354
|
-
// console.log('Fitter', globamMean, globalStd)
|
|
55355
|
-
|
|
55356
55937
|
|
|
55357
55938
|
// Apply partition method
|
|
55358
|
-
var partition = new Partition(wigFeatures, globamMean, globalStd);
|
|
55939
|
+
var partition = new read_depth_caller.Partition(wigFeatures, globamMean, globalStd);
|
|
55359
55940
|
var partition_array = partition.meanShiftCaller();
|
|
55360
55941
|
var caller_array = partition.cnv_calling();
|
|
55361
55942
|
|
|
@@ -55386,86 +55967,10 @@ class CNVpytorVCF {
|
|
|
55386
55967
|
results.push(new_sample);
|
|
55387
55968
|
});
|
|
55388
55969
|
}
|
|
55389
|
-
// console.log(feature_column, results)
|
|
55390
55970
|
|
|
55391
55971
|
return results
|
|
55392
55972
|
}
|
|
55393
55973
|
|
|
55394
|
-
// function for baf likelihood calculations
|
|
55395
|
-
async computeBAF() {
|
|
55396
|
-
const chromosomes = Object.keys(this.allVariants);
|
|
55397
|
-
const wigFeatures = {};
|
|
55398
|
-
const results = [];
|
|
55399
|
-
|
|
55400
|
-
for (let chr of chromosomes) {
|
|
55401
|
-
const variants = this.allVariants[chr];
|
|
55402
|
-
if (variants.length === 0) continue
|
|
55403
|
-
var featureBin;
|
|
55404
|
-
for (let snp of variants) {
|
|
55405
|
-
featureBin = Math.max(Math.floor(snp.start / this.binSize), 0);
|
|
55406
|
-
|
|
55407
|
-
if (!wigFeatures[chr]) {
|
|
55408
|
-
wigFeatures[chr] = [];
|
|
55409
|
-
}
|
|
55410
|
-
if (!wigFeatures[chr][featureBin]) {
|
|
55411
|
-
if (featureBin > 0) {
|
|
55412
|
-
// calculating the BAF likelihood for previous bin
|
|
55413
|
-
let previous_featureBin = featureBin - 1;
|
|
55414
|
-
if (wigFeatures[chr][previous_featureBin]) {
|
|
55415
|
-
|
|
55416
|
-
const updated_bin = this.get_max_min_score(wigFeatures[chr][previous_featureBin]);
|
|
55417
|
-
wigFeatures[chr][previous_featureBin] = updated_bin;
|
|
55418
|
-
results.push(wigFeatures[chr][previous_featureBin]);
|
|
55419
|
-
}
|
|
55420
|
-
}
|
|
55421
|
-
wigFeatures[chr][featureBin] = {
|
|
55422
|
-
chr,
|
|
55423
|
-
start: featureBin * this.binSize,
|
|
55424
|
-
end: (featureBin + 1) * this.binSize,
|
|
55425
|
-
value: 0,
|
|
55426
|
-
count: 0,
|
|
55427
|
-
likelihood_score: [],
|
|
55428
|
-
min_score: 0,
|
|
55429
|
-
};
|
|
55430
|
-
}
|
|
55431
|
-
const calls = snp.calls[9];
|
|
55432
|
-
let genotype = calls.genotype;
|
|
55433
|
-
let ad_score = calls.info["AD"].split(',');
|
|
55434
|
-
let ad_a = ad_score[0], ad_b = ad_score[1];
|
|
55435
|
-
|
|
55436
|
-
if ((genotype[0] == 0 && genotype[1] == 1) || (genotype[0] == 1 && genotype[1] == 0)) {
|
|
55437
|
-
//apply the beta function
|
|
55438
|
-
if (wigFeatures[chr][featureBin].likelihood_score.length == 0) {
|
|
55439
|
-
wigFeatures[chr][featureBin].likelihood_score = linspace(0, 1, 200).map((value, index) => {
|
|
55440
|
-
return beta(ad_a, ad_b, value);
|
|
55441
|
-
});
|
|
55442
|
-
} else {
|
|
55443
|
-
var sum = 0;
|
|
55444
|
-
|
|
55445
|
-
wigFeatures[chr][featureBin].likelihood_score = linspace(0, 1, 200).map((value, index) => {
|
|
55446
|
-
var likelihood_value = wigFeatures[chr][featureBin].likelihood_score[index] * beta(ad_a, ad_b, value);
|
|
55447
|
-
sum = sum + likelihood_value;
|
|
55448
|
-
return likelihood_value;
|
|
55449
|
-
});
|
|
55450
|
-
|
|
55451
|
-
wigFeatures[chr][featureBin].likelihood_score = linspace(0, 1, 200).map((value, index) => {
|
|
55452
|
-
return wigFeatures[chr][featureBin].likelihood_score[index] / sum;
|
|
55453
|
-
});
|
|
55454
|
-
}
|
|
55455
|
-
wigFeatures[chr][featureBin].count++;
|
|
55456
|
-
}
|
|
55457
|
-
}
|
|
55458
|
-
|
|
55459
|
-
// last feature bin
|
|
55460
|
-
const updated_bin = this.get_max_min_score(wigFeatures[chr][featureBin]);
|
|
55461
|
-
wigFeatures[chr][featureBin] = updated_bin;
|
|
55462
|
-
results.push(wigFeatures[chr][featureBin]);
|
|
55463
|
-
}
|
|
55464
|
-
|
|
55465
|
-
const baf2_result = this.format_BAF_likelihood(wigFeatures);
|
|
55466
|
-
return [results, baf2_result]
|
|
55467
|
-
|
|
55468
|
-
}
|
|
55469
55974
|
async computeBAF_v2() {
|
|
55470
55975
|
|
|
55471
55976
|
const chromosomes = Object.keys(this.allVariants);
|
|
@@ -55520,19 +56025,19 @@ class CNVpytorVCF {
|
|
|
55520
56025
|
if ((genotype[0] == 0 && genotype[1] == 1) || (genotype[0] == 1 && genotype[1] == 0)) {
|
|
55521
56026
|
//apply the beta function
|
|
55522
56027
|
if (wigFeatures[chr][featureBin].likelihood_score.length == 0) {
|
|
55523
|
-
wigFeatures[chr][featureBin].likelihood_score = linspace(0, 1, 100).map((value, index) => {
|
|
56028
|
+
wigFeatures[chr][featureBin].likelihood_score = g_utils.linspace(0, 1, 100).map((value, index) => {
|
|
55524
56029
|
return beta(ad_a, ad_b, value);
|
|
55525
56030
|
});
|
|
55526
56031
|
} else {
|
|
55527
56032
|
var sum = 0;
|
|
55528
56033
|
|
|
55529
|
-
wigFeatures[chr][featureBin].likelihood_score = linspace(0, 1, 100).map((value, index) => {
|
|
56034
|
+
wigFeatures[chr][featureBin].likelihood_score = g_utils.linspace(0, 1, 100).map((value, index) => {
|
|
55530
56035
|
var likelihood_value = wigFeatures[chr][featureBin].likelihood_score[index] * beta(ad_a, ad_b, value);
|
|
55531
56036
|
sum = sum + likelihood_value;
|
|
55532
56037
|
return likelihood_value;
|
|
55533
56038
|
});
|
|
55534
56039
|
|
|
55535
|
-
wigFeatures[chr][featureBin].likelihood_score = linspace(0, 1, 100).map((value, index) => {
|
|
56040
|
+
wigFeatures[chr][featureBin].likelihood_score = g_utils.linspace(0, 1, 100).map((value, index) => {
|
|
55536
56041
|
return wigFeatures[chr][featureBin].likelihood_score[index] / sum;
|
|
55537
56042
|
});
|
|
55538
56043
|
}
|
|
@@ -55578,7 +56083,6 @@ class CNVpytorVCF {
|
|
|
55578
56083
|
if (sample.likelihood_score.length > 0) {
|
|
55579
56084
|
const max = Math.max(...sample.likelihood_score);
|
|
55580
56085
|
const res = sample.likelihood_score.indexOf(max);
|
|
55581
|
-
sample.likelihood_score = [];
|
|
55582
56086
|
sample.value = Math.max(res / 100, 1 - res / 100);
|
|
55583
56087
|
sample.min_score = Math.min(res / 100, 1 - res / 100);
|
|
55584
56088
|
|
|
@@ -55594,7 +56098,7 @@ class CNVpytorVCF {
|
|
|
55594
56098
|
|
|
55595
56099
|
//console.log('getAllbins', bins["value"])
|
|
55596
56100
|
|
|
55597
|
-
const fitter = new GetFit(bins);
|
|
56101
|
+
const fitter = new g_utils.GetFit(bins);
|
|
55598
56102
|
|
|
55599
56103
|
fitter.fit_data();
|
|
55600
56104
|
// dconsole.log('rd list', distParams)
|
|
@@ -55602,7 +56106,7 @@ class CNVpytorVCF {
|
|
|
55602
56106
|
return bins
|
|
55603
56107
|
}
|
|
55604
56108
|
|
|
55605
|
-
async read_rd_baf(){
|
|
56109
|
+
async read_rd_baf(caller='ReadDepth'){
|
|
55606
56110
|
|
|
55607
56111
|
const chromosomes = Object.keys(this.allVariants);
|
|
55608
56112
|
var wigFeatures = {};
|
|
@@ -55648,13 +56152,22 @@ class CNVpytorVCF {
|
|
|
55648
56152
|
}
|
|
55649
56153
|
|
|
55650
56154
|
}
|
|
55651
|
-
|
|
56155
|
+
|
|
55652
56156
|
var avgbin = this.adjust_bin_size(wigFeatures);
|
|
56157
|
+
var finalFeatureSet;
|
|
56158
|
+
if(caller == 'ReadDepth'){
|
|
56159
|
+
finalFeatureSet = this.readDepthMeanshift(avgbin);
|
|
56160
|
+
var baf = this.formatDataStructure_BAF(avgbin, 'max_likelihood');
|
|
56161
|
+
}else if(caller=='2D'){
|
|
56162
|
+
|
|
56163
|
+
let caller_obj = new combined_caller.CombinedCaller(avgbin, this.binSize);
|
|
56164
|
+
let processed_bins = await caller_obj.call_2d();
|
|
56165
|
+
|
|
56166
|
+
finalFeatureSet = [processed_bins.binScore, [], processed_bins.segment_score];
|
|
56167
|
+
|
|
56168
|
+
var baf = caller_obj.formatDataStructure_BAF('max_likelihood');
|
|
56169
|
+
}
|
|
55653
56170
|
|
|
55654
|
-
let finalFeatureSet = this.readDepthMeanshift(avgbin);
|
|
55655
|
-
|
|
55656
|
-
//var rawbinScore = this.formatDataStructure(avgbin, 'binScore', globamMean)
|
|
55657
|
-
var baf = this.formatDataStructure_BAF(avgbin, 'max_likelihood');
|
|
55658
56171
|
|
|
55659
56172
|
return [finalFeatureSet, baf]
|
|
55660
56173
|
}
|
|
@@ -55717,19 +56230,19 @@ class CNVpytorVCF {
|
|
|
55717
56230
|
|
|
55718
56231
|
wigFeatures[chr][j].hets.forEach((hets, hets_idx) => {
|
|
55719
56232
|
if(avgbin[chr][k].likelihood_score.length == 0){
|
|
55720
|
-
avgbin[chr][k].likelihood_score = linspace(0, 1, 100).map((value, index) => {
|
|
56233
|
+
avgbin[chr][k].likelihood_score = g_utils.linspace(0, 1, 100).map((value, index) => {
|
|
55721
56234
|
return beta(hets.ref, hets.alt, value);
|
|
55722
56235
|
});
|
|
55723
56236
|
}
|
|
55724
56237
|
else {
|
|
55725
56238
|
var likelihood_sum = 0;
|
|
55726
|
-
avgbin[chr][k].likelihood_score = linspace(0, 1, 100).map((value, index) => {
|
|
56239
|
+
avgbin[chr][k].likelihood_score = g_utils.linspace(0, 1, 100).map((value, index) => {
|
|
55727
56240
|
var likelihood_value = avgbin[chr][k].likelihood_score[index] * beta(hets.ref, hets.alt, value);
|
|
55728
56241
|
likelihood_sum += likelihood_value;
|
|
55729
56242
|
return likelihood_value;
|
|
55730
56243
|
});
|
|
55731
56244
|
|
|
55732
|
-
avgbin[chr][k].likelihood_score = linspace(0, 1, 100).map((value, index) => {
|
|
56245
|
+
avgbin[chr][k].likelihood_score = g_utils.linspace(0, 1, 100).map((value, index) => {
|
|
55733
56246
|
return avgbin[chr][k].likelihood_score[index] / likelihood_sum;
|
|
55734
56247
|
});
|
|
55735
56248
|
|
|
@@ -55754,19 +56267,6 @@ function beta(a, b, p, phased = true) {
|
|
|
55754
56267
|
return p ** a * (1 - p) ** b + p ** b * (1 - p) ** a;
|
|
55755
56268
|
}
|
|
55756
56269
|
|
|
55757
|
-
function linspace(a, b, n) {
|
|
55758
|
-
if (typeof n === "undefined") n = Math.max(Math.round(b - a) + 1, 1);
|
|
55759
|
-
if (n < 2) {
|
|
55760
|
-
return n === 1 ? [a] : [];
|
|
55761
|
-
}
|
|
55762
|
-
var ret = Array(n);
|
|
55763
|
-
n--;
|
|
55764
|
-
for (let i = n; i >= 0; i--) {
|
|
55765
|
-
ret[i] = (i * b + (n - i) * a) / n;
|
|
55766
|
-
}
|
|
55767
|
-
return ret;
|
|
55768
|
-
}
|
|
55769
|
-
|
|
55770
56270
|
/*
|
|
55771
56271
|
* The MIT License (MIT)
|
|
55772
56272
|
*
|
|
@@ -55877,29 +56377,43 @@ class CNVPytorTrack extends TrackBase {
|
|
|
55877
56377
|
}, Object.create(null));
|
|
55878
56378
|
|
|
55879
56379
|
const cnvpytor_obj = new CNVpytorVCF(allVariants, this.bin_size);
|
|
55880
|
-
//const wigFeatures = await cnvpytor_obj.computeReadDepth()
|
|
55881
|
-
//const bafFeatures = await cnvpytor_obj.computeBAF_v2()
|
|
55882
|
-
const dataWigs = await cnvpytor_obj.read_rd_baf();
|
|
55883
|
-
const wigFeatures = dataWigs[0];
|
|
55884
|
-
const bafFeatures = dataWigs[1];
|
|
55885
56380
|
|
|
56381
|
+
let wigFeatures;
|
|
56382
|
+
let bafFeatures;
|
|
55886
56383
|
this.wigFeatures_obj = {};
|
|
55887
|
-
this.wigFeatures_obj[this.bin_size] = {
|
|
55888
|
-
|
|
55889
|
-
|
|
55890
|
-
|
|
55891
|
-
|
|
55892
|
-
|
|
55893
|
-
|
|
55894
|
-
|
|
55895
|
-
|
|
55896
|
-
|
|
56384
|
+
this.wigFeatures_obj[this.bin_size] = {};
|
|
56385
|
+
|
|
56386
|
+
let dataWigs;
|
|
56387
|
+
if(this.config.cnv_caller == '2D'){
|
|
56388
|
+
|
|
56389
|
+
dataWigs = await cnvpytor_obj.read_rd_baf('2D');
|
|
56390
|
+
|
|
56391
|
+
wigFeatures = dataWigs[0];
|
|
56392
|
+
bafFeatures = dataWigs[1];
|
|
56393
|
+
this.wigFeatures_obj[this.bin_size]['2D'] = wigFeatures[2];
|
|
56394
|
+
|
|
56395
|
+
this.available_callers = ['2D'];
|
|
56396
|
+
}else {
|
|
56397
|
+
dataWigs = await cnvpytor_obj.read_rd_baf();
|
|
56398
|
+
wigFeatures = dataWigs[0];
|
|
56399
|
+
bafFeatures = dataWigs[1];
|
|
56400
|
+
this.wigFeatures_obj[this.bin_size]['ReadDepth'] = wigFeatures[2];
|
|
56401
|
+
this.available_callers = ['ReadDepth'];
|
|
56402
|
+
}
|
|
56403
|
+
|
|
56404
|
+
this.wigFeatures_obj[this.bin_size]['RD_Raw'] = wigFeatures[0];
|
|
56405
|
+
this.wigFeatures_obj[this.bin_size]['RD_Raw_gc_coor'] = wigFeatures[1];
|
|
56406
|
+
this.wigFeatures_obj[this.bin_size]['BAF1'] = bafFeatures[0];
|
|
56407
|
+
this.wigFeatures_obj[this.bin_size]['BAF2'] = bafFeatures[1];
|
|
56408
|
+
|
|
56409
|
+
this.available_bins = [this.bin_size];
|
|
56410
|
+
|
|
55897
56411
|
this.set_available_callers();
|
|
55898
56412
|
|
|
55899
56413
|
} else {
|
|
55900
56414
|
this.cnvpytor_obj = new HDF5Reader(this.config.url, this.bin_size);
|
|
55901
56415
|
this.wigFeatures_obj = await this.cnvpytor_obj.get_rd_signal(this.bin_size);
|
|
55902
|
-
this.
|
|
56416
|
+
this.available_bins = this.cnvpytor_obj.available_bins;
|
|
55903
56417
|
this.available_callers = this.cnvpytor_obj.callers;
|
|
55904
56418
|
this.set_available_callers();
|
|
55905
56419
|
}
|
|
@@ -56012,7 +56526,7 @@ class CNVPytorTrack extends TrackBase {
|
|
|
56012
56526
|
|
|
56013
56527
|
items.push('<hr/>');
|
|
56014
56528
|
items.push("Bin Sizes");
|
|
56015
|
-
for (let rd_bin of this.
|
|
56529
|
+
for (let rd_bin of this.available_bins) {
|
|
56016
56530
|
const checkBox = createCheckbox(rd_bin, rd_bin === this.bin_size);
|
|
56017
56531
|
items.push({
|
|
56018
56532
|
object: $$1(checkBox),
|