Commit 5d797b9f authored by Mathieu Giraud's avatar Mathieu Giraud
Browse files

merge -- refactor axis management

See !601. Great work by @duez. Streamline axis handling.
Will soon allow new features on displaying axes/color/...
parents d0959315 dfb9b718
Pipeline #137920 passed with stages
in 57 minutes and 4 seconds
......@@ -32,3 +32,19 @@ node_modules/
cypress/
server/web2py/applications/vidjil/errors
*.bak
docker/vidjil-client/ssl/web2py.crt
docker/vidjil-client/ssl/web2py.key
tools/align.cgi
tools/similarity.cgi
germline/homo-sapiens/
germline/germline-59.tar.gz
germline/IMGT_RELEASE
vidjil-algo
......@@ -106,6 +106,7 @@ ul {
-ms-user-select: none;
user-select: none;
overflow: hidden;
height : 100%;
}
#mid-container {
position: fixed;
......@@ -2377,6 +2378,7 @@ textarea {
-moz-flex: 2 32%;
-ms-flex: 2 32%;
flex: 2 32%;
height : 100%;
}
#segmenter_panel {
bottom: 0;
......
......@@ -50,8 +50,7 @@ function loadAfterConf() {
require(["../germline"],
function() {
require(["../generic_axis",
"../closeable"],
require(["../closeable"],
function() {
require(["../compare",
"../menu",
......@@ -63,10 +62,11 @@ function loadAfterConf() {
"../clone",
"../dynprog",
"../list",
"../germline_axis",
"../numerical_axis",
"../axes",
"../axis",
"../graph",
"../scatterPlot_menu",
"../scatterPlot_selector",
"../scatterPlot",
"../builder",
"../info",
......
This diff is collapsed.
This diff is collapsed.
......@@ -94,9 +94,6 @@ function Clone(data, model, index, attributes) {
this.m.clusters[index]=[index]
this.m.clones[index]=this
this.tag = this.getTag();
this.computeGCContent()
this.computeCoverage()
this.computeEValue()
// .warn, client computed warnings
this.computeWarnings()
......@@ -132,10 +129,10 @@ Clone.prototype = {
computeWarnings: function() {
if (this.coverage < this.COVERAGE_WARN)
if (this.getCoverage() < this.COVERAGE_WARN)
this.warn.push({'code': 'W51', 'level': warnLevels[WARN], 'msg': 'Low coverage (' + this.coverage.toFixed(3) + ')'}) ;
if (typeof(this.eValue) != 'undefined' && this.eValue > this.EVALUE_WARN)
if (typeof(this.getEValue()) != 'undefined' && this.eValue > this.EVALUE_WARN)
this.warn.push({'code': 'Wxx', 'level': warnLevels[WARN], 'msg': 'Bad e-value (' + this.eValue + ')' });
},
......@@ -170,7 +167,7 @@ Clone.prototype = {
REGEX_GENE_IGNORE_ALLELE: /(IGH|IGK|IGL|TRA|TRB|TRG|TRD|IKZF1-|ERG-)([\w-]*)([\w-*]*)$/, // IGHV3-11*03 (ignore *03)
getAverageReadLength: function(time) {
if (this._average_read_length == 'undefined')
if (typeof this._average_read_length == 'undefined')
return 'undefined';
time = this.m.getTime(time);
var size = this._average_read_length[time];
......@@ -402,6 +399,7 @@ Clone.prototype = {
if (this.hasSizeDistrib()){
// TODO: move this function into an update function and store result into an attribute of this clone
var t = this.m.t
//if (this.current_clones == undefined) return "bob"
var n = this.current_clones[t]
var name = this.getDistributionsValues().toString() + " (" + n + " clone" + (n>1 ? "s" : "") + ")"
return name
......@@ -860,12 +858,16 @@ Clone.prototype = {
return true
},
computeEValue: function () {
getEValue: function () {
if (this.eValue) return this.eValue
var e = this.seg.evalue;
if (typeof(e) != 'undefined')
this.eValue = parseFloat(e.val)
else
this.eValue = undefined
return this.eValue
},
getGene: function (type, withAllele) {
......@@ -892,7 +894,7 @@ Clone.prototype = {
if (this.hasSeg('3', '5')){
return this.seg['3'].start-this.seg['5'].stop-1
}else{
return 'undefined'
return '?'
}
},
......@@ -943,8 +945,9 @@ Clone.prototype = {
/*
* Compute coverage as the average value of non-zero coverages
*/
getCoverage: function () {
if (this.coverage) return this.coverage
computeCoverage: function () {
if (typeof (this._coverage) == 'undefined') {
this.coverage = undefined
return
......@@ -960,9 +963,13 @@ Clone.prototype = {
}
}
this.coverage = sum/nb
return this.coverage
},
computeGCContent: function () {
getGCContent: function() {
if (this.GCContent) return this.GCContent
if (this.getSequenceLength() === 0) {
this.GCContent = undefined
return
......@@ -974,7 +981,9 @@ Clone.prototype = {
gc++ }
this.GCContent = gc / this.sequence.length
},
return this.GCContent
},
getSequenceLength : function () {
if (typeof (this.sequence) != 'undefined' &&
......@@ -1102,51 +1111,86 @@ Clone.prototype = {
var allele;
if (!this.hasSizeConstant()){
this.color = "rgba(150, 150, 150, 0.65)"
} else if (this.m.colorMethod == "abundance") {
var size = this.getSize()
if (this.getCluster().length===0){ size = this.getSequenceSize() }
if (size === 0){
this.color = "";
}else{
this.color = colorGenerator(this.m.scale_color(size * this.m.precision));
}
} else if (this.m.colorMethod == 'clone') {
this.color = colorGeneratorIndex(this.index)
} else if (this.m.colorMethod == 'cdr3') {
this.color = this.getCDR3Color();
}else if (this.m.colorMethod == "Tag"){
this.color = this.m.tag[this.getTag()].color;
}else if (this.m.colorMethod == "dbscan"){
this.color = this.colorDBSCAN;
}else if (this.m.colorMethod == "V" && this.getGene("5") != "undefined V"){
this.color = "";
allele = this.m.germlineV.allele[this.getGene("5")]
if (typeof allele != 'undefined' ) this.color = allele.color;
}else if (this.m.colorMethod == "D" && this.getGene("4") != "undefined D"){
this.color = "";
allele = this.m.germlineD.allele[this.getGene("4")]
if (typeof allele != 'undefined' ) this.color = allele.color;
}else if (this.m.colorMethod == "J" && this.getGene("3") != "undefined J"){
this.color = "";
allele = this.m.germlineJ.allele[this.getGene("3")]
if (typeof allele != 'undefined' ) this.color = allele.color;
}else if (this.m.colorMethod == "N"){
this.color = this.colorN;
}else if (this.m.colorMethod == "system") {
this.color = this.m.germlineList.getColor(this.germline)
} else if (this.m.colorMethod == 'productive') {
if (this.hasSeg('junction') &&
typeof this.seg.junction.productive != 'undefined') {
this.color = colorProductivity(this.seg.junction.productive)
}
}else{
this.color = "";
return
}
this.true_color = this.color
if (this.m.focus == this.index){
this.color = "";
switch (this.m.colorMethod){
case "abundance":
var size = this.getSize()
if (this.getCluster().length===0)
size = this.getSequenceSize()
if (size === 0)
this.color = ""
else
this.color = colorGenerator(this.m.scale_color(size * this.m.precision))
break;
case "clone":
this.color = colorGeneratorIndex(this.index)
break;
case "cdr3":
this.color = this.getCDR3Color()
break;
case "Tag":
this.color = this.m.tag[this.getTag()].color
if (this.color == "default") this.color = ""
break;
case "dbscan":
this.color = this.colorDBSCAN
break;
case "system":
this.color = this.m.germlineList.getColor(this.germline)
break;
case "productive":
this.color = ""
if (this.hasSeg('junction') &&
typeof this.seg.junction.productive != 'undefined')
this.color = colorProductivity(this.seg.junction.productive)
break;
case "N":
this.color = this.colorN
break;
case "V":
this.color = ""
if (this.getGene("5") != "undefined V"){
var alleleV = this.m.germlineV.allele[this.getGene("5")]
if (typeof alleleV != 'undefined' ) this.color = alleleV.color
}
break;
case "D":
this.color = ""
if (this.getGene("4") != "undefined D"){
var alleleD = this.m.germlineD.allele[this.getGene("4")]
if (typeof alleleD != 'undefined' ) this.color = alleleD.color
}
break;
case "J":
this.color = ""
if (this.getGene("3") != "undefined J"){
var alleleJ = this.m.germlineJ.allele[this.getGene("3")]
if (typeof alleleJ != 'undefined' ) this.color = alleleJ.color
}
break;
default:
this.color = ""
}
this.true_color = this.color
if (this.m.focus == this.index)
this.color = ""
},
/**
......@@ -1375,7 +1419,7 @@ Clone.prototype = {
}
//coverage info
if (typeof this.coverage != 'undefined') {
if (typeof this.getCoverage() != 'undefined') {
html += row_1("average coverage",
"<span " +
(this.coverage < this.COVERAGE_WARN ? "class='warning'" : "") +
......@@ -1384,7 +1428,7 @@ Clone.prototype = {
}
// e-value
if (typeof this.eValue != 'undefined') {
if (typeof this.getEValue() != 'undefined') {
html += row_1("e-value",
"<span " +
(this.eValue > this.EVALUE_WARN ? "class='warning'" : "") +
......@@ -1522,16 +1566,16 @@ Clone.prototype = {
html += "</table></div>"
return html
},
/*
axisOptions: function() {
return [
"consensusLength", "averageLength", "nLength", "lengthCDR3",
"productivity", "productivity-IMGT",
"VIdentity-IMGT",
"tag", "coverage", "locus", "size", "nbSamples"
"clone consensus length", "clone average read length", "GC content", "N length",
"CDR3 length (nt)", "productivity", "productivity-IMGT",
"VIdentity-IMGT", "clone consensus coverage",
"tag", "coverage", "size", "number of samples", "primers"
];
},
*/
/**
* start to fill a node with clone informations common between segmenter and list
* @param {dom_object} div_elem - html element to complete
......@@ -1784,8 +1828,7 @@ Clone.prototype = {
round = true
}
var values = []
var axes_obj = this.m.axes
var available_axes = this.m.available_axes
var available_axes = Axis.prototype.available()
for (var a = 0; a < axes.length; a++) {
var axe = axes[a]
......@@ -1793,11 +1836,9 @@ Clone.prototype = {
if (axe == undefined || naxe == undefined){
console.default.error("Getter: not axis " + axe + "; ("+naxe+")")
}
if (available_axes[naxe] != undefined && available_axes[naxe].fct != undefined) {
var value = available_axes[naxe].fct(this, timepoint)
if (round && available_axes[naxe] != undefined && available_axes[naxe].round != undefined){
value = available_axes[naxe].round(value)
}
if (available_axes.indexOf(naxe) != -1 ) {
var axis_p = Axis.prototype.getAxisProperties(naxe)
var value = axis_p.fct(this, timepoint)
values.push( value )
} else {
console.default.error("Getter: not axis " + axe + "; ("+naxe+")")
......@@ -1896,7 +1937,7 @@ Clone.prototype = {
tmpValue.fill(value)
value = tmpValue
}
/*
var naxe = this.m.distrib_convertion[axe]
var available_axes = this.m.available_axes
if (available_axes[naxe] != undefined) {
......@@ -1907,12 +1948,16 @@ Clone.prototype = {
}
} else {
console.default.error( "Axe not present in obj: " + axe + ";" + naxe)
*/
// Each content should be hardcoded. Not optimal
if (axe == "GCContent") { this.GCContent = value}
else if (axe == "lenSeqAverage") { this._average_read_length = value}
else if (axe == "lenSeqConsensus") { this.consensusLength = value}
}
if (axe == "GCContent") { this.GCContent = value}
else if (axe == "lenSeqAverage") { this._average_read_length = value}
else if (axe == "lenSeqConsensus") { this.consensusLength = value}
else if (axe == "seg5") { this.seg[5] = { name: value}}
else if (axe == "seg4") { this.seg[4] = { name: value}}
else if (axe == "seg3") { this.seg[3] = { name: value}}
else if (axe == "lenCDR3") { this.seg.cdr3 = { start: 0,
stop: value}}
},
sameAxesAsScatter: function(scatterplot){
......@@ -1930,15 +1975,7 @@ Clone.prototype = {
}
if (mode == "bar"){
// on doit retirer dans ce cas le "size"
var pos_size = axes.indexOf("size")
if (pos_size != -1){
axes.splice(pos_size, 1)
return x.equals(axes)
} else {
// In mode bar, each axes should be associated with size
// console.default.warn( "same_axes_as_scatter: Only one axe to test (size not present), "+ axes)
}
return (x.indexOf(axes[0]) != -1)
} else {
// console.default.warn("same_axes_as_scatter: The scatter mode is not correct; '"+mode+"'")
return x.equals(axes)
......
......@@ -218,7 +218,7 @@ function imgtPostForSegmenter(species, data, system, segmenter, override_imgt_op
// sai : segmenter axis inputs ; activate productivity-IMGT and VIdentity-IMGT
var sai = document.getElementById('segmenter_axis_select').getElementsByTagName('input');
for (var index in sai) {
if (!sai[index].checked && (sai[index].value == "productivity-IMGT" || sai[index].value == "VIdentity-IMGT"))
if (!sai[index].checked && (sai[index].value == "productivity IMGT" || sai[index].value == "VIdentity IMGT"))
sai[index].click();
}
......
......@@ -39,6 +39,7 @@ function Database(model, address) {
this.m = model
this.uploader = new Uploader()
this.build()
this.m.db = this
window.onbeforeunload = function(e){
if ( self.uploader.is_uploading() ){
......@@ -1018,7 +1019,7 @@ Database.prototype = {
xhrFields: {withCredentials: true},
timeout: DB_TIMEOUT_CALL,
success: function (result) {
notification.parse_notification(result)
m.notification.parse_notification(result)
},
error: function (request, status, error) {
......
/*
* This file is part of Vidjil <http://www.vidjil.org>,
* High-throughput Analysis of V(D)J Immune Repertoire.
* Copyright (C) 2013-2017 by Bonsai bioinformatics
* at CRIStAL (UMR CNRS 9189, Université Lille) and Inria Lille
* Contributors:
* Marc Duez <marc.duez@vidjil.org>
* Antonin Carette <antonin.carette@etudiant.univ-lille1.fr>
* The Vidjil Team <contact@vidjil.org>
*
* "Vidjil" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "Vidjil" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "Vidjil". If not, see <http://www.gnu.org/licenses/>
*/
/**
* GenericAxis object contain labels and their position on an axis (from 0 to 1)
* can provide the position of an element on it
* @constructor
* */
function GenericAxis (reverse, can_undefined) {
this.labels = [];
this.label_mapping = {};
this.values = []
this.value_mapping = {};
this.can_undefined = true;
this.MAX_NB_STEPS_IN_AXIS = 14; // Number (max) of labels per numerical axis
this.MAX_NB_BARS_IN_AXIS = 200
this.NB_STEPS_BAR = 18; // Number (max) of labels per numerical axis in histograms
if(typeof can_undefined !== "undefined")
this.can_undefined = can_undefined;
this.reverse = false;
if(typeof reverse !== "undefined")
this.reverse = reverse
this.adapt = false
}
GenericAxis.prototype = {
init : function (values, key, labels, sort) {
this.reset();
this.values = values;
if (typeof sort === 'undefined') {sort = false;}
if (typeof key === 'function') {
this.converter = key;
} else {
this.converter = function(elem) {
return elem[key];
}
}
this.populateLabels(labels, sort);
this.populateValueMapping();
return this;
},
ignore: function(clone) {
return this.adapt && clone.isFiltered
},
compareLabels: function(a, b) {
if (typeof a === 'undefined') return (typeof b === 'undefined') ? 0 : -1;
if (typeof b === 'undefined') return (typeof a === 'undefined') ? 0 : 1;
if (a.constructor === String) {
if (b.constructor === String) return a.localeCompare(b);
if (b.constructor === Number ) return 1
}
if (a.constructor === Number) return (b.constructor === Number ) ? (a-b) : -1;
},
populateLabels: function(labels, sort) {
var values = this.values;
var label_mapping = this.label_mapping;
if (typeof labels === 'undefined')
this.computeLabels(values, sort);
else {
for (var i=0; i < values.length; i++) {
var value = values[i];
if (this.ignore(value))
continue;
var convert = this.applyConverter(value);
var pos;
if (labels.indexOf(convert) != -1) {
if (typeof label_mapping[convert] === 'undefined') {
pos = labels.indexOf(convert)/labels.length;
if (this.reverse)
pas = 1 - pos;
this.addLabel("line", convert, pos, convert);
}
} else {
if (this.can_undefined) {
pos = 1;
if (this.reverse)
pos = 0;
this.addLabel("line", "?", pos, "?");
}
}
}
}
var step = 1/(this.labels.length+1);
offset = step/2;
for (var idx in this.labels){
this.labels[idx].pos += offset;
}
},
populateValueMapping: function(round) {
for (var idx in this.values) {
var value = this.values[idx];
// if (value.isVirtual())
// continue ; // ? pas toujours ?
if (this.ignore(value))
continue;
var convert = this.applyConverter(value);
if (typeof round !== 'undefined')
convert = nice_ceil(convert - round/2, round)
if (typeof convert == "undefined" || convert == undefined || convert == "undefined" || Number.isNaN(convert)) {
if (this.can_undefined) {
if (typeof this.value_mapping["?"] === 'undefined')
this.value_mapping["?"] = [];
this.value_mapping["?"].push(value);
}
}
else
{
this.value_mapping[convert]<