UNPKG

@gmod/jbrowse

Version:

JBrowse - client-side genome browser

183 lines (166 loc) 6.15 kB
/** * The scaling used for drawing a Wiggle track, which is the data's * origin. * * Has numeric attributes range, min, max, origin, and offset. */ define([ 'dojo/_base/lang', 'JBrowse/Util', 'JBrowse/Digest/Crc32' ], function( lang, Util, Digest ) { return Util.fastDeclare({ // Returns a boolean value saying whether a stats object is needed // to calculate the scale for the given configuration. // // This is invokable either on the class (prototype) or on // the object itself, so does not use `this` in its implementation. needStats: function( config ) { return !( ( 'min_score' in config ) && ( 'max_score' in config ) && ( config.bicolor_pivot != 'z_score' && config.bicolor_pivot != 'mean' ) && ( config.scale != 'z_score' ) ); }, constructor: function( config, stats ) { var needStats = this.needStats( config ); if( needStats && !stats ) throw 'No stats object provided, cannot calculate scale'; if( needStats && stats.scoreMin == stats.scoreMax ) { stats = lang.mixin( {}, stats ); if( stats.scoreMin < 0 ) stats.scoreMax = 0; else stats.scoreMin = 0; } // if either autoscale or scale is set to z_score, the other one should default to z_score if( config.autoscale == 'z_score' && ! config.scale || config.scale == 'z_score' && !config.autoscale ) { config.scale = 'z_score'; config.autoscale = 'z_score'; } var z_score_bound = parseFloat( config.z_score_bound ) || 4; var min = 'min_score' in config ? parseFloat( config.min_score ) : (function() { switch( config.autoscale ) { case 'z_score': return Math.max( -z_score_bound, (stats.scoreMin-stats.scoreMean) / stats.scoreStdDev ); case 'global': case 'local': return stats.scoreMin; case 'clipped_global': /* fall through */ default: return Math.max( stats.scoreMin, stats.scoreMean - z_score_bound * stats.scoreStdDev ); } })(); var max = 'max_score' in config ? parseFloat( config.max_score ) : (function() { switch( config.autoscale ) { case 'z_score': return Math.min( z_score_bound, (stats.scoreMax-stats.scoreMean) / stats.scoreStdDev ); case 'global': case 'local': return stats.scoreMax; case 'clipped_global': /* fall through */ default: return Math.min( stats.scoreMax, stats.scoreMean + z_score_bound * stats.scoreStdDev ); } })(); if( typeof min != 'number' || isNaN(min) ) { min = 0; } if( typeof max != 'number' || isNaN(max) ) { max = min + 10; } var offset = parseFloat( config.data_offset ) || 0; if( config.scale == 'log' ) { max = this.log( max + offset ); min = this.log( min + offset ); } else { max += offset; min += offset; } var origin = (function() { if ( 'bicolor_pivot' in config ) { if ( config.bicolor_pivot == 'mean' ) { return stats.scoreMean || 0; } else if ( config.bicolor_pivot == 'zero' ) { return 0; } else { return parseFloat( config.bicolor_pivot ); } } else if ( config.scale == 'z_score' ) { return stats.scoreMean || 0; } else if ( config.scale == 'log' ) { return 1; } else { return 0; } })(); lang.mixin( this, { offset: offset, min: min, max: max, range: max - min, origin: origin, _statsFingerprint: Digest.objectFingerprint( stats ) }); if( needStats ) { this.scoreMean = stats.scoreMean; this.scoreStdDev = stats.scoreStdDev; } // make this.normalize a func that converts wiggle values to a // range between 0 and 1, depending on what kind of scale we // are using this.normalize = (function(config) { switch( config.scale ) { case 'z_score': return function( value ) { return (value+this.offset-this.scoreMean) / this.scoreStdDev-this.min / this.range; }; case 'log': return function( value ) { return ( this.log(value+this.offset) - this.min )/this.range; }; case 'linear': /* fall through */ default: return function( value ) { return ( value + this.offset - this.min ) / this.range; }; } })(config); }, log: function( value ) { return value ? Math.log( Math.abs( value ) ) * ( value < 0 ? -1 : 1 ) : 0; }, /** * Standard comparison function, compare this scale to another one. */ compare: function( b ) { if( ! b ) return 1; var a = this; return ( a.offset - b.offset ) || ( a.min - b.min ) || ( a.max - b.max ) || ( a.range - b.range ) || ( a.origin - b.origin ); }, /** * Return true if this scaling was generated from the same set of stats. */ sameStats: function( stats ) { return this._statsFingerprint == Digest.objectFingerprint( stats ); } }); });