diff --git a/js/cnvpytor/CombinedCaller.js b/js/cnvpytor/CombinedCaller.js index a33187034..996da916f 100644 --- a/js/cnvpytor/CombinedCaller.js +++ b/js/cnvpytor/CombinedCaller.js @@ -352,7 +352,7 @@ class CombinedCaller{ return results } - formatDataStructure_BAF(feature_column, scaling_factor = 2) { + formatDataStructure_BAF(feature_column, scaling_factor = -1) { const baf1 = [] const baf2 = [] for (const [chr, wig] of Object.entries(this.wigFeatures)) { @@ -364,10 +364,10 @@ class CombinedCaller{ let value = sample[feature_column] if (value != 0.5){ - baf2_value.value = -2 * (1 - value) + baf2_value.value = scaling_factor * (1 - value) baf2.push(baf2_value) } - baf1_value.value = -2 * value + baf1_value.value = scaling_factor * value baf1.push(baf1_value) }) diff --git a/js/cnvpytor/HDF5IndexedReader.js b/js/cnvpytor/HDF5IndexedReader.js index cdcafd3ed..f028105f2 100644 --- a/js/cnvpytor/HDF5IndexedReader.js +++ b/js/cnvpytor/HDF5IndexedReader.js @@ -232,7 +232,7 @@ class HDF5Reader { return chr_wig } - async get_baf_signals(chrom, bin_size, signal_name){ + async get_baf_signals(chrom, bin_size, signal_name, scaling_factor = -1){ /* return two list of dictionary*/ let chr_wig_1 = []; let chr_wig_2 = []; @@ -243,16 +243,16 @@ class HDF5Reader { let max_value = Math.max(...bin_value); const res = bin_value.indexOf(max_value); let lh = Math.max(res / 200, 1 - res / 200); - chr_wig_1.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: -2 * lh}) + chr_wig_1.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: scaling_factor * lh}) if(lh != 0.5){ - chr_wig_2.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: -2 *(1-lh)}) + chr_wig_2.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: scaling_factor *(1-lh)}) } }); } return [chr_wig_1, chr_wig_2] } - async get_baf_signals_v2(chrom, bin_size, signal_name){ + async get_baf_signals_v2(chrom, bin_size, signal_name, scaling_factor = -1){ /* return two list of dictionary*/ let chr_wig_1 = []; @@ -262,9 +262,9 @@ class HDF5Reader { let chrom_data = await chrom_dataset.to_array() //create_nested_array(value, shape) chrom_data.forEach((lh, bin_idx) => { if (!isNaN(lh)){ - chr_wig_1.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: -2 * ( 0.5 - lh )}) + chr_wig_1.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: scaling_factor * ( 0.5 - lh )}) if(lh != 0.5){ - chr_wig_2.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: -2 * ( 0.5 + lh )}) + chr_wig_2.push({chr:chrom, start: bin_idx*bin_size, end: (bin_idx+1) * bin_size, value: scaling_factor * ( 0.5 + lh )}) } } }); diff --git a/js/cnvpytor/cnvpytorTrack.js b/js/cnvpytor/cnvpytorTrack.js index 6c9ded55d..a7cd3350a 100644 --- a/js/cnvpytor/cnvpytorTrack.js +++ b/js/cnvpytor/cnvpytorTrack.js @@ -25,7 +25,6 @@ */ import TrackBase from "../trackBase.js" -import paintAxis from "../util/paintAxis.js" import MenuUtils from "../ui/menuUtils.js" import HDF5IndexedReader from "./HDF5IndexedReader.js" import {CNVpytorVCF} from "./cnvpytorVCF.js" @@ -47,7 +46,6 @@ class CNVPytorTrack extends TrackBase { constructor(config, browser) { super(config, browser) this.featureType = 'numeric' - this.paintAxis = paintAxis if (!config.max) { this.defaultScale = true @@ -118,8 +116,9 @@ class CNVPytorTrack extends TrackBase { this.wigFeatures_obj[this.bin_size] = {} let dataWigs; - if(this.config.cnv_caller == '2D'){ + if(this.cnv_caller == '2D'){ + dataWigs = await cnvpytor_obj.read_rd_baf('2D') wigFeatures = dataWigs[0] @@ -409,17 +408,17 @@ class CNVPytorTrack extends TrackBase { if (this.defaultScale) { if (this.signal_name == 'rd_snp') { this.dataRange = { - min: this.config.min || this.dataRange.min || -2, - max: this.config.max || this.dataRange.max || 6 + min: this.config.min || this.dataRange.min || -1, + max: this.config.max || this.dataRange.max || 5 } } else if (this.signal_name == 'rd') { this.dataRange = { min: this.config.min || this.dataRange.min || 0, - max: this.config.max || this.dataRange.max || 6 + max: this.config.max || this.dataRange.max || 5 } } else if (this.signal_name == 'snp') { this.dataRange = { - min: this.config.min || this.dataRange.min || -2, + min: this.config.min || this.dataRange.min || -1, max: this.config.max || this.dataRange.max || 0 } } @@ -463,8 +462,96 @@ class CNVPytorTrack extends TrackBase { } } } + + let props = { + 'strokeStyle': 'lightgray', + 'strokeWidth': 0.5 + } + let y = yScale(2); + IGVGraphics.dashedLine(options.context, 0, y, options.pixelWidth, y, 5, props) + } + paintAxis(ctx, pixelWidth, pixelHeight) { + + var x1, + x2, + y1, + y2, + a, + b, + reference, + shim, + font = { + 'font': 'normal 10px Arial', + 'textAlign': 'right', + 'strokeStyle': "black" + } + + if (undefined === this.dataRange || undefined === this.dataRange.max || undefined === this.dataRange.min) { + return + } + + let flipAxis = (undefined === this.flipAxis) ? false : this.flipAxis + + IGVGraphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"}) + + reference = 0.95 * pixelWidth + x1 = reference - 8 + x2 = reference + + //shim = 0.5 * 0.125; + shim = .01 + y1 = y2 = shim * pixelHeight + + a = {x: x2, y: y1} + + // tick + IGVGraphics.strokeLine(ctx, x1, y1, x2, y2, font) + IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.min : this.dataRange.max), x1 + 4, y1 + 12, font) + + //shim = 0.25 * 0.125; + y1 = y2 = (1.0 - shim) * pixelHeight + + b = {x: x2, y: y1} + + // tick + IGVGraphics.strokeLine(ctx, x1, y1, x2, y2, font) + IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.max : this.dataRange.min), x1 + 4, y1 - 4, font) + + IGVGraphics.strokeLine(ctx, a.x, a.y, b.x, b.y, font) + + function prettyPrint(number) { + // if number >= 100, show whole number + // if >= 1 show 1 significant digits + // if < 1 show 2 significant digits + + if (number === 0) { + return "0" + } else if (Math.abs(number) >= 10) { + return number.toFixed() + } else if (number %1 == 0){ + return number.toFixed() + } + else if (Math.abs(number) >= 1) { + return number.toFixed(1) + } else { + return number.toFixed(2) + } + } + const scaleFactor = this.getScaleFactor(this.dataRange.min, this.dataRange.max, pixelHeight, this.logScale) + const yScale = (yValue) => this.logScale + ? this.computeYPixelValueInLogScale(yValue, scaleFactor) + : this.computeYPixelValue(yValue, scaleFactor) + const n = Math.ceil((this.dataRange.max - this.dataRange.min) /10) + for (let p = Math.ceil(this.dataRange.min+1); p < Math.round(this.dataRange.max - 0.4 ); p += n) { + const yp = yScale(p) + IGVGraphics.strokeLine(ctx, 45, yp, 50, yp, font) // Offset dashes up by 2 pixel + IGVGraphics.fillText(ctx, prettyPrint(flipAxis ? this.dataRange.max-p: p), 44, yp+4, font) + + } + + } popupData(clickState, features) { const featuresArray = features || clickState.viewport.cachedFeatures diff --git a/js/cnvpytor/cnvpytorVCF.js b/js/cnvpytor/cnvpytorVCF.js index 382a3a0d0..2b9d95b10 100644 --- a/js/cnvpytor/cnvpytorVCF.js +++ b/js/cnvpytor/cnvpytorVCF.js @@ -78,16 +78,13 @@ class CNVpytorVCF { // finalFeatureSet = this.readDepthMeanshift(avgbin) var baf = this.formatDataStructure_BAF(avgbin, 'max_likelihood') }else if(caller=='2D'){ - let caller_obj = new combined_caller.CombinedCaller(avgbin, this.binSize) let processed_bins = await caller_obj.call_2d() finalFeatureSet = [processed_bins.binScore, [], processed_bins.segment_score] - - var baf = caller_obj.formatDataStructure_BAF('max_likelihood') + var baf = caller_obj.formatDataStructure_BAF('max_likelihood', -1) } - return [finalFeatureSet, baf] } @@ -108,8 +105,6 @@ class CNVpytorVCF { return results } - - format_BAF_likelihood(wigFeatures) { const results = [] @@ -155,8 +150,8 @@ class CNVpytorVCF { - formatDataStructure_BAF(wigFeatures, feature_column, scaling_factor = 2) { - /* Rescale the BAF level from 0:1 to -2:0*/ + formatDataStructure_BAF(wigFeatures, feature_column, scaling_factor=-1) { + /* Rescale the BAF level from 0:1 to scaling_factpr:0*/ const baf1 = [] const baf2 = [] for (const [chr, wig] of Object.entries(wigFeatures)) { @@ -168,10 +163,10 @@ class CNVpytorVCF { let value = sample[feature_column] if (value != 0.5){ - baf2_value.value = -2 * (1 - value) + baf2_value.value = scaling_factor * (1 - value) baf2.push(baf2_value) } - baf1_value.value = -2 * value + baf1_value.value = scaling_factor * value baf1.push(baf1_value) }