Commit 58d7baf2 authored by Mathieu Giraud's avatar Mathieu Giraud

Merge branch 'feature-c/3644-3645-normalization' into 'dev'

Refactor and extend normalization

See merge request !379
parents 3425e544 56609a4c
Pipeline #56881 passed with stages
in 6 minutes and 39 seconds
......@@ -28,3 +28,5 @@ dep.mk
/browser/css/*.css
/browser/cgi/align.cgi
/browser/js/conf.js
node_modules/
cypress/
\ No newline at end of file
......@@ -55,7 +55,7 @@
<input id="upload_pref" type="file" name="pref" /></br>
<p class='help'>The .analysis file stores all parameters set by the user (tags, colors, manual clusters).</p>
<button onclick="document.getElementById('file_menu').style.display='none';
<button id="start_import_json" onclick="document.getElementById('file_menu').style.display='none';
m.load('upload_json','upload_pref', 200)">start</button>
</div>
......@@ -194,8 +194,20 @@
<div class="menu" id="settings_menu" onmouseenter="builder.build_settings();" onmouseover=" showSelector('settingsSelector');" > settings
<div id="settingsSelector" class="selector"><div>
<div class="menu_box">
normalization</br>
<form name="normalize_list" id="normalize_list">
normalization
<form name="normalize_list_2" id="normalize_list_2">
<label id="no_normalization" for="no_normalization_input" class="buttonSelector" onclick="m.set_normalization(m.NORM_FALSE); m.update()">
<input id="no_normalization_input" type="radio" name="normalization" value="no_norm" />
no normalization
</label>
<label id="external_normalization" for="external_normalization_input" class="buttonSelector" onclick="m.set_normalization(m.NORM_EXTERNAL); m.update()">
<input id="external_normalization_input" type="radio" name="normalization" value="external_normalization" />
from input data
</label>
<label id="expected_normalization" for="expected_normalization_input" class="buttonSelector" onclick="m.set_normalization(m.NORM_EXPECTED); m.update()">
<input id="expected_normalization_input" type="radio" name="normalization" value="expected_normalization" />
set on a given clone
</label>
</form>
</div>
<div class="menu_box">
......
......@@ -475,10 +475,7 @@ Clone.prototype = {
if (this.m.reads.segmented[time] === 0 ) return 0;
var result = this.getReads(time) / this.m.reads.segmented[time];
if (this.m.norm) result = this.m.normalize(result, time);
return result;
return this.m.normalize(result, time)
}, //end getSize
/**
......@@ -537,10 +534,7 @@ Clone.prototype = {
if (this.m.reads.segmented[time] === 0 ) return 0
var result = this.getReads(time) / this.m.reads.segmented[time]
if (this.m.norm ) result = this.m.normalize(result, time)
return result
return this.m.normalize(result, time)
},
/**
......@@ -564,10 +558,7 @@ Clone.prototype = {
if (system_reads === 0 ) return 0
var result = this.getReads(time) / system_reads
if (this.m.norm) result = this.m.normalize(result, time)
return result
return this.m.normalize(result, time)
},
/**
......@@ -622,9 +613,7 @@ Clone.prototype = {
if (group_reads === 0 ) return 0 ;
var result = this.getReads(time) / group_reads
if (this.norm) result = this.normalize(result, time)
return result
return this.m.normalize(result, time)
},
/* return a printable information: length, number of reads, and ratios
......@@ -688,13 +677,7 @@ Clone.prototype = {
if (this.m.reads.segmented[time] === 0 ) return 0
var result = this.get('reads',time) / this.m.reads.segmented[time]
if (this.norm) {
result = this.m.normalize(result, time)
}
return result
return this.m.normalize(result, time)
}, //end getSequenceSize
getStrSequenceSize: function (time) {
......@@ -713,7 +696,7 @@ Clone.prototype = {
var cluster = this.getCluster()
for (var j = 0; j < cluster.length; j++) {
result += this.m.clone(cluster[j]).reads[time];
result += this.m.normalize_reads(this.m.clone(cluster[j]), time);
}
return result
......@@ -1394,12 +1377,15 @@ Clone.prototype = {
self.m.openTagSelector(self.index, e);
}
span_star.id = self.index
if ((self.m.norm)&&(self.index==self.m.normalization.id)){
span_star.appendChild(icon('icon-lock-1', 'clone tag'))
var tag_icon = document.createElement('i')
tag_icon.id = "tag_icon_"+self.index
tag_icon.title = "clone_tag"
if ((self.m.normalization_mode == self.m.NORM_EXPECTED)&&(self.index==self.m.normalization.id)){
tag_icon.classList.add('icon-lock-1')
}else{
span_star.appendChild(icon('icon-star-2', 'clone tag'))
tag_icon.classList.add('icon-star-2')
}
span_star.appendChild(tag_icon)
span_star.setAttribute('id', 'color' + this.index);
if (typeof this.tag != 'undefined')
span_star.style.color = this.m.tag[this.getTag()].color
......@@ -1560,7 +1546,39 @@ Clone.prototype = {
}
return res;
}
},
/**
* Update the clone tag icon
*/
updateCloneTagIcon: function () {
// get the icon tag element
icon_tag = document.getElementById("tag_icon_"+this.index)
if (icon_tag != null){
icon_tag.classList.remove("icon-star-2")
icon_tag.classList.remove("icon-lock-1")
icon_tag.classList.remove("icon-star-empty-1")
// change class in function of model.normalization method
if (this.m.normalization_mode == this.m.NORM_EXPECTED){
var expected_clone_index = this.m.normalization.id
if (expected_clone_index == this.index){
icon_tag.classList.add("icon-lock-1")
} else {
icon_tag.classList.add("icon-star-2")
}
} else if (this.m.normalization_mode == this.m.NORM_EXTERNAL){
if (this.normalized_reads != undefined){
icon_tag.classList.add("icon-star-empty-1")
} else {
icon_tag.classList.add("icon-star-2")
}
} else {
icon_tag.classList.add("icon-star-2")
}
}
return
},
};
......
......@@ -462,7 +462,7 @@ Report.prototype = {
},
normalizeInfo: function () {
if (this.m.norm){
if (this.m.normalization_mode != this.NORM_FALSE){
var container = this.container("Normalization")
var norm_id = this.m.normalization.id
var norm_value = this.m.normalization.B
......
......@@ -544,15 +544,9 @@ Graph.prototype = {
];
var size = []
if (this.m.norm === true){
for (var j = 0; j < res.length; j++) {
size[j] = this.m.normalize(res[j], j)
}
}else{
for (var k = 0; k < res.length; k++) {
size[k] = res[k]
}
}
p.push([0, (1 - this.scale_x(size[0] * this.m.precision))]);
......@@ -749,7 +743,7 @@ Graph.prototype = {
for (var i = 0; i < this.m.samples.number; i++) {
var t = this.m.samples.order.indexOf(i)
var val = this.m.data[key][t]
if (this.m.norm && this.m.normalization.type=="data") val = this.m.normalize(val,t)
val = this.m.normalize(val,t)
tab.push(val)
}
......@@ -971,14 +965,12 @@ Graph.prototype = {
var max = this.m.precision*this.m.max_size
//get ready for something really dirty
if (this.m.norm){
for (var i=0; i<this.m.samples.order.length; i++) {
for (var j=0; j<this.m.clones.length; j++){
var size = this.m.precision*this.m.clone(j).getSize()
if (size>max) max=size;
}
}
}
this.scale_x = d3.scale.log()
.domain([1, max])
......@@ -1028,15 +1020,13 @@ Graph.prototype = {
var max = this.m.data[key][0];
var min = this.m.data[key][0];
if (this.m.norm && this.m.normalization.type=="data"){
max = this.m.normalize(max, 0)
min = this.m.normalize(min, 0)
}
for (var i = 0; i < this.m.samples.number; i++) {
var t = this.m.samples.order.indexOf(i)
var val = this.m.data[key][t]
if (this.m.norm && this.m.normalization.type=="data") val = this.m.normalize(val, t)
val = this.m.normalize(val, t)
if (val>max) max=val;
if (val<min) min=val;
}
......
......@@ -57,6 +57,11 @@ function Model() {
this.germlineList = new GermlineList()
this.build();
window.onresize = function () { self.resize(); };
this.NORM_FALSE = "no_norm"
this.NORM_EXPECTED = "expected"
this.NORM_EXTERNAL = "external"
this.normalization_mode = this.NORM_FALSE
}
......@@ -170,7 +175,6 @@ Model.prototype = {
this.cloneNotationType="short_sequence";
this.alleleNotation = "when_not_01";
this.norm = false;
this.normalization = {
"method" : "constant",
"size_list" : [],
......@@ -178,6 +182,7 @@ Model.prototype = {
"id" : -1
};
this.normalization_list=[]
this.normalization_mode = this.NORM_FALSE
/*Variables pour DBSCAN*/
this.eps = 0;
this.nbr = 0;
......@@ -268,6 +273,7 @@ Model.prototype = {
* */
initClones: function () {
console.log("initClones()");
var have_external_normalization = false
// time_type to name_short if there is many samples
if (this.samples.order.length > 6)
......@@ -285,6 +291,9 @@ Model.prototype = {
clone = this.clone(i)
var n = clone.getNlength();
if (n > n_max) {n_max = n; }
if (clone.normalized_reads){
have_external_normalization = true
}
}
this.n_max = n_max
......@@ -297,6 +306,14 @@ Model.prototype = {
this.applyAnalysis(this.analysis);
this.initData();
if (have_external_normalization){
this.set_normalization(this.NORM_EXTERNAL)
// change radio button selection
var radio = document.getElementById("external_normalization_input")
if (radio != undefined) {
radio.checked = true;
}
}
}, //end initClones
changeCloneNotation: function(cloneNotationType) {
......@@ -630,25 +647,56 @@ changeAlleleNotation: function(alleleNotation) {
}
},
/**
* [changeNormalisation description]
* @param {String} mode - some this.NORM_*
* @return {[type]} [description]
*/
set_normalization: function(mode){
if (mode !== this.NORM_FALSE && mode !== this.NORM_EXPECTED && mode !== this.NORM_EXTERNAL ){
console.error("Try to change to an undetermined mode of normalization")
this.normalization_mode = this.NORM_FALSE
return
}
this.normalization_mode = mode
return
},
/**
* normalize a size to match the normalization done on a given time/sample
* normalize a ratio/size to match the normalization done on a given time/sample
* normalization is done when update is
* @param {float} original_size - size before normalization
* @param {integer} time - time/sample index of the timepoint where happen the normalization
* @return {float} normalized_size - size after normalization
* */
normalize: function (original_size, time) {
normalize: function (original_size, time, normalized_reads) {
var normalized_size = 0;
if (this.normalization_mode == this.NORM_EXPECTED){
if (this.normalization.size_list.length !== 0 && this.normalization.size_list[time] !== 0) {
var A = this.normalization.size_list[time] /* standard/spike at point time */
var B = this.normalization.expected_size /* standard/spike expected value */
normalized_size = (original_size * B) / A
}else{
normalized_size = original_size
return normalized_size
}
}
return normalized_size
// includes this.NORM_FALSE
return original_size
},
/**
* normalize a number of reads
*/
normalize_reads: function(clone, time) {
if (this.normalization_mode == this.NORM_EXTERNAL && clone.normalized_reads != undefined) {
return clone.normalized_reads[time] ;
} else {
return clone.reads[time] ;
}
},
/**
......@@ -658,11 +706,9 @@ changeAlleleNotation: function(alleleNotation) {
* */
compute_normalization: function (cloneID, expected_size) {
if (cloneID==-1){
this.norm = false
expected_size = 0;
this.normalization.id = cloneID
}else{
this.norm = true
expected_size = typeof expected_size !== 'undefined' ? expected_size : this.clone(cloneID).expected;
this.normalization.size_list = []
......@@ -670,14 +716,13 @@ changeAlleleNotation: function(alleleNotation) {
this.normalization.id = cloneID
this.normalization.type = "clone"
var tmp = this.norm
this.norm = false
var tmp = this.normalization_mode
this.normalization_mode = this.NORM_FALSE
for (var i=0; i<this.samples.number; i++){
this.normalization.size_list[i] = this.clone(cloneID).getSize(i)
}
this.norm = tmp
this.normalization_mode = tmp
norm_hash = jQuery.extend(true, {}, this.normalization)
this.normalization_list.push(norm_hash)
......@@ -692,7 +737,6 @@ changeAlleleNotation: function(alleleNotation) {
* */
compute_data_normalization: function (data, expected_size) {
expected_size = typeof expected_size !== 'undefined' ? expected_size : this.data[data].expected;
this.norm = true
this.normalization.size_list = []
this.normalization.expected_size = expected_size
......@@ -726,13 +770,13 @@ changeAlleleNotation: function(alleleNotation) {
for (var i=0; i<this.samples.order.length; i++){
var t = this.samples.order[i]
var size = this.min_sizes[t]
if (this.norm) size = this.normalize(this.min_sizes[t], t)
size = this.normalize(this.min_sizes[t], t)
if (size < min_size) min_size = size
}
this.max_size = 1
this.min_size = min_size
if (this.norm){
if (this.normalization_mode != this.NORM_FALSE){
for (var j=0; j<this.samples.order.length; j++){
if(this.normalization.size_list[j]==0){
max = this.normalization.expected_size
......@@ -1049,17 +1093,10 @@ changeAlleleNotation: function(alleleNotation) {
for (var n = 0; n < this.clones.length; n++) {
this.clone(n).updateColor()
}
// update icon if normalisation is setup
if(this.norm){
$("i.icon-lock-1").toggleClass('icon-lock-1 icon-star-2')
$("#"+this.normalization.id+" i.icon-star-2").toggleClass('icon-star-2 icon-lock-1')
$("#f"+this.normalization.id+" i.icon-star-2").toggleClass('icon-star-2 icon-lock-1')
}else{
$("i.icon-lock-1").toggleClass('icon-lock-1 icon-star-2')
// $("#f"+this.normalization.id+" i.icon-star-2").toggleClass('icon-lock-1 icon-star-2')
this.clone(n).updateCloneTagIcon()
}
},
/**
......@@ -1795,8 +1832,7 @@ changeAlleleNotation: function(alleleNotation) {
if (this.reads.segmented[time] === 0 ) return 0;
var result = this.NB_READS_THRESHOLD_QUANTIFIABLE / this.reads.segmented[time];
if (this.norm) result = this.normalize(result, time);
result = this.normalize(result, time);
return result;
},
......@@ -1960,11 +1996,14 @@ changeAlleleNotation: function(alleleNotation) {
var size = parseFloat(self.norm_input.value);
if (size>0 && size<1){
self.set_normalization( self.NORM_EXPECTED )
self.norm_input.value = ""
self.clone(cloneID).expected=size;
self.compute_normalization(cloneID, size)
self.update()
$(self.tagSelector).hide('fast')
document.getElementById("expected_normalization_input").checked = true;
}else{
console.log({"type": "popup", "msg": "expected input between 0.0001 and 1"});
}
......
......@@ -114,6 +114,13 @@ var json_clone5 = {
"top": 5,
};
// Clone with normalized_reads
var json_clone6 = {
"id" : "id6",
"reads" : [10,10,0,30],
"normalized_reads" : [20,20,0,30],
}
QUnit.test("name, informations, getHtmlInfo", function(assert) {
assert.equal(json_clone1.seg.junction.start, 10, "Start junction is 10 in JSON for clone 1");
......
......@@ -161,6 +161,8 @@ QUnit.test("tag/norm", function(assert) {
assert.equal(m.clone(1).getSize(), 0.1, "size before norm : Ok")
assert.equal(m.clone(2).getSize(), 0.125, "size before norm : Ok")
return; // TMP //
m.norm_input.value = 0.25;
m.norm_button.click();
......
......@@ -365,17 +365,34 @@ QUnit.test("normalization: test", function(assert) {
var c3 = new Clone(json_clone3, m, 2)
var c4 = new Clone(json_clone4, m, 3)
var c5 = new Clone(json_clone5, m, 4)
var c6 = new Clone(json_clone6, m, 4)
m.initClones()
m.set_normalization(m.NORM_FALSE)
assert.equal(c2.getSize(),0.05,"clone3 size")
m.set_normalization(m.NORM_EXPECTED)
m.compute_normalization(0,0.20)
assert.equal(m.normalization.expected_size,0.20, "expected value")
assert.deepEqual(m.normalization.expected_size, 0.20, "expected value")
assert.equal(c1.getSize().toFixed(2),m.normalization.expected_size,"clone1 normalized size")
assert.equal(c1.getSize(1).toFixed(2),m.normalization.expected_size,"clone1 normalized size")
assert.equal(c1.getSize(2),0,"clone1 normalized size")
assert.equal(m.normalize(c2.getSize(),0),0.8000000000000002,"normalize")
m.set_normalization(m.NORM_FALSE)
m.compute_normalization(-1,0)
assert.equal(c2.getSize(), 0.05, "clone3 size ")
// m.compute_data_normalization()
});
\ No newline at end of file
// Switch normalization to external (field normalized_reads)
m.set_normalization(m.NORM_EXTERNAL)
assert.equal(c6.getSize(), 0.1, "external normalization: 20 / 200")
assert.equal(c6.getSize(2), 0, "external normalization: 0 / 100")
assert.equal(c6.getSize(3), 0.3, "external normalization: 30 / 100")
assert.equal(c2.getSize(), 0.05, "external normalization have no effect on clone without field")
// Disable normalization
m.set_normalization(m.NORM_FALSE)
assert.equal(c2.getSize(), 0.05, "Clone 2 has correct size after disble normalization")
// Switch normalization again to NORM_EXPECTED
m.set_normalization(m.NORM_EXPECTED)
assert.equal(c6.getSize().toFixed(2), 0.2, "Clone 1 has correct size after switching again normalization to NORM_EXPECTED")
})
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment