igv 2.13.7 → 2.13.9
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 +431 -228
- package/dist/igv.esm.min.js +8 -8
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +443 -210
- package/dist/igv.min.js +5 -5
- package/dist/igv.min.js.map +1 -1
- package/package.json +1 -1
package/dist/igv.esm.js
CHANGED
|
@@ -15473,7 +15473,7 @@ function download(filename, data) {
|
|
|
15473
15473
|
|
|
15474
15474
|
const { Deflate, deflate, deflateRaw, gzip } = deflate_1$1;
|
|
15475
15475
|
|
|
15476
|
-
const { Inflate, inflate: inflate$3, inflateRaw, ungzip: ungzip$2 } = inflate_1$1;
|
|
15476
|
+
const { Inflate, inflate: inflate$3, inflateRaw: inflateRaw$2, ungzip: ungzip$2 } = inflate_1$1;
|
|
15477
15477
|
|
|
15478
15478
|
|
|
15479
15479
|
|
|
@@ -15483,7 +15483,7 @@ function download(filename, data) {
|
|
|
15483
15483
|
var gzip_1 = gzip;
|
|
15484
15484
|
var Inflate_1 = Inflate;
|
|
15485
15485
|
var inflate_1 = inflate$3;
|
|
15486
|
-
var inflateRaw_1 = inflateRaw;
|
|
15486
|
+
var inflateRaw_1 = inflateRaw$2;
|
|
15487
15487
|
var ungzip_1 = ungzip$2;
|
|
15488
15488
|
var constants_1 = constants$2;
|
|
15489
15489
|
|
|
@@ -15517,7 +15517,7 @@ function download(filename, data) {
|
|
|
15517
15517
|
|
|
15518
15518
|
pako.deflateRaw;
|
|
15519
15519
|
pako.deflate;
|
|
15520
|
-
pako.inflateRaw;
|
|
15520
|
+
const inflateRaw = pako.inflateRaw;
|
|
15521
15521
|
const inflate = pako.inflate;
|
|
15522
15522
|
pako.gzip;
|
|
15523
15523
|
|
|
@@ -15595,7 +15595,7 @@ function unbgzf(data, lim) {
|
|
|
15595
15595
|
}
|
|
15596
15596
|
}
|
|
15597
15597
|
|
|
15598
|
-
function bgzBlockSize(data) {
|
|
15598
|
+
function bgzBlockSize$1(data) {
|
|
15599
15599
|
const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
15600
15600
|
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
15601
15601
|
return bsize;
|
|
@@ -18596,11 +18596,7 @@ RandomColorGenerator.prototype.get = function (saturation, value) {
|
|
|
18596
18596
|
|
|
18597
18597
|
};
|
|
18598
18598
|
|
|
18599
|
-
|
|
18600
|
-
|
|
18601
|
-
function randomColor() {
|
|
18602
|
-
return randomColorGenerator.get()
|
|
18603
|
-
}
|
|
18599
|
+
new RandomColorGenerator();
|
|
18604
18600
|
|
|
18605
18601
|
function randomRGB$1(min, max) {
|
|
18606
18602
|
|
|
@@ -20792,7 +20788,7 @@ function buildOptions(config, options) {
|
|
|
20792
20788
|
const doAutoscale = function (features) {
|
|
20793
20789
|
var min, max;
|
|
20794
20790
|
|
|
20795
|
-
if (features.length > 0) {
|
|
20791
|
+
if (features && features.length > 0) {
|
|
20796
20792
|
min = Number.MAX_VALUE;
|
|
20797
20793
|
max = -Number.MAX_VALUE;
|
|
20798
20794
|
|
|
@@ -24215,7 +24211,7 @@ const Cytoband = function (start, end, name, typestain) {
|
|
|
24215
24211
|
}
|
|
24216
24212
|
};
|
|
24217
24213
|
|
|
24218
|
-
const _version = "2.13.
|
|
24214
|
+
const _version = "2.13.9";
|
|
24219
24215
|
function version() {
|
|
24220
24216
|
return _version
|
|
24221
24217
|
}
|
|
@@ -29233,12 +29229,88 @@ class VPointer {
|
|
|
29233
29229
|
(this.block === vp.block && this.offset > vp.offset)
|
|
29234
29230
|
}
|
|
29235
29231
|
|
|
29232
|
+
isEqualTo(vp) {
|
|
29233
|
+
return this.block === vp.block && this.offset === vp.offset
|
|
29234
|
+
}
|
|
29235
|
+
|
|
29236
29236
|
print() {
|
|
29237
29237
|
return "" + this.block + ":" + this.offset
|
|
29238
29238
|
}
|
|
29239
29239
|
}
|
|
29240
29240
|
|
|
29241
|
-
|
|
29241
|
+
function optimizeChunks(chunks, lowest) {
|
|
29242
|
+
|
|
29243
|
+
if (chunks.length === 0) return chunks
|
|
29244
|
+
|
|
29245
|
+
chunks.sort(function (c0, c1) {
|
|
29246
|
+
|
|
29247
|
+
const dif = c0.minv.block - c1.minv.block;
|
|
29248
|
+
if (dif !== 0) {
|
|
29249
|
+
return dif
|
|
29250
|
+
} else {
|
|
29251
|
+
return c0.minv.offset - c1.minv.offset
|
|
29252
|
+
}
|
|
29253
|
+
});
|
|
29254
|
+
|
|
29255
|
+
if(chunks.length <= 1) {
|
|
29256
|
+
return chunks
|
|
29257
|
+
}
|
|
29258
|
+
|
|
29259
|
+
// console.log("Before trimming " + chunks.length)
|
|
29260
|
+
// for (let c of chunks) {
|
|
29261
|
+
// console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
|
|
29262
|
+
// }
|
|
29263
|
+
|
|
29264
|
+
if (lowest) {
|
|
29265
|
+
chunks = chunks.filter(c => c.maxv.isGreaterThan(lowest));
|
|
29266
|
+
}
|
|
29267
|
+
|
|
29268
|
+
// console.log("Before merging " + chunks.length)
|
|
29269
|
+
// for (let c of chunks) {
|
|
29270
|
+
// console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
|
|
29271
|
+
// }
|
|
29272
|
+
|
|
29273
|
+
const mergedChunks = [];
|
|
29274
|
+
let lastChunk;
|
|
29275
|
+
for (let chunk of chunks) {
|
|
29276
|
+
|
|
29277
|
+
if (!lastChunk) {
|
|
29278
|
+
mergedChunks.push(chunk);
|
|
29279
|
+
lastChunk = chunk;
|
|
29280
|
+
} else {
|
|
29281
|
+
if (canMerge(lastChunk, chunk)) {
|
|
29282
|
+
if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
|
|
29283
|
+
lastChunk.maxv = chunk.maxv;
|
|
29284
|
+
}
|
|
29285
|
+
} else {
|
|
29286
|
+
mergedChunks.push(chunk);
|
|
29287
|
+
lastChunk = chunk;
|
|
29288
|
+
}
|
|
29289
|
+
}
|
|
29290
|
+
}
|
|
29291
|
+
|
|
29292
|
+
// console.log("After merging " + mergedChunks.length)
|
|
29293
|
+
// for (let c of mergedChunks) {
|
|
29294
|
+
// console.log(`${c.minv.block} ${c.minv.offset} - ${c.maxv.block} ${c.maxv.offset}`)
|
|
29295
|
+
// }
|
|
29296
|
+
|
|
29297
|
+
return mergedChunks
|
|
29298
|
+
}
|
|
29299
|
+
|
|
29300
|
+
|
|
29301
|
+
/**
|
|
29302
|
+
* Merge 2 blocks if the file position gap between them is < 16 kb, and the total size is < ~5 mb
|
|
29303
|
+
* @param chunk1
|
|
29304
|
+
* @param chunk2
|
|
29305
|
+
* @returns {boolean|boolean}
|
|
29306
|
+
*/
|
|
29307
|
+
function canMerge(chunk1, chunk2) {
|
|
29308
|
+
const gap = chunk2.minv.block - chunk1.maxv.block;
|
|
29309
|
+
const sizeEstimate = chunk1.maxv.block - chunk1.minv.block;
|
|
29310
|
+
return gap < 65000 && sizeEstimate < 5000000
|
|
29311
|
+
}
|
|
29312
|
+
|
|
29313
|
+
// Represents a CSI Bam or Tabix index
|
|
29242
29314
|
|
|
29243
29315
|
const CSI1_MAGIC$1 = 21582659; // CSI\1
|
|
29244
29316
|
const CSI2_MAGIC$1 = 38359875; // CSI\2
|
|
@@ -29365,7 +29437,7 @@ class CSIIndex {
|
|
|
29365
29437
|
* @param max genomic end position
|
|
29366
29438
|
* @param return an array of {minv: {filePointer, offset}, {maxv: {filePointer, offset}}
|
|
29367
29439
|
*/
|
|
29368
|
-
|
|
29440
|
+
chunksForRange(refId, min, max) {
|
|
29369
29441
|
|
|
29370
29442
|
const ba = this.indices[refId];
|
|
29371
29443
|
if (!ba) {
|
|
@@ -29391,7 +29463,7 @@ class CSIIndex {
|
|
|
29391
29463
|
|
|
29392
29464
|
const lowestOffset = ba.loffset[overlappingBins[0]];
|
|
29393
29465
|
|
|
29394
|
-
return optimizeChunks
|
|
29466
|
+
return optimizeChunks(chunks, lowestOffset)
|
|
29395
29467
|
}
|
|
29396
29468
|
|
|
29397
29469
|
}
|
|
@@ -29428,58 +29500,11 @@ class CSIIndex {
|
|
|
29428
29500
|
|
|
29429
29501
|
}
|
|
29430
29502
|
|
|
29431
|
-
|
|
29432
|
-
|
|
29433
|
-
const mergedChunks = [];
|
|
29434
|
-
let lastChunk = null;
|
|
29435
|
-
|
|
29436
|
-
if (chunks.length === 0) return chunks
|
|
29437
|
-
|
|
29438
|
-
chunks.sort(function (c0, c1) {
|
|
29439
|
-
const dif = c0.minv.block - c1.minv.block;
|
|
29440
|
-
if (dif !== 0) {
|
|
29441
|
-
return dif
|
|
29442
|
-
} else {
|
|
29443
|
-
return c0.minv.offset - c1.minv.offset
|
|
29444
|
-
}
|
|
29445
|
-
});
|
|
29446
|
-
|
|
29447
|
-
chunks.forEach(function (chunk) {
|
|
29448
|
-
|
|
29449
|
-
if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
|
|
29450
|
-
if (lastChunk === null) {
|
|
29451
|
-
mergedChunks.push(chunk);
|
|
29452
|
-
lastChunk = chunk;
|
|
29453
|
-
} else {
|
|
29454
|
-
if (canMerge$1(lastChunk, chunk)) {
|
|
29455
|
-
if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
|
|
29456
|
-
lastChunk.maxv = chunk.maxv;
|
|
29457
|
-
}
|
|
29458
|
-
} else {
|
|
29459
|
-
mergedChunks.push(chunk);
|
|
29460
|
-
lastChunk = chunk;
|
|
29461
|
-
}
|
|
29462
|
-
}
|
|
29463
|
-
}
|
|
29464
|
-
});
|
|
29465
|
-
|
|
29466
|
-
return mergedChunks
|
|
29467
|
-
}
|
|
29468
|
-
|
|
29469
|
-
function canMerge$1(chunk1, chunk2) {
|
|
29470
|
-
return (chunk2.minv.block - chunk1.maxv.block) < 65000 &&
|
|
29471
|
-
(chunk2.maxv.block - chunk1.minv.block) < 5000000
|
|
29472
|
-
// lastChunk.minv.block === lastChunk.maxv.block &&
|
|
29473
|
-
// lastChunk.maxv.block === chunk.minv.block &&
|
|
29474
|
-
// chunk.minv.block === chunk.maxv.block
|
|
29475
|
-
|
|
29476
|
-
}
|
|
29477
|
-
|
|
29478
|
-
// Represents a BAM index.
|
|
29503
|
+
// Represents a BAM or Tabix index.
|
|
29479
29504
|
|
|
29480
29505
|
const BAI_MAGIC$1 = 21578050;
|
|
29481
29506
|
const TABIX_MAGIC$1 = 21578324;
|
|
29482
|
-
|
|
29507
|
+
|
|
29483
29508
|
|
|
29484
29509
|
async function parseBamIndex(arrayBuffer, genome) {
|
|
29485
29510
|
const index = new BamIndex();
|
|
@@ -29601,14 +29626,14 @@ class BamIndex {
|
|
|
29601
29626
|
}
|
|
29602
29627
|
|
|
29603
29628
|
/**
|
|
29604
|
-
* Fetch
|
|
29629
|
+
* Fetch chunks for a particular genomic range. This method is public so it can be unit-tested.
|
|
29605
29630
|
*
|
|
29606
29631
|
* @param refId the sequence dictionary index of the chromosome
|
|
29607
29632
|
* @param min genomic start position
|
|
29608
29633
|
* @param max genomic end position
|
|
29609
|
-
* @param return an array of {minv: {
|
|
29634
|
+
* @param return an array of objects representing chunks (file spans) {minv: {block, offset}, {maxv: {block, offset}}
|
|
29610
29635
|
*/
|
|
29611
|
-
|
|
29636
|
+
chunksForRange(refId, min, max) {
|
|
29612
29637
|
|
|
29613
29638
|
const bam = this;
|
|
29614
29639
|
const ba = bam.indices[refId];
|
|
@@ -29617,8 +29642,13 @@ class BamIndex {
|
|
|
29617
29642
|
return []
|
|
29618
29643
|
} else {
|
|
29619
29644
|
const overlappingBins = reg2bins(min, max); // List of bin #s that overlap min, max
|
|
29620
|
-
const chunks = [];
|
|
29621
29645
|
|
|
29646
|
+
//console.log("bin ranges")
|
|
29647
|
+
//for(let b of overlappingBins) {
|
|
29648
|
+
// console.log(`${b[0]} - ${b[1]}`)
|
|
29649
|
+
//}
|
|
29650
|
+
|
|
29651
|
+
const chunks = [];
|
|
29622
29652
|
// Find chunks in overlapping bins. Leaf bins (< 4681) are not pruned
|
|
29623
29653
|
for (let binRange of overlappingBins) {
|
|
29624
29654
|
for (let bin = binRange[0]; bin <= binRange[1]; bin++) {
|
|
@@ -29627,7 +29657,7 @@ class BamIndex {
|
|
|
29627
29657
|
for (let c of binChunks) {
|
|
29628
29658
|
const cs = c[0];
|
|
29629
29659
|
const ce = c[1];
|
|
29630
|
-
chunks.push({minv: cs, maxv: ce
|
|
29660
|
+
chunks.push({minv: cs, maxv: ce});
|
|
29631
29661
|
}
|
|
29632
29662
|
}
|
|
29633
29663
|
}
|
|
@@ -29635,16 +29665,15 @@ class BamIndex {
|
|
|
29635
29665
|
|
|
29636
29666
|
// Use the linear index to find minimum file position of chunks that could contain alignments in the region
|
|
29637
29667
|
const nintv = ba.linearIndex.length;
|
|
29638
|
-
|
|
29639
|
-
|
|
29668
|
+
|
|
29669
|
+
let lowest;
|
|
29670
|
+
const minLin = Math.min(min >> 14, nintv - 1); // i.e. min / 16384
|
|
29640
29671
|
const maxLin = Math.min(max >> 14, nintv - 1);
|
|
29641
|
-
for (let i = minLin; i
|
|
29672
|
+
for (let i = minLin; i <= maxLin; i++) {
|
|
29642
29673
|
const vp = ba.linearIndex[i];
|
|
29643
29674
|
if (vp) {
|
|
29644
|
-
|
|
29645
|
-
|
|
29646
|
-
lowest = vp;
|
|
29647
|
-
}
|
|
29675
|
+
lowest = vp; // lowest file offset that contains alignments overlapping (min, max)
|
|
29676
|
+
break
|
|
29648
29677
|
}
|
|
29649
29678
|
}
|
|
29650
29679
|
|
|
@@ -29653,56 +29682,7 @@ class BamIndex {
|
|
|
29653
29682
|
}
|
|
29654
29683
|
}
|
|
29655
29684
|
|
|
29656
|
-
function optimizeChunks(chunks, lowest) {
|
|
29657
|
-
|
|
29658
|
-
const mergedChunks = [];
|
|
29659
|
-
let lastChunk = null;
|
|
29660
|
-
|
|
29661
|
-
if (chunks.length === 0) return chunks
|
|
29662
|
-
|
|
29663
|
-
chunks.sort(function (c0, c1) {
|
|
29664
|
-
const dif = c0.minv.block - c1.minv.block;
|
|
29665
|
-
if (dif !== 0) {
|
|
29666
|
-
return dif
|
|
29667
|
-
} else {
|
|
29668
|
-
return c0.minv.offset - c1.minv.offset
|
|
29669
|
-
}
|
|
29670
|
-
});
|
|
29671
|
-
|
|
29672
|
-
chunks.forEach(function (chunk) {
|
|
29673
|
-
|
|
29674
|
-
if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
|
|
29675
|
-
if (lastChunk === null) {
|
|
29676
|
-
mergedChunks.push(chunk);
|
|
29677
|
-
lastChunk = chunk;
|
|
29678
|
-
} else {
|
|
29679
|
-
if (canMerge(lastChunk, chunk)) {
|
|
29680
|
-
if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
|
|
29681
|
-
lastChunk.maxv = chunk.maxv;
|
|
29682
|
-
}
|
|
29683
|
-
} else {
|
|
29684
|
-
mergedChunks.push(chunk);
|
|
29685
|
-
lastChunk = chunk;
|
|
29686
|
-
}
|
|
29687
|
-
}
|
|
29688
|
-
}
|
|
29689
|
-
});
|
|
29690
|
-
|
|
29691
|
-
return mergedChunks
|
|
29692
|
-
}
|
|
29693
|
-
|
|
29694
29685
|
|
|
29695
|
-
/**
|
|
29696
|
-
* Merge 2 blocks if the gap between them is < 1kb and the total resulting size < 100mb
|
|
29697
|
-
* @param chunk1
|
|
29698
|
-
* @param chunk2
|
|
29699
|
-
* @returns {boolean|boolean}
|
|
29700
|
-
*/
|
|
29701
|
-
function canMerge(chunk1, chunk2) {
|
|
29702
|
-
const gap = chunk2.minv.block - chunk1.maxv.block;
|
|
29703
|
-
const total = chunk2.maxv.block - chunk1.minv.block;
|
|
29704
|
-
return gap < 30000 && total < 10 * MB
|
|
29705
|
-
}
|
|
29706
29686
|
|
|
29707
29687
|
/**
|
|
29708
29688
|
* Calculate the list of bins that overlap with region [beg, end]
|
|
@@ -29840,7 +29820,7 @@ class TribbleIndex {
|
|
|
29840
29820
|
* @param min genomic start position
|
|
29841
29821
|
* @param max genomic end position
|
|
29842
29822
|
*/
|
|
29843
|
-
|
|
29823
|
+
chunksForRange(queryChr, min, max) { //function (refId, min, max) {
|
|
29844
29824
|
const chrIdx = this.chrIndex[queryChr];
|
|
29845
29825
|
|
|
29846
29826
|
if (chrIdx) {
|
|
@@ -30007,7 +29987,12 @@ class ByteArrayDataWrapper {
|
|
|
30007
29987
|
|
|
30008
29988
|
}
|
|
30009
29989
|
|
|
30010
|
-
|
|
29990
|
+
/**
|
|
29991
|
+
* Class to iterate line-by-line over a BGZipped text file. This class is useful for iterating from the start of
|
|
29992
|
+
* the file. Not useful for indexed queries.
|
|
29993
|
+
*/
|
|
29994
|
+
|
|
29995
|
+
class BGZLineReader {
|
|
30011
29996
|
|
|
30012
29997
|
constructor(config) {
|
|
30013
29998
|
this.config = config;
|
|
@@ -30053,7 +30038,7 @@ class BGZipLineReader {
|
|
|
30053
30038
|
}
|
|
30054
30039
|
});
|
|
30055
30040
|
const abuffer = await igvxhr.loadArrayBuffer(this.config.url, bsizeOptions);
|
|
30056
|
-
const bufferSize = bgzBlockSize(abuffer);
|
|
30041
|
+
const bufferSize = bgzBlockSize$1(abuffer);
|
|
30057
30042
|
//console.log(`next block ${this.filePtr} ${bufferSize}`);
|
|
30058
30043
|
|
|
30059
30044
|
if (bufferSize === 0) {
|
|
@@ -30074,6 +30059,250 @@ class BGZipLineReader {
|
|
|
30074
30059
|
|
|
30075
30060
|
}
|
|
30076
30061
|
|
|
30062
|
+
function concatenateArrayBuffers(arrayBuffers) {
|
|
30063
|
+
|
|
30064
|
+
if (arrayBuffers.length === 1) {
|
|
30065
|
+
return arrayBuffers[0]
|
|
30066
|
+
}
|
|
30067
|
+
|
|
30068
|
+
let len = 0;
|
|
30069
|
+
for (const b of arrayBuffers) {
|
|
30070
|
+
len += b.byteLength;
|
|
30071
|
+
}
|
|
30072
|
+
const c = new Uint8Array(len);
|
|
30073
|
+
let offset = 0;
|
|
30074
|
+
for (const b of arrayBuffers) {
|
|
30075
|
+
c.set(new Uint8Array(b), offset);
|
|
30076
|
+
offset += b.byteLength;
|
|
30077
|
+
}
|
|
30078
|
+
return c.buffer
|
|
30079
|
+
}
|
|
30080
|
+
|
|
30081
|
+
/**
|
|
30082
|
+
* Return the block size for the data buffer.
|
|
30083
|
+
* @param data
|
|
30084
|
+
* @returns {number}
|
|
30085
|
+
*/
|
|
30086
|
+
const bgzBlockSize = (data) => {
|
|
30087
|
+
const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
30088
|
+
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
30089
|
+
return bsize
|
|
30090
|
+
};
|
|
30091
|
+
|
|
30092
|
+
class BGZBlockLoader {
|
|
30093
|
+
|
|
30094
|
+
constructor(config) {
|
|
30095
|
+
this.config = config;
|
|
30096
|
+
this.cacheBlocks = false != config.cacheBlocks; // Default to true
|
|
30097
|
+
this.cache = undefined;
|
|
30098
|
+
}
|
|
30099
|
+
|
|
30100
|
+
/**
|
|
30101
|
+
* Return inflated data from startBlock through endBlock as an UInt8Array
|
|
30102
|
+
*
|
|
30103
|
+
* @param startBlock
|
|
30104
|
+
* @param endBlock
|
|
30105
|
+
* @returns {Promise<Uint8Array>}
|
|
30106
|
+
*/
|
|
30107
|
+
async getData(startBlock, endBlock) {
|
|
30108
|
+
|
|
30109
|
+
const blocks = await this.getInflatedBlocks(startBlock, endBlock);
|
|
30110
|
+
if (blocks.length === 1) {
|
|
30111
|
+
return blocks[0]
|
|
30112
|
+
}
|
|
30113
|
+
|
|
30114
|
+
let len = 0;
|
|
30115
|
+
for (const b of blocks) {
|
|
30116
|
+
len += b.byteLength;
|
|
30117
|
+
}
|
|
30118
|
+
const c = new Uint8Array(len);
|
|
30119
|
+
let offset = 0;
|
|
30120
|
+
for (const b of blocks) {
|
|
30121
|
+
c.set(b, offset);
|
|
30122
|
+
offset += b.byteLength;
|
|
30123
|
+
}
|
|
30124
|
+
return c
|
|
30125
|
+
}
|
|
30126
|
+
|
|
30127
|
+
/**
|
|
30128
|
+
* Return the inflated data for the specified blocks as an array of Uint8Arrays. This method is public so
|
|
30129
|
+
* it can be unit tested. *
|
|
30130
|
+
* @param startBlock
|
|
30131
|
+
* @param endBlock
|
|
30132
|
+
* @returns {Promise<*[Uint8Array]>}
|
|
30133
|
+
*/
|
|
30134
|
+
async getInflatedBlocks(startBlock, endBlock) {
|
|
30135
|
+
|
|
30136
|
+
if (!this.cacheBlocks) {
|
|
30137
|
+
const buffer = await this.loadBLockData(startBlock, endBlock);
|
|
30138
|
+
return inflateBlocks(buffer)
|
|
30139
|
+
} else {
|
|
30140
|
+
|
|
30141
|
+
const c = this.cache;
|
|
30142
|
+
if (c && (c.startBlock <= startBlock && c.endBlock >= endBlock)) {
|
|
30143
|
+
//console.log("Complete overlap")
|
|
30144
|
+
const startOffset = startBlock - c.startBlock;
|
|
30145
|
+
const endOffset = endBlock - c.startBlock;
|
|
30146
|
+
return inflateBlocks(c.buffer, startOffset, endOffset)
|
|
30147
|
+
// Don't update cache, still valid
|
|
30148
|
+
} else {
|
|
30149
|
+
|
|
30150
|
+
let buffer;
|
|
30151
|
+
if (!c || (c.startBlock > endBlock || c.endBlock < startBlock)) {
|
|
30152
|
+
// no overlap with cache
|
|
30153
|
+
buffer = await this.loadBLockData(startBlock, endBlock);
|
|
30154
|
+
} else {
|
|
30155
|
+
|
|
30156
|
+
//console.log("Some overlap")
|
|
30157
|
+
const arrayBuffers = [];
|
|
30158
|
+
|
|
30159
|
+
// Load blocks preceding cache start, if any
|
|
30160
|
+
if (startBlock < c.startBlock) {
|
|
30161
|
+
// load first blocks
|
|
30162
|
+
const startBuffer = await this.loadBLockData(startBlock, c.startBlock, {skipEnd: true});
|
|
30163
|
+
arrayBuffers.push(startBuffer);
|
|
30164
|
+
}
|
|
30165
|
+
|
|
30166
|
+
// Slice cached buffer as needed
|
|
30167
|
+
let cachedBuffer;
|
|
30168
|
+
if (startBlock <= c.startBlock && endBlock >= c.endBlock) {
|
|
30169
|
+
cachedBuffer = c.buffer;
|
|
30170
|
+
} else {
|
|
30171
|
+
const start = Math.max(0, startBlock - c.startBlock);
|
|
30172
|
+
let end;
|
|
30173
|
+
if (endBlock >= c.endBlock) {
|
|
30174
|
+
end = c.buffer.byteLength;
|
|
30175
|
+
} else {
|
|
30176
|
+
// We need to find the byte position of the end of "endBlock"
|
|
30177
|
+
const boundaries = findBlockBoundaries(c.buffer);
|
|
30178
|
+
for (let i = 0; i < boundaries.length - 1; i++) {
|
|
30179
|
+
if (c.startBlock + boundaries[i] === endBlock) {
|
|
30180
|
+
end = boundaries[i + 1];
|
|
30181
|
+
break
|
|
30182
|
+
}
|
|
30183
|
+
}
|
|
30184
|
+
// Do something if end not found
|
|
30185
|
+
}
|
|
30186
|
+
cachedBuffer = c.buffer.slice(start, end);
|
|
30187
|
+
}
|
|
30188
|
+
arrayBuffers.push(cachedBuffer);
|
|
30189
|
+
|
|
30190
|
+
// Load end blocks, if any
|
|
30191
|
+
if (endBlock > c.endBlock) {
|
|
30192
|
+
const endBuffer = await this.loadBLockData(c.endBlock, endBlock, {skipStart: true});
|
|
30193
|
+
arrayBuffers.push(endBuffer);
|
|
30194
|
+
}
|
|
30195
|
+
|
|
30196
|
+
buffer = concatenateArrayBuffers(arrayBuffers);
|
|
30197
|
+
}
|
|
30198
|
+
|
|
30199
|
+
this.cache = {startBlock, endBlock, buffer};
|
|
30200
|
+
return inflateBlocks(buffer)
|
|
30201
|
+
}
|
|
30202
|
+
}
|
|
30203
|
+
}
|
|
30204
|
+
|
|
30205
|
+
async loadBLockData(startBlock, endBlock, options) {
|
|
30206
|
+
|
|
30207
|
+
const config = this.config;
|
|
30208
|
+
const skipStart = options && options.skipStart;
|
|
30209
|
+
const skipEnd = options && options.skipEnd;
|
|
30210
|
+
|
|
30211
|
+
// Get size of last block if not skipped
|
|
30212
|
+
let lastBlockSize = 0;
|
|
30213
|
+
if (!skipEnd) {
|
|
30214
|
+
const bsizeOptions = buildOptions(config, {range: {start: endBlock, size: 26}});
|
|
30215
|
+
const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
|
|
30216
|
+
lastBlockSize = bgzBlockSize(abuffer);
|
|
30217
|
+
}
|
|
30218
|
+
|
|
30219
|
+
if (skipStart) {
|
|
30220
|
+
const bsizeOptions = buildOptions(config, {range: {start: startBlock, size: 26}});
|
|
30221
|
+
const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
|
|
30222
|
+
startBlock += bgzBlockSize(abuffer);
|
|
30223
|
+
}
|
|
30224
|
+
|
|
30225
|
+
// Load data for all blocks
|
|
30226
|
+
const loadOptions = buildOptions(config, {
|
|
30227
|
+
range: {
|
|
30228
|
+
start: startBlock,
|
|
30229
|
+
size: endBlock + lastBlockSize - startBlock
|
|
30230
|
+
}
|
|
30231
|
+
});
|
|
30232
|
+
|
|
30233
|
+
//console.log(`${this.config.name} Loaded ${startBlock} - ${endBlock + lastBlockSize} (${(endBlock + lastBlockSize - startBlock) / 1000} kb)`)
|
|
30234
|
+
|
|
30235
|
+
return igvxhr.loadArrayBuffer(config.url, loadOptions)
|
|
30236
|
+
}
|
|
30237
|
+
}
|
|
30238
|
+
|
|
30239
|
+
function findBlockBoundaries(arrayBuffer) {
|
|
30240
|
+
|
|
30241
|
+
const byteLengh = arrayBuffer.byteLength;
|
|
30242
|
+
let offset = 0;
|
|
30243
|
+
const blockBoundaries = [0];
|
|
30244
|
+
while (offset < byteLengh) {
|
|
30245
|
+
//console.log("Cache block " + offset)
|
|
30246
|
+
const ba = new Uint8Array(arrayBuffer, offset);
|
|
30247
|
+
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
30248
|
+
offset += bsize;
|
|
30249
|
+
if (offset < byteLengh) {
|
|
30250
|
+
blockBoundaries.push(offset);
|
|
30251
|
+
}
|
|
30252
|
+
}
|
|
30253
|
+
return blockBoundaries
|
|
30254
|
+
}
|
|
30255
|
+
|
|
30256
|
+
|
|
30257
|
+
/**
|
|
30258
|
+
* Inflate compressed blocks within the data buffer*
|
|
30259
|
+
* @param data
|
|
30260
|
+
* @param startBlock - optional file location for start block. Default == 0
|
|
30261
|
+
* @param endBlock - optional file location for last block to decompress.
|
|
30262
|
+
* @returns {*[]}
|
|
30263
|
+
*/
|
|
30264
|
+
function inflateBlocks(data, startBlock, endBlock) {
|
|
30265
|
+
|
|
30266
|
+
startBlock = startBlock || 0;
|
|
30267
|
+
|
|
30268
|
+
const oBlockList = [];
|
|
30269
|
+
let ptr = startBlock;
|
|
30270
|
+
|
|
30271
|
+
const lim = data.byteLength - 18;
|
|
30272
|
+
while (ptr < lim) {
|
|
30273
|
+
try {
|
|
30274
|
+
//console.log(113873 + ptr)
|
|
30275
|
+
const header = new Uint8Array(data, ptr, 18);
|
|
30276
|
+
const xlen = (header[11] << 8) | (header[10]);
|
|
30277
|
+
const bsize = ((header[17] << 8) | (header[16])); // Total block size, including header, minus 1
|
|
30278
|
+
const start = 12 + xlen + ptr; // Start of CDATA
|
|
30279
|
+
const bytesLeft = data.byteLength - start;
|
|
30280
|
+
const cDataSize = bsize - xlen - 18;
|
|
30281
|
+
|
|
30282
|
+
if (bytesLeft < cDataSize || cDataSize <= 0) {
|
|
30283
|
+
// This is unexpected. Throw error?
|
|
30284
|
+
break
|
|
30285
|
+
}
|
|
30286
|
+
|
|
30287
|
+
const cdata = new Uint8Array(data, start, cDataSize);
|
|
30288
|
+
const unc = inflateRaw(cdata);
|
|
30289
|
+
oBlockList.push(unc);
|
|
30290
|
+
|
|
30291
|
+
if (endBlock === ptr) {
|
|
30292
|
+
break
|
|
30293
|
+
} else {
|
|
30294
|
+
// Advance to next block
|
|
30295
|
+
ptr += bsize + 1;
|
|
30296
|
+
}
|
|
30297
|
+
|
|
30298
|
+
} catch (e) {
|
|
30299
|
+
console.error(e);
|
|
30300
|
+
break
|
|
30301
|
+
}
|
|
30302
|
+
}
|
|
30303
|
+
return oBlockList
|
|
30304
|
+
}
|
|
30305
|
+
|
|
30077
30306
|
/*
|
|
30078
30307
|
* The MIT License (MIT)
|
|
30079
30308
|
*
|
|
@@ -30131,6 +30360,7 @@ class FeatureFileReader {
|
|
|
30131
30360
|
if (this.config.format === "vcf" && !this.config.indexURL) {
|
|
30132
30361
|
console.warn("Warning: index file not specified. The entire vcf file will be loaded.");
|
|
30133
30362
|
}
|
|
30363
|
+
|
|
30134
30364
|
}
|
|
30135
30365
|
|
|
30136
30366
|
async defaultVisibilityWindow() {
|
|
@@ -30188,7 +30418,8 @@ class FeatureFileReader {
|
|
|
30188
30418
|
|
|
30189
30419
|
let dataWrapper;
|
|
30190
30420
|
if (index.tabix) {
|
|
30191
|
-
|
|
30421
|
+
this._blockLoader = new BGZBlockLoader(this.config);
|
|
30422
|
+
dataWrapper = new BGZLineReader(this.config);
|
|
30192
30423
|
} else {
|
|
30193
30424
|
// Tribble
|
|
30194
30425
|
const maxSize = Object.values(index.chrIndex)
|
|
@@ -30274,51 +30505,27 @@ class FeatureFileReader {
|
|
|
30274
30505
|
}
|
|
30275
30506
|
|
|
30276
30507
|
const genome = this.genome;
|
|
30277
|
-
const
|
|
30278
|
-
if (!
|
|
30508
|
+
const chunks = this.index.chunksForRange(refId, start, end);
|
|
30509
|
+
if (!chunks || chunks.length === 0) {
|
|
30279
30510
|
return []
|
|
30280
30511
|
} else {
|
|
30281
30512
|
const allFeatures = [];
|
|
30282
|
-
for (let
|
|
30283
|
-
|
|
30284
|
-
const startPos = block.minv.block;
|
|
30285
|
-
const startOffset = block.minv.offset;
|
|
30286
|
-
const endOffset = block.maxv.offset;
|
|
30287
|
-
let endPos;
|
|
30288
|
-
|
|
30289
|
-
if (tabix) {
|
|
30290
|
-
let lastBlockSize = 0;
|
|
30291
|
-
if (endOffset > 0) {
|
|
30292
|
-
const bsizeOptions = buildOptions(config, {
|
|
30293
|
-
range: {
|
|
30294
|
-
start: block.maxv.block,
|
|
30295
|
-
size: 26
|
|
30296
|
-
}
|
|
30297
|
-
});
|
|
30298
|
-
const abuffer = await igvxhr.loadArrayBuffer(config.url, bsizeOptions);
|
|
30299
|
-
lastBlockSize = bgzBlockSize(abuffer);
|
|
30300
|
-
}
|
|
30301
|
-
endPos = block.maxv.block + lastBlockSize;
|
|
30302
|
-
} else {
|
|
30303
|
-
endPos = block.maxv.block;
|
|
30304
|
-
}
|
|
30305
|
-
|
|
30306
|
-
const options = buildOptions(config, {
|
|
30307
|
-
range: {
|
|
30308
|
-
start: startPos,
|
|
30309
|
-
size: endPos - startPos + 1
|
|
30310
|
-
}
|
|
30311
|
-
});
|
|
30513
|
+
for (let chunk of chunks) {
|
|
30312
30514
|
|
|
30313
30515
|
let inflated;
|
|
30314
30516
|
if (tabix) {
|
|
30315
|
-
|
|
30316
|
-
inflated = unbgzf(data);
|
|
30517
|
+
inflated = await this._blockLoader.getData(chunk.minv.block, chunk.maxv.block);
|
|
30317
30518
|
} else {
|
|
30519
|
+
const options = buildOptions(config, {
|
|
30520
|
+
range: {
|
|
30521
|
+
start: chunk.minv.block,
|
|
30522
|
+
size: chunk.maxv.block - chunk.minv.block + 1
|
|
30523
|
+
}
|
|
30524
|
+
});
|
|
30318
30525
|
inflated = await igvxhr.loadString(config.url, options);
|
|
30319
30526
|
}
|
|
30320
30527
|
|
|
30321
|
-
const slicedData =
|
|
30528
|
+
const slicedData = chunk.minv.offset ? inflated.slice(chunk.minv.offset) : inflated;
|
|
30322
30529
|
const dataWrapper = getDataWrapper(slicedData);
|
|
30323
30530
|
let slicedFeatures = await parser.parseFeatures(dataWrapper);
|
|
30324
30531
|
|
|
@@ -36420,6 +36627,8 @@ class BamReader {
|
|
|
36420
36627
|
this.bamPath = config.url;
|
|
36421
36628
|
this.baiPath = config.indexURL;
|
|
36422
36629
|
BamUtils.setReaderDefaults(this, config);
|
|
36630
|
+
|
|
36631
|
+
this._blockLoader = new BGZBlockLoader(config);
|
|
36423
36632
|
}
|
|
36424
36633
|
|
|
36425
36634
|
async readAlignments(chr, bpStart, bpEnd) {
|
|
@@ -36435,32 +36644,16 @@ class BamReader {
|
|
|
36435
36644
|
} else {
|
|
36436
36645
|
|
|
36437
36646
|
const bamIndex = await this.getIndex();
|
|
36438
|
-
const chunks = bamIndex.
|
|
36647
|
+
const chunks = bamIndex.chunksForRange(chrId, bpStart, bpEnd);
|
|
36439
36648
|
|
|
36440
36649
|
if (!chunks || chunks.length === 0) {
|
|
36441
36650
|
return alignmentContainer
|
|
36442
36651
|
}
|
|
36443
|
-
for (let c of chunks) {
|
|
36444
|
-
|
|
36445
|
-
let lastBlockSize;
|
|
36446
|
-
if (c.maxv.offset === 0) {
|
|
36447
|
-
lastBlockSize = 0; // Don't need to read the last block.
|
|
36448
|
-
} else {
|
|
36449
|
-
const bsizeOptions = buildOptions(this.config, {range: {start: c.maxv.block, size: 26}});
|
|
36450
|
-
const abuffer = await igvxhr.loadArrayBuffer(this.bamPath, bsizeOptions);
|
|
36451
|
-
lastBlockSize = bgzBlockSize(abuffer);
|
|
36452
|
-
}
|
|
36453
|
-
const fetchMin = c.minv.block;
|
|
36454
|
-
const fetchMax = c.maxv.block + lastBlockSize;
|
|
36455
|
-
const range = {start: fetchMin, size: fetchMax - fetchMin + 1};
|
|
36456
|
-
|
|
36457
|
-
const compressed = await igvxhr.loadArrayBuffer(this.bamPath, buildOptions(this.config, {range: range}));
|
|
36458
36652
|
|
|
36459
|
-
|
|
36653
|
+
for (let c of chunks) {
|
|
36654
|
+
const ba = await this._blockLoader.getData(c.minv.block, c.maxv.block);
|
|
36460
36655
|
const done = BamUtils.decodeBamRecords(ba, c.minv.offset, alignmentContainer, this.indexToChr, chrId, bpStart, bpEnd, this.filter);
|
|
36461
|
-
|
|
36462
36656
|
if (done) {
|
|
36463
|
-
// console.log(`Loaded ${counter} chunks out of ${chunks.length}`);
|
|
36464
36657
|
break
|
|
36465
36658
|
}
|
|
36466
36659
|
}
|
|
@@ -36477,7 +36670,7 @@ class BamReader {
|
|
|
36477
36670
|
if (index.firstBlockPosition) {
|
|
36478
36671
|
const bsizeOptions = buildOptions(this.config, {range: {start: index.firstBlockPosition, size: 26}});
|
|
36479
36672
|
const abuffer = await igvxhr.loadArrayBuffer(this.bamPath, bsizeOptions);
|
|
36480
|
-
const bsize = bgzBlockSize(abuffer);
|
|
36673
|
+
const bsize = bgzBlockSize$1(abuffer);
|
|
36481
36674
|
len = index.firstBlockPosition + bsize; // Insure we get the complete compressed block containing the header
|
|
36482
36675
|
} else {
|
|
36483
36676
|
len = 64000;
|
|
@@ -40152,7 +40345,9 @@ class BAMTrack extends TrackBase {
|
|
|
40152
40345
|
hoverText(clickState) {
|
|
40153
40346
|
if (true === this.showCoverage && clickState.y >= this.coverageTrack.top && clickState.y < this.coverageTrack.height) {
|
|
40154
40347
|
const clickedObject = this.coverageTrack.getClickedObject(clickState);
|
|
40155
|
-
|
|
40348
|
+
if(clickedObject) {
|
|
40349
|
+
return clickedObject.hoverText()
|
|
40350
|
+
}
|
|
40156
40351
|
}
|
|
40157
40352
|
|
|
40158
40353
|
}
|
|
@@ -42771,7 +42966,14 @@ class TrackView {
|
|
|
42771
42966
|
const max = visibleViewport.featureCache.features.getMax(start, end);
|
|
42772
42967
|
allFeatures = [{value: max}];
|
|
42773
42968
|
} else {
|
|
42774
|
-
|
|
42969
|
+
const viewFeatures = FeatureUtils.findOverlapping(visibleViewport.featureCache.features, start, end);
|
|
42970
|
+
if(!allFeatures) {
|
|
42971
|
+
allFeatures = viewFeatures;
|
|
42972
|
+
} else {
|
|
42973
|
+
for(let f of viewFeatures) {
|
|
42974
|
+
allFeatures.push(f);
|
|
42975
|
+
}
|
|
42976
|
+
}
|
|
42775
42977
|
}
|
|
42776
42978
|
}
|
|
42777
42979
|
}
|
|
@@ -47105,21 +47307,16 @@ class EqtlTrack extends TrackBase {
|
|
|
47105
47307
|
* Colors used for coding omosomes
|
|
47106
47308
|
*/
|
|
47107
47309
|
|
|
47108
|
-
const
|
|
47310
|
+
const GWASColors = {
|
|
47109
47311
|
"X": "rgb(204, 153, 0)",
|
|
47110
47312
|
"Y": "rgb(153, 204, 0)",
|
|
47111
47313
|
"Un": "darkGray)",
|
|
47112
47314
|
"1": "rgb(80, 80, 255)",
|
|
47113
|
-
//"1": Color.red);
|
|
47114
|
-
"I": "rgb(139, 155, 187)",
|
|
47115
47315
|
"2": "rgb(206, 61, 50)",
|
|
47116
|
-
"II": "rgb(206, 61, 50)",
|
|
47117
47316
|
"2a": "rgb(210, 65, 55)",
|
|
47118
47317
|
"2b": "rgb(215, 70, 60)",
|
|
47119
47318
|
"3": "rgb(116, 155, 88)",
|
|
47120
|
-
"III": "rgb(116, 155, 88)",
|
|
47121
47319
|
"4": "rgb(240, 230, 133)",
|
|
47122
|
-
"IV": "rgb(240, 230, 133)",
|
|
47123
47320
|
"5": "rgb(70, 105, 131)",
|
|
47124
47321
|
"6": "rgb(186, 99, 56)",
|
|
47125
47322
|
"7": "rgb(93, 177, 221)",
|
|
@@ -47167,9 +47364,28 @@ const Colors = {
|
|
|
47167
47364
|
};
|
|
47168
47365
|
|
|
47169
47366
|
// aliasing
|
|
47170
|
-
for (let key of Object.keys(
|
|
47367
|
+
for (let key of Object.keys(GWASColors)) {
|
|
47171
47368
|
const altName = "chr" + key;
|
|
47172
|
-
|
|
47369
|
+
GWASColors[altName] = GWASColors[key];
|
|
47370
|
+
}
|
|
47371
|
+
|
|
47372
|
+
// romanizing
|
|
47373
|
+
for(let a = 1; a <= 48; a++) {
|
|
47374
|
+
if(a === 10) continue // Don't overide "X"
|
|
47375
|
+
const roman = romanize(a);
|
|
47376
|
+
GWASColors[roman] = GWASColors[a.toString()];
|
|
47377
|
+
}
|
|
47378
|
+
|
|
47379
|
+
|
|
47380
|
+
function romanize (num) {
|
|
47381
|
+
if (!+num) return false;
|
|
47382
|
+
var digits = String(+num).split('');
|
|
47383
|
+
var key = ['','C','CC','CCC','CD','D','DC','DCC','DCCC','CM',
|
|
47384
|
+
'','X','XX','XXX','XL','L','LX','LXX','LXXX','XC',
|
|
47385
|
+
'','I','II','III','IV','V','VI','VII','VIII','IX'];
|
|
47386
|
+
var roman = '', i = 3;
|
|
47387
|
+
while (i--) roman = (key[+digits.pop() + (i * 10)] || '') + roman;
|
|
47388
|
+
return Array(+digits.join('') + 1).join('M') + roman;
|
|
47173
47389
|
}
|
|
47174
47390
|
|
|
47175
47391
|
/*
|
|
@@ -47224,14 +47440,19 @@ class GWASTrack extends TrackBase {
|
|
|
47224
47440
|
this.dotSize = config.dotSize || 3;
|
|
47225
47441
|
this.popoverWindow = (config.popoverWindow === undefined ? DEFAULT_POPOVER_WINDOW : config.popoverWindow);
|
|
47226
47442
|
|
|
47227
|
-
|
|
47228
|
-
|
|
47229
|
-
|
|
47230
|
-
|
|
47231
|
-
|
|
47232
|
-
|
|
47233
|
-
|
|
47234
|
-
|
|
47443
|
+
// Color settings
|
|
47444
|
+
if (this.useChrColors) {
|
|
47445
|
+
this.colorScale = new ColorTable(config.colorTable || GWASColors);
|
|
47446
|
+
} else if (config.color) {
|
|
47447
|
+
this.colorScale = new ConstantColorScale(config.color);
|
|
47448
|
+
} else {
|
|
47449
|
+
this.colorScale =
|
|
47450
|
+
new BinnedColorScale(config.colorScale ||
|
|
47451
|
+
{
|
|
47452
|
+
thresholds: [5e-8, 5e-4, 0.5],
|
|
47453
|
+
colors: ["rgb(255,50,50)", "rgb(251,100,100)", "rgb(251,170,170)", "rgb(227,238,249)"],
|
|
47454
|
+
});
|
|
47455
|
+
}
|
|
47235
47456
|
|
|
47236
47457
|
this.featureSource = FeatureSource(config, this.browser.genome);
|
|
47237
47458
|
}
|
|
@@ -47240,7 +47461,7 @@ class GWASTrack extends TrackBase {
|
|
|
47240
47461
|
|
|
47241
47462
|
if (typeof this.featureSource.getHeader === "function") {
|
|
47242
47463
|
this.header = await this.featureSource.getHeader();
|
|
47243
|
-
if(this.disposed) return
|
|
47464
|
+
if (this.disposed) return // This track was removed during async load
|
|
47244
47465
|
}
|
|
47245
47466
|
|
|
47246
47467
|
// Set properties from track line
|
|
@@ -47298,20 +47519,20 @@ class GWASTrack extends TrackBase {
|
|
|
47298
47519
|
if (pos < bpStart) continue
|
|
47299
47520
|
if (pos > bpEnd) break
|
|
47300
47521
|
|
|
47301
|
-
const colorScale = this.getColorScale(variant._f ? variant._f.chr : variant.chr);
|
|
47302
|
-
|
|
47303
|
-
let color;
|
|
47304
47522
|
let val;
|
|
47305
47523
|
if (this.posteriorProbability) {
|
|
47306
47524
|
val = variant[this.valueProperty];
|
|
47307
|
-
color = colorScale.getColor(val);
|
|
47308
47525
|
} else {
|
|
47309
47526
|
const pvalue = variant[this.valueProperty];
|
|
47310
47527
|
if (!pvalue) continue
|
|
47311
47528
|
val = -Math.log10(pvalue);
|
|
47312
|
-
color = colorScale.getColor(val);
|
|
47313
47529
|
}
|
|
47314
47530
|
|
|
47531
|
+
const colorKey = this.useChrColors ?
|
|
47532
|
+
variant._f ? variant._f.chr : variant.chr :
|
|
47533
|
+
val;
|
|
47534
|
+
|
|
47535
|
+
const color = this.colorScale.getColor(colorKey);
|
|
47315
47536
|
const yScale = (this.dataRange.max - this.dataRange.min) / pixelHeight;
|
|
47316
47537
|
const px = Math.round((pos - bpStart) / bpPerPixel);
|
|
47317
47538
|
const py = Math.max(this.dotSize, pixelHeight - Math.round((val - this.dataRange.min) / yScale));
|
|
@@ -47326,21 +47547,6 @@ class GWASTrack extends TrackBase {
|
|
|
47326
47547
|
}
|
|
47327
47548
|
}
|
|
47328
47549
|
|
|
47329
|
-
getColorScale(chr) {
|
|
47330
|
-
|
|
47331
|
-
if (this.useChrColors) {
|
|
47332
|
-
let cs = this.colorScales[chr];
|
|
47333
|
-
if (!cs) {
|
|
47334
|
-
const color = Colors[chr] || randomColor();
|
|
47335
|
-
cs = new ConstantColorScale(color);
|
|
47336
|
-
this.colorScales[chr] = cs;
|
|
47337
|
-
}
|
|
47338
|
-
return cs
|
|
47339
|
-
} else {
|
|
47340
|
-
return this.colorScales("*")
|
|
47341
|
-
}
|
|
47342
|
-
}
|
|
47343
|
-
|
|
47344
47550
|
paintAxis(ctx, pixelWidth, pixelHeight) {
|
|
47345
47551
|
|
|
47346
47552
|
IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
|
|
@@ -47377,7 +47583,7 @@ class GWASTrack extends TrackBase {
|
|
|
47377
47583
|
|
|
47378
47584
|
popupData(clickState, features) {
|
|
47379
47585
|
|
|
47380
|
-
if(features === undefined) features =
|
|
47586
|
+
if (features === undefined) features = clickState.viewport.cachedFeatures;
|
|
47381
47587
|
|
|
47382
47588
|
let data = [];
|
|
47383
47589
|
const track = clickState.viewport.trackView.track;
|
|
@@ -47438,13 +47644,10 @@ class GWASTrack extends TrackBase {
|
|
|
47438
47644
|
} else {
|
|
47439
47645
|
// No features -- pick something reasonable for PPAs and p-values
|
|
47440
47646
|
if (this.posteriorProbability) {
|
|
47441
|
-
this.dataRange
|
|
47442
|
-
this.dataRange.max = this.config.max || 1;
|
|
47647
|
+
this.dataRange = {min: this.config.min || 0, max: this.config.max || 1};
|
|
47443
47648
|
} else {
|
|
47444
|
-
this.dataRange
|
|
47445
|
-
this.dataRange.min = this.config.min || 0;
|
|
47649
|
+
this.dataRange = {min: this.config.max || 25, max: this.config.min || 0};
|
|
47446
47650
|
}
|
|
47447
|
-
|
|
47448
47651
|
}
|
|
47449
47652
|
|
|
47450
47653
|
return this.dataRange
|