From bce1cd676fd0df263f149c1eb4a3323b77647404 Mon Sep 17 00:00:00 2001 From: Alexander Veit <53857412+alexander-veit@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:34:10 -0500 Subject: [PATCH] Bugfixes + version bump --- package-lock.json | 4 +- package.json | 2 +- src/ScannerResultTrack.js | 274 +++++++++++++++++++++++++++++--------- src/chrom-utils.js | 3 +- src/index.html | 43 ++---- 5 files changed, 227 insertions(+), 99 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca69f1b..4771df3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "smaht-higlass-misc", - "version": "0.1.0-beta.2", + "version": "0.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "smaht-higlass-misc", - "version": "0.1.0-beta.2", + "version": "0.2.0", "license": "MIT", "dependencies": { "d3-array": "^2.3.1", diff --git a/package.json b/package.json index d17b895..964bc67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "smaht-higlass-misc", - "version": "0.1.0-beta.2", + "version": "0.2.0", "description": "HiGlass tracks for one-off use cases", "keywords": [ "HiGlass", diff --git a/src/ScannerResultTrack.js b/src/ScannerResultTrack.js index a589e57..560ce9b 100644 --- a/src/ScannerResultTrack.js +++ b/src/ScannerResultTrack.js @@ -19,6 +19,13 @@ function ScannerResultTrack(HGC, ...args) { this.mouseClickData = null; this.data = []; + this.snpData = []; + + this.previousFromX = Number.MIN_SAFE_INTEGER; + this.previousToX = Number.MAX_SAFE_INTEGER; + this.currentFilteredListSnp = []; + this.currentFilteredList = []; + this.currentMaxValue = 0; // we scale the entire view up until a certain point // at which point we redraw everything to get rid of @@ -28,11 +35,14 @@ function ScannerResultTrack(HGC, ...args) { this.drawnAtScale = HGC.libraries.d3Scale.scaleLinear(); this.visibleSegments = []; - this.currentYScale = this.HGC.libraries.d3Scale.scaleLinear( + this.currentYScaleSegments = this.HGC.libraries.d3Scale.scaleLinear( + [0, 1], + [0, 1], + ); + this.currentYScalePoints = this.HGC.libraries.d3Scale.scaleLinear( [0, 1], [0, 1], ); - this.segmentHeight = 10; // graphics for highliting reads under the cursor this.mouseOverGraphics = new HGC.libraries.PIXI.Graphics(); @@ -49,7 +59,7 @@ function ScannerResultTrack(HGC, ...args) { this.chromSizes = {}; this.chomSizesLoaded = false; - this.hasRerenderBeenTriggered = false; + //this.hasRerenderBeenTriggered = false; if (options.chromSizesUrl) { this.chromSizes[options.chromSizesUrl] = @@ -66,10 +76,9 @@ function ScannerResultTrack(HGC, ...args) { this.loadingText.text = 'Loading...'; this.chomSizesLoaded = true; this.chromInfo = chromInfo; - console.log(this.chromInfo, chromInfo); - if (this.hasRerenderBeenTriggered) { - this.rerender(options); - } + //if (this.hasRerenderBeenTriggered) { + this.rerender(options); + //} }); } @@ -88,13 +97,58 @@ function ScannerResultTrack(HGC, ...args) { this.pMain.addChild(this.segmentGraphics); this.legendUtils = new LegendUtils(this.HGC, 70, 1); + + // setTimeout(() => { + // const d = [ + // ['chr1', 566870, 0.0], + // ['chr1', 729679, 1.0], + // ['chr1', 752566, 1.0], + // ['chr1', 752721, 1.0], + // ['chr1', 753541, 1.0], + // ['chr1', 754192, 1.0], + // ['chr1', 754334, 1.0], + // ['chr1', 754503, 1.0], + // ['chr1', 750000, 0.5], + // ['chr1', 1611995, 0.0], + // ['chr1', 1618592, 0.0], + // ['chr1', 1618675, 0.0], + // ['chr1', 1619848, 0.0], + // ['chr1', 1620860, 0.0], + // ['chr1', 1620885, 0.0], + // ['chr1', 1628197, 0.0], + // ['chr1', 1651631, 0.0], + // ['chr1', 1655928, 0.0], + // ['chr1', 1660978, 0.0], + // ['chr1', 1668168, 0.0], + // ['chr1', 1672142, 0.0], + // ['chr1', 1674111, 0.0], + // ['chr1', 1692321, 0.0], + // ['chr1', 1694251, 0.0], + // ['chr1', 1698092, 0.0], + // ['chr1', 1704654, 0.0], + // ['chr1', 1718435, 0.0], + // ]; + // this.setSnpData(d); + // }, 1000); + } + + setData(data) { + this.parseData(data); + this.rerender(this.options); + } + + setSnpData(data) { + this.parseSnpData(data); + this.rerender(this.options); } rerender(options) { - this.hasRerenderBeenTriggered = true; super.rerender(options); this.options = options; - this.parseData(); + if (this.options.data.length > 0) { + this.parseData(this.options.data); + } + this.resetCache(); this.updateExistingGraphics(); this.prevOptions = Object.assign({}, options); } @@ -125,16 +179,44 @@ function ScannerResultTrack(HGC, ...args) { this.legendUtils.drawHorizontalLines(this.bgGraphics, 0, trackWidth); } - parseData() { + resetCache(){ + this.previousFromX = Number.MIN_SAFE_INTEGER; + this.previousToX = Number.MAX_SAFE_INTEGER; + } + + parseSnpData(data) { + this.snpData = []; if (!this.chromInfo) { return; } this.loadingText.text = 'Parsing data...'; + data.forEach((d) => { + const chr = d[0]; + const pos = d[1]; + const snp_baf = d[2]; + + this.snpData.push({ + chr: chr, + pos: pos, + yvalue: snp_baf, + posAbs: chrToAbs(chr, pos, this.chromInfo), + importance: Math.random(), + }); + }); + this.snpData.sort((a, b) => a.importance - b.importance); + //console.log(this.snpData) + } + + parseData(data) { this.data = []; - console.log(this.chromInfo); - this.options.data.forEach((d) => { + if (!this.chromInfo) { + return; + } + this.loadingText.text = 'Parsing data...'; + + data.forEach((d) => { const chr = d[0]; const from = d[1]; const to = d[2]; @@ -144,7 +226,12 @@ function ScannerResultTrack(HGC, ...args) { const rdr = d[6]; const baf = d[7]; const cell = d[8]; - const yValue = rdr; + let yValue = rdr; + if (this.options.yValue === 'baf') { + yValue = baf; + } else if (this.options.yValue === 'total_cn') { + yValue = total_cn; + } this.data.push({ chr: chr, from: from, @@ -164,9 +251,6 @@ function ScannerResultTrack(HGC, ...args) { } updateExistingGraphics() { - if (!this.chomSizesLoaded) { - return; - } this.loadingText.text = 'Rendering...'; //this.segmentGraphics.drawRect(5, 10, 200, 10); @@ -178,44 +262,114 @@ function ScannerResultTrack(HGC, ...args) { const fromX = this._xScale.invert(0); const toX = this._xScale.invert(this.dimensions[0]); + const refreshStep = 0.05; + + if ( + Math.abs( + (this.previousFromX - fromX) / + (this.previousToX - this.previousFromX), + ) > refreshStep || + Math.abs( + (this.previousToX - toX) / (this.previousToX - this.previousFromX), + ) > refreshStep + ) { + // Recompute + this.currentFilteredList = this.data.filter( + (segment) => + segment.toAbs >= fromX - refreshStep && + segment.fromAbs <= toX + refreshStep, + ); - const filteredList = this.data.filter( - (segment) => segment.toAbs >= fromX && segment.fromAbs <= toX, - ); + this.currentFilteredListSnp = this.snpData + .filter( + (segment) => + segment.posAbs >= fromX - refreshStep && + segment.posAbs <= toX + refreshStep, + ) + .slice(0, 10000); + + let maxValue = 0.0; + this.currentFilteredList.forEach((segment) => { + if (this.options.show_total_cn) { + maxValue = Math.max(maxValue, segment.yvalue, segment.total_cn); + } else { + maxValue = Math.max(maxValue, segment.yvalue); + } + }); + //maxValue = 1.1*maxValue; + if (this.currentFilteredList.length === 0) { + maxValue = 1.0; + } - let maxValue = 0.0; - filteredList.forEach((segment) => { - maxValue = Math.max(maxValue, segment.yvalue); - }); - //maxValue = 1.1*maxValue; - if (filteredList.length === 0) { - maxValue = 1.0; + let maxValueSnp = 0.0; + this.currentFilteredListSnp.forEach((segment) => { + maxValueSnp = Math.max(maxValueSnp, segment.yvalue); + }); + this.currentMaxValue = Math.max(maxValue, maxValueSnp); + this.previousFromX = fromX; + this.previousToX = toX; + //console.log(fromX, this.currentFilteredListSnp.length); } - this.createLegendGraphics(maxValue); - this.currentYScale = this.HGC.libraries.d3Scale.scaleLinear( - [0, maxValue], + this.createLegendGraphics(this.currentMaxValue); + + this.currentYScaleSegments = this.HGC.libraries.d3Scale.scaleLinear( + [0, this.currentMaxValue], [ - this.legendUtils.currentLegendLevels[4] - this.segmentHeight / 2, - this.legendUtils.currentLegendLevels[0] - this.segmentHeight / 2, + this.legendUtils.currentLegendLevels[4] - + this.options.segmentHeight / 2, + this.legendUtils.currentLegendLevels[0] - + this.options.segmentHeight / 2, ], ); - // this.segmentGraphics.removeChildren(); - // this.segmentGraphics.clear(); + this.currentYScalePoints = this.HGC.libraries.d3Scale.scaleLinear( + [0, this.currentMaxValue], + [ + this.legendUtils.currentLegendLevels[4] + 0, + this.legendUtils.currentLegendLevels[0] + 0, + ], + ); + + const segmentColorHex = this.HGC.utils.colorToHex( + this.options.segmentColor, + ); + const snpColorHex = this.HGC.utils.colorToHex(this.options.snpColor); + const blackColorHex = this.HGC.utils.colorToHex('#333333'); this.segmentGraphics.removeChildren(); this.segmentGraphics.clear(); - this.segmentGraphics.beginFill(this.HGC.utils.colorToHex('#ff0000')); - filteredList.forEach((segment) => { + + this.segmentGraphics.beginFill(snpColorHex, 0.4); + this.currentFilteredListSnp.forEach((segment) => { + const xPos = this._xScale(segment.posAbs); + + this.segmentGraphics.drawCircle( + xPos, + this.currentYScalePoints(segment.yvalue), + 3, + ); + }); + + this.currentFilteredList.forEach((segment) => { const xPos = this._xScale(segment.fromAbs); const width = this._xScale(segment.toAbs) - xPos; // this.segmentGraphics.drawRect(xPos, 10, width, 10); + this.segmentGraphics.beginFill(segmentColorHex); this.segmentGraphics.drawRect( xPos, - this.currentYScale(segment.yvalue), + this.currentYScaleSegments(segment.yvalue), width, - this.segmentHeight, + this.options.segmentHeight, ); + if (this.options.show_total_cn) { + this.segmentGraphics.beginFill(blackColorHex); + this.segmentGraphics.drawRect( + xPos, + this.currentYScalePoints(segment.total_cn), + width, + 2, + ); + } }); this.loadingText.text = ''; @@ -225,12 +379,13 @@ function ScannerResultTrack(HGC, ...args) { this.mouseOverGraphics.clear(); requestAnimationFrame(this.animate); - const padding = 2; + const padding = 0; const filteredList = this.data.filter( (segment) => - trackY >= this.currentYScale(segment.yvalue) && - trackY <= this.currentYScale(segment.yvalue) + this.segmentHeight && + trackY >= this.currentYScaleSegments(segment.yvalue) && + trackY <= + this.currentYScaleSegments(segment.yvalue) + this.options.segmentHeight && this._xScale(segment.fromAbs) <= trackX + padding && trackX <= this._xScale(segment.toAbs) + padding, ); @@ -256,16 +411,16 @@ function ScannerResultTrack(HGC, ...args) { `