From b5581309f4b0b0958d38acbead1c645cbdfc5baa Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 14:15:30 -0500 Subject: [PATCH 001/122] Set link[linkSortVariable] to 0 if not defined The only viable resolution to #77 --- components/files.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/files.html b/components/files.html index ad2531cb..2d4a2134 100644 --- a/components/files.html +++ b/components/files.html @@ -576,7 +576,12 @@ metric = metric.toLowerCase(); base[metric] = null; }); - base[session.state.linkSortVariable] = parseFloat(link[file.field3]); + var num = parseFloat(link[file.field3]); + if(_.isNumber(num) && !_.isNaN(num)){ + base[session.state.linkSortVariable] = num; + } else { + base[session.state.linkSortVariable] = 0; + } l += app.addLink(Object.assign(base, link), check); } From 33ac81a18cac3f9cca11a7fe2132fa0625394b4f Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 15:08:55 -0500 Subject: [PATCH 002/122] hotfix for loading older sessions --- scripts/common.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/common.js b/scripts/common.js index fa01605c..293f7ec7 100644 --- a/scripts/common.js +++ b/scripts/common.js @@ -663,6 +663,7 @@ app.applyStyle = function(style){ app.applySession = function(data, startTime){ session = data; if(!startTime) startTime = Date.now(); + if(!session.meta) session.meta = {}; session.meta.startTime = startTime; app.applyStyle(session.style); app.finishUp(true); From 696c7bbb32f6ec58a16b5f87115ac7824a61d094 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 16:42:02 -0500 Subject: [PATCH 003/122] Added a (delayed) call to fit on network load --- components/2d_network.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/2d_network.html b/components/2d_network.html index 76eef76a..a671809c 100644 --- a/components/2d_network.html +++ b/components/2d_network.html @@ -1144,5 +1144,7 @@ } }, 1); + setTimeout(fit, 1200); + })(); From eb114a8cf2ecce887938c2305acfb2962ec3d8d8 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 16:44:38 -0500 Subject: [PATCH 004/122] Settings button to point to appropriate settings --- components/files.html | 9 +++++---- index.html | 2 +- scripts/common.js | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/files.html b/components/files.html index 2d4a2134..643465c4 100644 --- a/components/files.html +++ b/components/files.html @@ -14,16 +14,16 @@ -
-
+
-
-
+
+
@@ -405,8 +402,8 @@ reference: session.data.reference, aligner: $('input[name="shouldAlign"]:checked').data('aligner'), isLocal: $('#localAlign').is(':checked'), - match: [parseFloat($('#alignerMatch').val()), parseFloat($('#alignerMismatch').val())], - gap: [parseFloat($('#alignerGapO').val()), parseFloat($('#alignerGapE').val())] + match: [parseFloat($('#alignerMatch').val()), -parseFloat($('#alignerMismatch').val())], + gap: [-parseFloat($('#alignerGapO').val()), -parseFloat($('#alignerGapE').val())] }, function(output){ alignmentViewer(output, { showID: false diff --git a/package-lock.json b/package-lock.json index 5d0f2efd..3c1fc1d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3594,11 +3594,6 @@ "resolved": "https://registry.npmjs.org/normals/-/normals-1.1.0.tgz", "integrity": "sha1-MltZXtNK/kZ6bFWhT9kIV4f/WcA=" }, - "ntseq": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ntseq/-/ntseq-1.1.0.tgz", - "integrity": "sha1-wfurCBP1HtK87A6vmy93tP+mIuI=" - }, "number-is-integer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-integer/-/number-is-integer-1.0.1.tgz", diff --git a/package.json b/package.json index 0b031cbf..c16bf300 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "marked": "^0.5.1", "moment": "^2.23.0", "neighborjoining": "git+https://github.com/CDCgov/neighborjoining.git", - "ntseq": "^1.1.0", "open-iconic": "^1.1.1", "papaparse": "^4.4.0", "patristic": "git+https://github.com/CDCgov/patristic.git", diff --git a/scripts/align-nbeam.js b/scripts/align-nbeam.js deleted file mode 100644 index 37df6484..00000000 --- a/scripts/align-nbeam.js +++ /dev/null @@ -1,24 +0,0 @@ -importScripts('../vendor/ntseq.js'); -onmessage = function(e){ - let start = Date.now(); - let subset = e.data.nodes; - let reference = new Nt.Seq(); - reference.read(e.data.reference); - let n = subset.length; - for(let i = 0; i < n; i++){ - let node = subset[i]; - let match = (new Nt.Seq()).read(node.seq); - let map = new Nt.MatchMap(match, reference); - map.initialize(); - map.sort(); - let best = map.best(); - node.padding = best.position; - node.score = best.score; - } - console.log('Alignment time: ', ((Date.now()-start)/1000).toLocaleString(), 's'); - start = Date.now(); - let encoder = new TextEncoder(); - output = encoder.encode(JSON.stringify(subset)).buffer; - postMessage({nodes: output, start: start}, [output]); - close(); -}; diff --git a/vendor/ntseq.js b/vendor/ntseq.js deleted file mode 100644 index c19240b1..00000000 --- a/vendor/ntseq.js +++ /dev/null @@ -1,1335 +0,0 @@ -var Nt = function() { - - 'use strict'; - - function makeArray(length, val) { - if (val === undefined) { val = 0|0; } - if (val < 0) { val = 0; } - length |= 0; - var max = 0; - for (var i = length; i !== 0; i >>>= 1) { max++; } - var n = Array(max); - n[0] = [val]; - for (i = 1; i < max; i++) { - n[i] = n[i-1].concat(n[i-1]); - } - var a = []; - for (var i = 0, l = length; l !== 0; l >>>= 1, i++) { - if (l&1) { - a = a.concat(n[i]); - } - } - return a; - }; - - var __bitCount = (function() { - var a = new Uint8Array(256); - var bin; - for (var i = 0; i < 256; i++) { - bin = i; - bin = bin - ((bin >> 1) & 0x55555555); - bin = (bin & 0x33333333) + ((bin >> 2) & 0x33333333); - a[i] = (((bin + (bin >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; - } - return a; - })(); - - var __nucleotideTo4Bit = Object.create(null); - __nucleotideTo4Bit['A'] = 8; // 0b1000 - __nucleotideTo4Bit['T'] = 4; // 0b0100 - __nucleotideTo4Bit['G'] = 2; // 0b0010 - __nucleotideTo4Bit['C'] = 1; // 0b0001 - - function setNucleotide() { - var n = arguments[0]; - __nucleotideTo4Bit[n] = 0; - for (var i = 1; i < arguments.length; i++) { - __nucleotideTo4Bit[n] |= __nucleotideTo4Bit[arguments[i]]; - } - }; - - setNucleotide('-'); - setNucleotide('W', 'A', 'T'); - setNucleotide('S', 'G', 'C'); - setNucleotide('M', 'A', 'C'); - setNucleotide('K', 'G', 'T'); - setNucleotide('R', 'A', 'G'); - setNucleotide('Y', 'C', 'T'); - setNucleotide('B', 'C', 'G', 'T'); - setNucleotide('D', 'A', 'G', 'T'); - setNucleotide('H', 'A', 'C', 'T'); - setNucleotide('V', 'A', 'C', 'G'); - setNucleotide('N', 'A', 'T', 'G', 'C'); - - var __4BitToNucleotide = ( - function() { - var a = makeArray(16); - var keys = Object.keys(__nucleotideTo4Bit); - for (var i = 0, len = keys.length; i < len; i++) { - a[__nucleotideTo4Bit[keys[i]]] = keys[i]; - } - return a; - } - )(); - - var __nucleotideList = Object.keys(__nucleotideTo4Bit); - - var __complementNucleotide = ( - function() { - var a = Object.create(null); - a['A'] = 'T'; - a['G'] = 'C'; - a['B'] = 'V'; - a['H'] = 'D'; - a['M'] = 'K'; - a['R'] = 'Y'; - // S, W, N, - not included - var keys = Object.keys(a); - for (var i = 0, len = keys.length; i < len; i++) { - a[a[keys[i]]] = keys[i]; - } - a['S'] = 'S'; - a['W'] = 'W'; - a['N'] = 'N'; - a['-'] = '-'; - return a; - } - )(); - - var __complement4Bit = ( - function() { - var a = new Uint8Array(16); - for (var i = 0, len = a.length; i < len; i++) { - a[i] = __nucleotideTo4Bit[__complementNucleotide[__4BitToNucleotide[i]]]; - } - return a; - } - )(); - - function nucleotideToBin(s) { - return __nucleotideTo4Bit[s] | 0; - } - - function binToNucleotide(b) { - return __4BitToNucleotide[b] || '-'; - } - - function complementNucleotide(s) { - return __complementNucleotide[s] || '-'; - } - - function complementBin(b) { - return __complement4Bit[b] | 0; - } - - /* Double up to form bytes */ - var __byteComplement; - var __nucleotidesToByte; - var __byteToNucleotides; - var __byteNucleotideContent; - - void function() { - - var a = Object.create(null); - var b = new Uint8Array(256); - var c = new makeArray(256); - var d = new makeArray(256); - - var keys = Object.keys(__nucleotideTo4Bit); - var len = keys.length; - var ki; - var kj; - var byte; - - for (var i = 0; i < len; i++) { - ki = keys[i]; - for (var j = 0; j < len; j++) { - kj = keys[j]; - byte = __nucleotideTo4Bit[ki] | (__nucleotideTo4Bit[kj] << 4); - a[ki + kj] = byte; - b[byte] = __nucleotideTo4Bit[complementNucleotide(kj)] | (__nucleotideTo4Bit[complementNucleotide(ki)] << 4); - c[byte] = ki + kj; - d[byte] = [ki, kj]; - } - } - - __nucleotidesToByte = a; - __byteComplement = b; - __byteToNucleotides = c; - __byteNucleotideContent = d; - - }(); - - function nucleotidesToByte(ss) { - return __nucleotidesToByte[ss] | 0; - } - - /* amino acids */ - - var __codonToAminoAcid = Object.create(null); - __codonToAminoAcid['AAA'] = 'K'; - __codonToAminoAcid['AAT'] = 'N'; - __codonToAminoAcid['AAG'] = 'K'; - __codonToAminoAcid['AAC'] = 'N'; - __codonToAminoAcid['ATA'] = 'I'; - __codonToAminoAcid['ATT'] = 'I'; - __codonToAminoAcid['ATG'] = 'M'; - __codonToAminoAcid['ATC'] = 'I'; - __codonToAminoAcid['AGA'] = 'R'; - __codonToAminoAcid['AGT'] = 'S'; - __codonToAminoAcid['AGG'] = 'R'; - __codonToAminoAcid['AGC'] = 'S'; - __codonToAminoAcid['ACA'] = 'T'; - __codonToAminoAcid['ACT'] = 'T'; - __codonToAminoAcid['ACG'] = 'T'; - __codonToAminoAcid['ACC'] = 'T'; - __codonToAminoAcid['TAA'] = '*'; - __codonToAminoAcid['TAT'] = 'Y'; - __codonToAminoAcid['TAG'] = '&'; - __codonToAminoAcid['TAC'] = 'Y'; - __codonToAminoAcid['TTA'] = 'L'; - __codonToAminoAcid['TTT'] = 'F'; - __codonToAminoAcid['TTG'] = 'L'; - __codonToAminoAcid['TTC'] = 'F'; - __codonToAminoAcid['TGA'] = '$'; - __codonToAminoAcid['TGT'] = 'C'; - __codonToAminoAcid['TGG'] = 'W'; - __codonToAminoAcid['TGC'] = 'C'; - __codonToAminoAcid['TCA'] = 'S'; - __codonToAminoAcid['TCT'] = 'S'; - __codonToAminoAcid['TCG'] = 'S'; - __codonToAminoAcid['TCC'] = 'S'; - __codonToAminoAcid['GAA'] = 'E'; - __codonToAminoAcid['GAT'] = 'D'; - __codonToAminoAcid['GAG'] = 'E'; - __codonToAminoAcid['GAC'] = 'D'; - __codonToAminoAcid['GTA'] = 'V'; - __codonToAminoAcid['GTT'] = 'V'; - __codonToAminoAcid['GTG'] = 'V'; - __codonToAminoAcid['GTC'] = 'V'; - __codonToAminoAcid['GGA'] = 'G'; - __codonToAminoAcid['GGT'] = 'G'; - __codonToAminoAcid['GGG'] = 'G'; - __codonToAminoAcid['GGC'] = 'G'; - __codonToAminoAcid['GCA'] = 'A'; - __codonToAminoAcid['GCT'] = 'A'; - __codonToAminoAcid['GCG'] = 'A'; - __codonToAminoAcid['GCC'] = 'A'; - __codonToAminoAcid['CAA'] = 'Q'; - __codonToAminoAcid['CAT'] = 'H'; - __codonToAminoAcid['CAG'] = 'Q'; - __codonToAminoAcid['CAC'] = 'H'; - __codonToAminoAcid['CTA'] = 'L'; - __codonToAminoAcid['CTT'] = 'L'; - __codonToAminoAcid['CTG'] = 'L'; - __codonToAminoAcid['CTC'] = 'L'; - __codonToAminoAcid['CGA'] = 'R'; - __codonToAminoAcid['CGT'] = 'R'; - __codonToAminoAcid['CGG'] = 'R'; - __codonToAminoAcid['CGC'] = 'R'; - __codonToAminoAcid['CCA'] = 'P'; - __codonToAminoAcid['CCT'] = 'P'; - __codonToAminoAcid['CCG'] = 'P'; - __codonToAminoAcid['CCC'] = 'P'; - - var __12BitToAminoAcid = (function() { - - var a = makeArray(4096, '?'); - var codons = Object.keys(__codonToAminoAcid); - var codon; - for (var i = 0, len = codons.length; i < len; i++) { - codon = codons[i]; - a[ - (nucleotideToBin(codon[2]) << 8) | - (nucleotideToBin(codon[1]) << 4) | - nucleotideToBin(codon[0]) - ] = __codonToAminoAcid[codon]; - } - - return a; - - })(); - - function Seq(type) { - - if (type === undefined) { - type = 'DNA'; - } - - if (!{'RNA': true, 'DNA': true}[type]) { - throw new Error('Sequence type ' + type + ' not supported'); - } - - this.__type = type; - this.__isRNA = (type === 'RNA'); - - this.__endPadding = 0; - - this.__buffer = new ArrayBuffer(4); - - this.__complement = null; - - this.__content = null; - this.__fractionalContent = null; - this.__contentATGC = null; - this.__fractionalContent = null; - - }; - - Seq.prototype.read = function(strData) { - - var ntToByte = nucleotidesToByte; - - var nucleotideString = strData.toUpperCase() - .replace(/\s/g, '') - .replace('U', 'T') - .replace(/[^ATGCBVHDMKRYSWN\-]/g, '-'); - - var length = nucleotideString.length | 0; - var max = length >>> 1; - var odd = length & 1; - - var endPadding = (4 - (max + odd) % 4) % 4; - this.__endPadding = endPadding; - - var buffer = new ArrayBuffer(max + odd + endPadding + 4); - var dataArray = new Int8Array(buffer, 4); - - var n; - var byte; - var content; - - for (var i = 0; i < max; i++) { - - n = i << 1; - dataArray[i] = ntToByte(nucleotideString[n] + nucleotideString[++n]); - - } - - if (odd) { - - dataArray[i] = __nucleotideTo4Bit[nucleotideString[i << 1]]; - - } - - this.__buffer = buffer; - this.__length = length; - (new Uint32Array(buffer, 0, 1))[0] = length; - - this.__complement = null; - - this.__content = null; - this.__fractionalContent = null; - this.__contentATGC = null; - this.__fractionalContent = null; - - return this; - - }; - - Seq.prototype.readFASTA = function(strFASTA) { - - var data = strFASTA.split(/\n\r?/gi); - - while (data.length && data[0][0] === '>') { - data.shift(); - } - - return this.read(data.join('')); - - }; - - Seq.prototype.readBuffer = function(buffer) { - - this.__buffer = buffer; - - var length = (new Uint32Array(buffer, 0, 1))[0]; - - var max = length >>> 1; - var odd = length & 1; - - var endPadding = (4 - (max + odd) % 4) % 4; - this.__endPadding = endPadding; - - this.__length = length; - - this.__complement = null; - - this.__content = null; - this.__fractionalContent = null; - this.__contentATGC = null; - this.__fractionalContent = null; - - return this; - - }; - - Seq.prototype.__byteComplement = function() { - - var bComp = __byteComplement; - - var fwdBuffer = this.__buffer; - var len = fwdBuffer.byteLength; - - var n, i; - - var copyBuffer, fromArray, copyArray; - - var isOdd = this.__length & 1; - - if (isOdd) { - - copyBuffer = new ArrayBuffer(len); - copyArray = new Uint32Array(copyBuffer, 4); - fromArray = new Uint32Array(fwdBuffer, 4); - - n = (len - 4) >>> 2; - while(n--) { - copyArray[n] = (fromArray[n] << 4) | ((fromArray[n - 1]) >>> 28); - } - - } else { - - copyBuffer = fwdBuffer; - - } - - var fwdArray = new Uint8Array(copyBuffer, 4); - - var buffer = new ArrayBuffer(len); - var dataArray = new Uint8Array(buffer, 4); - - n = (len - 4) - this.__endPadding; - i = 0; - while(n--) { - dataArray[i++] = bComp[fwdArray[n]]; - } - - (new Uint32Array(buffer, 0, 1))[0] = this.__length; - - return buffer; - - }; - - Seq.prototype.size = function() { - return this.__length; - }; - - Seq.prototype.sequence = function() { - - var byteToNt = __byteToNucleotides; - var buffer = this.__buffer; - - if (buffer.byteLength < 4) { - return ''; - } - - var dataArray = new Uint8Array(buffer, 4); - var len = (buffer.byteLength - 4) - this.__endPadding; - - var nts = makeArray(len); - - for (var i = 0; i < len; i++) { - nts[i] = byteToNt[dataArray[i]]; - } - - var returnString; - - i = nts.length - 1; - if (this.__length & 1) { - nts[i] = nts[i][0]; - } - - returnString = nts.join(''); - - if (this.__isRNA) { - returnString = returnString.replace(/T/gi, 'U'); - } - - return returnString; - - }; - - Seq.prototype.complement = function() { - - if (!this.__complement) { - this.__complement = this.__byteComplement(); - } - - var complement = new Seq(this.__type).readBuffer(this.__complement.slice(0)); - - complement.__complement = this.__buffer.slice(0); - - return complement; - - }; - - Seq.prototype.equivalent = function(seq) { - - if (!(seq instanceof Seq)) { - throw new Error('Can only check for equivalence between sequences'); - } - - if (this.__type !== seq.__type) { - return false; - } - - var checkInts = new Uint32Array(this.__buffer); - var compareInts = new Uint32Array(seq.__buffer); - - for (var i = 0, len = checkInts.length; i < len; i++) { - if (checkInts[i] !== compareInts[i]) { - return false; - } - } - - return true; - - }; - - Seq.prototype.replicate = function(start, length) { - - start |= 0; - - if (start < 0) { - start = this.__length + start; - } - - if (length === undefined) { - - if (start === 0) { - - return this.__clone(); - - } - - length = this.__length - start; - - } else { - - length |= 0; - length = Math.min(length, this.__length - start); - - } - - length = Math.min(length, this.__length - start); - - if (length <= 0) { - - return this.__nullSeq(); - - } - - return this.__slice(start, length); - - }; - - Seq.prototype.polymerize = function(seq) { - - var seqLen = seq.__length; - - if (!(seq instanceof Seq)) { - throw new Error('.polymerize requires valid sequence'); - } - - if (!this.__length) { - return seq.__clone(); - } - - var offset = this.__length; - var length = this.__length + seqLen; - - var max = length >>> 1; - var odd = length & 1; - - var endPadding = (4 - (max + odd) % 4) % 4; - var newBuffer = new ArrayBuffer(max + odd + endPadding + 4); - var newArray = new Uint32Array(newBuffer, 4); - - var copyBuffer = this.__buffer; - var copyArray = new Uint32Array(copyBuffer, 4); - - var seqBuffer = seq.__buffer; - var seqArray = new Uint32Array(seqBuffer, 4); - - var copyPos = 0; - var shift = (this.__length % 8) * 4; - var shiftSeq = 32 - shift; - - for (var len = copyArray.length; copyPos < len; copyPos++) { - newArray[copyPos] = copyArray[copyPos]; - } - - if (shift) { - - newArray[--copyPos] |= seqArray[0] << shift; - - for (var i = 0, len = seqArray.length; i < len; i++) { - newArray[++copyPos] = (seqArray[i] >>> shiftSeq) | (seqArray[i + 1] << shift); - } - - } else { - - for (var i = 0, len = seqArray.length; i < len; i++) { - newArray[copyPos++] = seqArray[i]; - } - - } - - (new Uint32Array(newBuffer, 0, 1))[0] = length; - - return new Seq(this.__type).readBuffer(newBuffer); - - }; - - Seq.prototype.insertion = function(seq, offset) { - - if (!(seq instanceof Seq)) { - throw new Error('Insertion requires valid sequence'); - } - - offset |= 0; - - if (offset < 0) { - offset = this.__length + offset; - } - - offset = Math.min(offset, this.__length); - - return this.replicate(0, offset).polymerize(seq).polymerize(this.replicate(offset)); - - }; - - Seq.prototype.deletion = function(offset, count) { - - if (offset === undefined || count === undefined) { - throw new Error('Must give valid offset and count for deletion'); - } - - offset |= 0; - count |= 0; - - if (count === 0) { - return this.__clone(); - } - - if (count < 0) { - throw new Error('Invalid count for deletion'); - } - - if (offset < 0) { - offset = this.__length + offset; - } - - offset = Math.min(offset, this.__length); - - return this.replicate(0, offset).polymerize(this.replicate(offset + count)); - - }; - - Seq.prototype.repeat = function(count) { - - count |= 0; - - var copy = this.replicate(); - var base = new Seq(this.__type); - - if (count <= 0) { - return base; - } - - while(true) { - if (count & 1) { - base = base.polymerize(copy); - } - count >>>= 1; - if (!count) { - break; - } - copy = copy.polymerize(copy); - } - - return base; - - }; - - Seq.prototype.mask = function(seq) { - - if (!(seq instanceof Seq)) { - throw new Error('Can only mask with valid sequence'); - } - - var newBuffer = this.__buffer.slice(0); - var newArray = new Uint32Array(newBuffer, 4); - var compareArray = new Uint32Array(seq.__buffer, 4); - - for (var i = 0, len = newArray.length; i < len; i++) { - newArray[i] &= compareArray[i]; - } - - return new Seq(this.__type).readBuffer(newBuffer); - - }; - - Seq.prototype.cover = function(seq) { - - if (!(seq instanceof Seq)) { - throw new Error('Can only cover with valid sequence'); - } - - var newBuffer = this.__buffer.slice(0); - var newArray = new Uint32Array(newBuffer, 4); - var compareArray = new Uint32Array(seq.__buffer, 4); - - for (var i = 0, len = newArray.length; i < len; i++) { - newArray[i] |= compareArray[i]; - } - - return new Seq(this.__type).readBuffer(newBuffer); - - }; - - Seq.prototype.__nullSeq = function() { - - return new Seq(this.__type).readBuffer(new ArrayBuffer(4)); - - }; - - Seq.prototype.__clone = function() { - - return new Seq(this.__type).readBuffer(this.__buffer.slice(0)); - - }; - - Seq.prototype.__slice = function(start, length) { - - var max = length >>> 1; - var odd = length & 1; - - var endPadding = (4 - (max + odd) % 4) % 4; - var newBuffer = new ArrayBuffer(max + odd + endPadding + 4); - var newArray = new Uint32Array(newBuffer, 4); - - var subBuffer = this.__buffer.slice(4 + (start >>> 1), 4 + (start >>> 1) + newBuffer.byteLength); - var subInt32Length = subBuffer.byteLength >>> 2; - var subArray = new Uint32Array(subBuffer, 0, subInt32Length); - - if (start & 1) { - - for (var i = 0, len = subArray.length; i < len; i++) { - newArray[i] = (subArray[i] >>> 4) | (subArray[i + 1] << 28); - } - - var remainder = subBuffer.byteLength - subArray.byteLength; - if (remainder) { - var remainderArray = new Uint8Array(newBuffer, 4 + (i << 2)); - var subRemainderArray = new Uint8Array(subBuffer, i << 2); - if (newArray.length > 0) { - newArray[i - 1] |= subRemainderArray[0] << 28; - } - for (var i = 0, len = subRemainderArray.length; i < len; i++) { - remainderArray[i] = (subRemainderArray[i] >>> 4) | (subRemainderArray[i + 1] << 4); - } - } - - } else { - - for (var i = 0, len = subArray.length; i < len; i++) { - newArray[i] = subArray[i]; - } - - var remainder = subArray.byteLength - subBuffer.byteLength; - if (remainder) { - var remainderArray = new Uint8Array(newBuffer, 4 + (i << 2)); - var subRemainderArray = new Uint8Array(subBuffer, i << 2); - for (var i = 0, len = subRemainderArray.length; i < len; i++) { - remainderArray[i] = subRemainderArray[i]; - } - } - - } - - var clearShift = ((endPadding * 2) + odd) * 4; - - var clearOut = new Uint32Array(newBuffer, newBuffer.byteLength - 4); - clearOut[0] = (clearOut[0] << clearShift) >>> clearShift; - - (new Uint32Array(newBuffer, 0, 1))[0] = length; - - return new Seq(this.__type).readBuffer(newBuffer); - - }; - - Seq.prototype.content = function() { - - if (!this.__content) { - - var ntContentByte = makeArray(256); - - var buffer = this.__buffer; - var dataArray = new Uint8Array(buffer); - - for(var i = 4; i < buffer.byteLength - this.__endPadding; i++) { - ntContentByte[dataArray[i]]++; - } - - var binToNt = binToNucleotide; - var ntList = __nucleotideList; - - var ntContent = Object.create(null); - for (var i = 0, len = ntList.length; i < len; i++) { - ntContent[ntList[i]] = 0; - } - - for (var i = 0, len = ntContentByte.length; i < len; i++) { - if (ntContentByte[i]) { - ntContent[binToNt(i & 0xF)] += ntContentByte[i]; - ntContent[binToNt(i >>> 4)] += ntContentByte[i]; - } - } - - if (this.__length & 1) { - ntContent['-']--; - } - - if (this.__isRNA) { - ntContent['U'] = ntContent['T']; - delete ntContent['T']; - } - - this.__content = ntContent; - - } - - var returnContent = Object.create(null); - var keys = Object.keys(this.__content); - for (var i = 0, len = keys.length; i < len; i++) { - returnContent[keys[i]] = this.__content[keys[i]]; - } - - return returnContent; - - }; - - Seq.prototype.fractionalContent = function() { - - if (!this.__fractionalContent) { - - var content = this.content(); - var nts = Object.keys(content); - for (var i = 0, len = nts.length; i < len; i++) { - content[nts[i]] = content[nts[i]] / this.__length; - } - - this.__fractionalContent = content; - - } - - var returnContent = Object.create(null); - var keys = Object.keys(this.__fractionalContent); - for (var i = 0, len = keys.length; i < len; i++) { - returnContent[keys[i]] = this.__fractionalContent[keys[i]]; - } - - return returnContent; - - }; - - Seq.prototype.contentATGC = function() { - - if (!this.__contentATGC) { - - var ntToBin = nucleotideToBin; - - var content = this.content(); - var nts = Object.keys(content); - var contentATGC = Object.create(null); - contentATGC['A'] = 0; - contentATGC['T'] = 0; - contentATGC['G'] = 0; - contentATGC['C'] = 0; - - var bits = 0; - var nt; - var ntBin; - var n; - var curContent; - - for (var i = 0, len = nts.length; i < len; i++) { - nt = nts[i]; - n = ntToBin(nt); - for (bits = 0; n; bits++) { n &= n - 1; } - - ntBin = ntToBin(nt); - curContent = content[nts[i]] * (1 / bits); - - contentATGC['A'] += (((ntToBin('A') & ntBin) | 0) && curContent); - contentATGC['T'] += (((ntToBin('T') & ntBin) | 0) && curContent); - contentATGC['G'] += (((ntToBin('G') & ntBin) | 0) && curContent); - contentATGC['C'] += (((ntToBin('C') & ntBin) | 0) && curContent); - - } - - if (this.__isRNA) { - contentATGC['U'] = contentATGC['T']; - delete contentATGC['T']; - } - - this.__contentATGC = contentATGC; - - } - - var returnContent = Object.create(null); - var keys = Object.keys(this.__contentATGC); - for (var i = 0, len = keys.length; i < len; i++) { - returnContent[keys[i]] = this.__contentATGC[keys[i]]; - } - - return returnContent; - - }; - - Seq.prototype.fractionalContentATGC = function() { - - if (!this.__fractionalContentATGC) { - - var content = this.contentATGC(); - var nts = Object.keys(content); - for (var i = 0, len = nts.length; i < len; i++) { - content[nts[i]] = content[nts[i]] / this.__length; - } - - this.__fractionalContentATGC = content; - - } - - var returnContent = Object.create(null); - var keys = Object.keys(this.__fractionalContentATGC); - for (var i = 0, len = keys.length; i < len; i++) { - returnContent[keys[i]] = this.__fractionalContentATGC[keys[i]]; - } - - return returnContent; - - }; - - Seq.prototype.translate = function(ntOffset, ntCount) { - - var binToAA = __12BitToAminoAcid; - - ntOffset |= 0; - - if (ntCount === undefined) { - ntCount = this.__length - ntOffset; - } - - ntCount |= 0; - ntCount -= (ntCount % 3); - - var offset = (ntOffset >>> 1) + 4; - var max = offset + (ntCount >>> 1) + (ntCount & 1); - - var dataArray = new Uint8Array(this.__buffer); - - var aminoAcids = makeArray(ntCount / 3); - /**/ - var aa = 0; - var lastByte, byte1, byte2, byte3; - - if ((ntOffset & 1) === 0) { - - for (var i = offset; i < max; i += 3) { - - var byte1 = dataArray[i]; - var byte2 = dataArray[i+1]; - var byte3 = dataArray[i+2]; - - aminoAcids[aa++] = binToAA[byte1 | ((byte2 & 0xF) << 8)]; - aminoAcids[aa++] = binToAA[(byte3 << 4) | (byte2 >>> 4)]; - - } - - } else { - - lastByte = dataArray[offset]; - - for (var i = offset + 1; i < max; i += 3) { - - byte1 = dataArray[i]; - byte2 = dataArray[i+1]; - byte3 = dataArray[i+2]; - - aminoAcids[aa++] = binToAA[(lastByte >> 4) | (byte1 << 4)]; - aminoAcids[aa++] = binToAA[byte2 | ((byte3 & 0xF) << 8)]; - - lastByte = byte3; - - } - - } - - if (ntCount & 1) { aminoAcids.pop(); } - - return aminoAcids.join(''); - - }; - - Seq.prototype.translateFrame = function(frame, AAoffset, AAcount) { - - if (frame === undefined) { - frame = 0; - } - - if (frame !== 0 && frame !== 1 && frame !== 2) { - throw new Error('Invalid translation frame, must be 0, 1 or 2.'); - } - - if (AAoffset === undefined) { - return this.translate(frame); - } - - if (AAcount === undefined) { - return this.translate(frame + ((AAoffset | 0) * 3)); - } - - return this.translate(frame + ((AAoffset | 0) * 3), (AAcount * 3) | 0); - - }; - - Seq.prototype.mapSequence = function(seq, offset) { - - if (!(seq instanceof Seq)) { - throw new Error('.mapSequence requires valid Seq'); - } - - return new MatchMap(seq, this, offset); - - }; - - /* MatchResult */ - - function MatchResult(matchMap, pos, score) { - - Object.defineProperty(this, '__matchMap', {value: matchMap}); - - this.position = pos; - this.score = score; - this.__align = null; - - }; - - MatchResult.prototype.alignment = function() { - - if (!this.__align) { - var map = this.__matchMap; - if (this.position < 0) { - this.__align = (new Nt.Seq()) - .read('-') - .repeat(-this.position) - .polymerize(map.__searchSpace.replicate(0, map.__query.__length + this.position)); - } else if (this.position + map.__query.__length > map.__searchSpace.__length) { - this.__align = map.__searchSpace - .replicate(this.position) - .polymerize((new Nt.Seq()).read('-').repeat(map.__searchSpace.__length - this.position)); - } else { - this.__align = map.__searchSpace.replicate(this.position, map.__query.__length); - } - } - return this.__align; - - }; - - MatchResult.prototype.alignmentMask = function() { - - return this.__matchMap.__query.mask(this.alignment()); - - }; - - MatchResult.prototype.alignmentCover = function() { - - return this.__matchMap.__query.cover(this.alignment()); - - }; - - /* MatchMap */ - - function MatchMap(query, searchSpace, offset) { - - if (!(query instanceof Seq) || !(searchSpace instanceof Seq)) { - throw new Error('MatchMap requires valid Seq'); - } - - this.__query = query.replicate(); - this.__searchSpace = searchSpace.replicate(); - this.__results = []; - this.__orderedResults = []; - this.__matchFrequencyData = null; - this.__initialized = false; - - this.__offset = Math.max(0, offset | 0); - this.__positionAdjustment = this.__offset - (this.__query.size() - 1); - - this.__debug = { - searchTime: null, - prepareTime: null, - sortTime: null - }; - - }; - - MatchMap.prototype.initialize = function(results) { - - this.__orderedResults = []; - this.__matchFrequencyData = null; - - this.__initialized = true; - - var t = (new Date).valueOf(); - - if (!results) { - - var dataArray = new Uint32Array(this.__execute(this.__query.__buffer, this.__searchSpace.__buffer)); - - this.__debug.searchTime = (-t) + (t = (new Date).valueOf()); - - var queryLen = this.__query.size(); - var searchLen = this.__searchSpace.size(); - var resultsLen = ((8 - (queryLen % 8)) % 8) + 1; - var totalLen = searchLen + queryLen - 1; - results = [].slice.call(dataArray, resultsLen, resultsLen + totalLen); - - } - - this.__results = results; - this.__debug.prepareTime = (-t) + (t = (new Date).valueOf()); - - return this; - - }; - - MatchMap.prototype.sort = function() { - - if (!this.__initialized) { - throw new Error('MatchMap must be initialized first.'); - } - - var t = new Date().valueOf(); - - if (this.__debug.sortTime !== null) { - return this; - } - - var adjust = this.__positionAdjustment; - this.__orderedResults = this.__results - .map(function(v, i) { return {n: i + adjust, s: v}; }) - .sort(function(a, b) { return b.s - a.s; }); - this.__debug.sortTime = new Date().valueOf() - t; - return this; - - }; - - MatchMap.prototype.__calculate_p_match = function(query, searchSpace) { - - /* - The approximate probability that two randomly chosen nucleotides - from QUERY and SEARCH match each other - */ - - var queryContent = query.fractionalContentATGC(); - var searchSpaceContent = searchSpace.fractionalContentATGC(); - - return (queryContent['A'] * searchSpaceContent['A']) + - (queryContent['T'] * searchSpaceContent['T']) + - (queryContent['G'] * searchSpaceContent['G']) + - (queryContent['C'] * searchSpaceContent['C']); - - }; - - MatchMap.prototype.results = function(offset, count) { - - if (!this.__initialized) { - throw new Error('MatchMap must be initialized first.'); - } - - if (offset === undefined) { - return this.__results.slice(); - } - - if (count === undefined) { - return this.__results.slice(offset | 0); - } - - return this.__results.slice(offset | 0, count | 0); - - }; - - MatchMap.prototype.best = function() { - - if (!this.__initialized) { - throw new Error('MatchMap must be initialized first.'); - } - - if (!this.__orderedResults.length) { - throw new Error('MatchMap must be sorted first.'); - } - - var result = this.__orderedResults[0]; - return new MatchResult(this, result.n, result.s); - - }; - - MatchMap.prototype.top = function(n) { - - if (!this.__initialized) { - throw new Error('MatchMap must be initialized first.'); - } - - if (!this.__orderedResults.length) { - throw new Error('MatchMap must be sorted first.'); - } - - var self = this; - - return this.__orderedResults.slice(0, n).map(function(result) { - return new MatchResult(self, result.n, result.s); - }); - - }; - - MatchMap.prototype.bottom = function(n) { - - if (!this.__initialized) { - throw new Error('MatchMap must be initialized first.'); - } - - if (!this.__orderedResults.length) { - throw new Error('MatchMap must be sorted first.'); - } - - var self = this; - - var adjust = this.__positionAdjustment; - var len = this.__orderedResults.length; - return this.__orderedResults.slice(this.__orderedResults.length - n, n).map(function(result) { - return new MatchResult(self, result.n, result.s); - }); - - }; - - /* Can be optimized with binary splitting */ - - MatchMap.prototype.matchFrequencyData = function() { - - if (!this.__initialized) { - throw new Error('MatchMap must be initialized first.'); - } - - if (!this.__orderedResults.length) { - throw new Error('MatchMap must be sorted first.'); - } - - if (this.__matchFrequencyData) { - return this.__matchFrequencyData; - } - - var ordered = this.__orderedResults; - var matchFrequencyData = makeArray(this.__query.size() + 1); - - var maxMatch = this.__query.size(); - var lastIndex = 0; - var num; - - for (var i = 0, len = ordered.length; i < len; i++) { - num = ordered[i].s; - if (num < maxMatch) { - matchFrequencyData[maxMatch] = i - lastIndex; - lastIndex = i; - maxMatch = num; - } - if (num === 0) { - matchFrequencyData[0] = len - i; - break; - } - } - - return (this.__matchFrequencyData = matchFrequencyData); - - }; - - MatchMap.prototype.__countMatches = function(int, bitCount) { - - int |= int >>> 1; - int |= int >>> 2; - int &= 0x11111111; - int |= int >>> 3; - int |= int >>> 6; - return bitCount[((int >>> 12) & 0xF0) | (int & 0xF)]; - - }; - - MatchMap.prototype.__execute = function(queryBuffer, searchSpaceBuffer) { - - var queryInts, spaceInts, queryIntsLength, spaceIntsLength, - arrLen, mapBuffer, mapArray, - A, B, A1, A2, T, cur, pos, move, i, k, - adjustNeg, adjustPos, - fnCountMatches, bitCount; - - queryInts = new Uint32Array(queryBuffer, 4); - spaceInts = new Uint32Array(searchSpaceBuffer, 4); - - fnCountMatches = this.__countMatches; - bitCount = __bitCount; - - queryIntsLength = queryInts.length|0; - spaceIntsLength = spaceInts.length|0; - - arrLen = (queryIntsLength + spaceIntsLength) << 3; - mapBuffer = new ArrayBuffer(4 * arrLen); - mapArray = new Uint32Array(mapBuffer); - - for (k = 0|0; k < queryIntsLength; k++) { - - A = queryInts[k]; - cur = (queryIntsLength - k) << 3; - - for (i = 0|0; i < spaceIntsLength; i++) { - (T = A & spaceInts[i]) && (mapArray[(i << 3) + cur] += fnCountMatches(T, bitCount)); - } - - A1 = A >>> 4; - A2 = A << 4; - - adjustNeg = cur - 1; - adjustPos = cur + 1; - - while(A1 || A2) { - - for (i = 0|0; i < spaceIntsLength; i++) { - B = spaceInts[i]; - pos = (i << 3); - - (T = A1 & B) && (mapArray[pos + adjustNeg] += fnCountMatches(T, bitCount)); - (T = A2 & B) && (mapArray[pos + adjustPos] += fnCountMatches(T, bitCount)); - } - - A1 >>>= 4; - A2 <<= 4; - - --adjustNeg; - ++adjustPos; - - } - - } - - return mapBuffer; - - }; - - return { - Seq: Seq, - MatchMap: MatchMap - }; - -}(); From c7dec16c5fb67ec630482a2d715fd766eba695ad Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Wed, 19 Dec 2018 13:33:36 -0500 Subject: [PATCH 009/122] Added Parse time reporting to all file parsers --- components/files.html | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/files.html b/components/files.html index 6bdfb4b9..3ce6c8f4 100644 --- a/components/files.html +++ b/components/files.html @@ -540,6 +540,7 @@ if(file.format === 'fasta'){ message(`Parsing ${filename} as FASTA...`); + var start = Date.now(); anySequences = true; var newNodes = 0; var seqs = app.parseFASTA(file.contents); @@ -550,14 +551,16 @@ node.id = filterXSS(node.id); node.seq = filterXSS(node.seq); node.origin = [filename]; - n += app.addNode(node); + newNodes += app.addNode(node); } + console.log('FASTA Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${newNodes} New, ${seqs.length} Total Nodes from FASTA.`); if(fileNum === session.files.length - 1) nextStuff(); } else if(file.format === 'link'){ message(`Parsing ${filename} as Link List...`); + var start = Date.now(); var l = 0; function forEachLink(link){ @@ -607,6 +610,7 @@ origin: [filename] }); }); + console.log('Link Excel Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${n} New, ${t} Total Nodes from Link Excel Table.`); if(fileNum === session.files.length - 1) nextStuff(); @@ -639,6 +643,7 @@ origin: [filename] }); }); + console.log('Link CSV Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${n} New, ${t} Total Nodes from Link CSV.`); if(fileNum === session.files.length - 1) nextStuff(); } @@ -647,7 +652,7 @@ } else if(file.format === 'node'){ message(`Parsing ${filename} as Node List...`); - + var start = Date.now(); if(file.field2 !== 'None') anySequences = true; var m = 0, n = 0; @@ -669,6 +674,7 @@ node['origin'] = [filename]; m += app.addNode(node); }); + console.log('Node Excel Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${m} New, ${n} Total Nodes from Node Excel Table.`); if(fileNum === session.files.length - 1) nextStuff(); @@ -695,6 +701,7 @@ m += app.addNode(node); }, complete: function(){ + console.log('Node CSV Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${m} New, ${n} Total Nodes from Node CSV.`); if(fileNum === session.files.length - 1) nextStuff(); } @@ -704,6 +711,7 @@ } else { //Distance Matrix message(`Parsing ${filename} as Distance Matrix...`); + var start = Date.now(); var defaultMetric = session.state.linkSortVariable; if(extension == 'xls' || extension == 'xlsx'){ @@ -742,6 +750,7 @@ }); } }); + console.log('Distance Matrix Excel Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${nn} New, ${data.length-1} Total Nodes from Excel Distance Matrix.`); message(` - Parsed ${nl} New, ${((data.length-1)**2-(data.length-1))/2} Total Links from Excel Distance Matrix.`); if(fileNum === session.files.length - 1) nextStuff(); @@ -786,6 +795,7 @@ }); } }); + console.log('Distance Matrix CSV Parse time:', ((Date.now()-start)/1000).toLocaleString(), 's'); message(` - Parsed ${nn} New, ${results.data.length - 1} Total Nodes from Distance Matrix.`); message(` - Parsed ${nl} New, ${((results.data.length-1)**2 - (results.data.length-1))/2} Total Links from Distance Matrix.`); if(fileNum === session.files.length - 1) nextStuff(); From 2a59018e0e5411808914bcc65ecaf97fcd4c07a7 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Wed, 19 Dec 2018 15:04:02 -0500 Subject: [PATCH 010/122] Switched from d3Sankey to Plotly Sankey --- components/flow_diagram.html | 132 ++++++++++++++--------------------- index.html | 1 - package.json | 1 - stylesheets/main.css | 1 + 4 files changed, 54 insertions(+), 81 deletions(-) diff --git a/components/flow_diagram.html b/components/flow_diagram.html index 98edd39c..b4bac027 100644 --- a/components/flow_diagram.html +++ b/components/flow_diagram.html @@ -1,4 +1,4 @@ - +
@@ -74,35 +69,43 @@ let width = $('#flow').parent().width() - 40, height = $('#flow').parent().height() - 60; - let nodes = app.getVisibleNodes(), labels = []; + let nodes = app.getVisibleNodes(); let onlyUnique = (value, index, self) => self.indexOf(value) === index; - let source_variable = $('#flow-source-variable').val(); - let source_values = nodes.map(n => n[source_variable]+'').filter(onlyUnique); - - source_values.forEach(sv => labels.push(sv)); + let order = []; + $($('#flow-variables').find('select')).each(function(i){ order.push($(this).val()); }); - let target_variable = $('#flow-target-variable').val(); - let target_values = nodes.map(n => n[target_variable]+'').filter(onlyUnique); - - target_values.forEach(tv => labels.push(tv)); + let source_values = [], target_values = [], all_values = [], labels = []; + order.forEach((variable, i) => { + let values = nodes.map(n => n[variable]+'').filter(onlyUnique); + values.forEach(value => all_values.push(variable + '-' + value + '-' + i)); + if(i < order.length-1){ + values.forEach(value => source_values.push(variable + '-' + value + '-' + i)); + } + if(i > 0){ + values.forEach(value => target_values.push(variable + '-' + value + '-' + i)); + } + values.forEach(value => labels.push(app.titleize(variable + ' ' + value))); + }); - let target_list = {}; + let link_matrix = {}, target_list = {}; target_values.forEach(target => target_list[target] = 0); - - let link_matrix = {}; - source_values.forEach(source => link_matrix[source] = Object.assign({}, target_list)); - nodes.forEach(n => link_matrix[n[source_variable]][n[target_variable]]++); + + for(let i = 0; i < order.length-1; i++){ + let source_variable = order[i]; + let target_variable = order[i+1]; + nodes.forEach(n => link_matrix[source_variable + '-' + n[source_variable] + '-' + i][target_variable + '-' + n[target_variable] + '-' + (i+1)]++); + } let source = [], target = [], value = []; - source_values.forEach((s, i) => { - target_values.forEach((t, j) => { + source_values.forEach(s => { + target_values.forEach(t => { if(link_matrix[s][t] > 0){ - source.push(i); - target.push(source_values.length + j); + source.push(all_values.indexOf(s)); + target.push(all_values.indexOf(t)); value.push(link_matrix[s][t]); } }); @@ -120,7 +123,7 @@ color: "black", width: 0.5 }, - label: labels, + label: labels.map(app.titleize), color: 'blue' }, link: { source, target, value } @@ -146,15 +149,18 @@ } }); - + $('#flow-add-variable').on('click', function(){ + $('#flow-variables').append(`
  • `); - $('#flow-source-variable') - .html(session.data.nodeFields.map((field, i) => `${app.titleize(field)}`)) - .change(drawFlowDiagram); + sortable('#flow-variables')[0].addEventListener('sortupdate', drawFlowDiagram); - $('#flow-target-variable') - .html(session.data.nodeFields.map((field, i) => `${app.titleize(field)}`)) - .change(drawFlowDiagram); + $('.flow-selector').on('change', drawFlowDiagram); + + $('.flow-remove').on('click', function(){ + $(this).parent().slideUp().remove(); + drawFlowDiagram(); + }); + }).trigger('click').trigger('click'); $('#flow-export').click(function(){ let network = $('#flow')[0]; @@ -173,22 +179,11 @@ layout.on('stateChanged', drawFlowDiagram); $(window) - .on('node-selected', function(){ - if($('#flow-source-variable').val() === 'selected' || $('#flow-target-variable').val() === 'selected'){ - drawFlowDiagram(); - } - }) - .on('link-threshold-change', function(){ - let affected = ['degree', 'cluster']; - if(affected.includes($('#flow-source-variable').val()) || affected.includes($('#flow-target-variable').val())){ - drawFlowDiagram(); - } - }) + .on('node-selected', drawFlowDiagram) + .on('link-threshold-change', drawFlowDiagram) .on('node-visibility', drawFlowDiagram) .on('background-color-change', function(){ $('#flow-diagram').parent().css('background-color', session.style.widgets['background-color']); }); - - drawFlowDiagram(); })(); diff --git a/index.html b/index.html index a32501c9..d1d0a269 100644 --- a/index.html +++ b/index.html @@ -463,6 +463,7 @@ + diff --git a/package-lock.json b/package-lock.json index 3c1fc1d0..023b2427 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2731,6 +2731,11 @@ "css-line-break": "1.0.1" } }, + "html5sortable": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/html5sortable/-/html5sortable-0.9.8.tgz", + "integrity": "sha512-QodBiv8LdTZHot3EMzNHTeKn/nHm66BlvmcFvMFMPVm4mYN5S0uKvDxFnzRltFvrIjvps7OVRrxBJQX8aLnxWg==" + }, "http-errors": { "version": "1.6.3", "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", diff --git a/package.json b/package.json index db57464e..328042c0 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "fileto": "0.0.1", "golden-layout": "^1.5.9", "html2canvas": "^1.0.0-alpha.12", + "html5sortable": "^0.9.8", "jquery": "^3.3.1", "jszip": "^3.1.5", "leaflet": "^1.3.3", diff --git a/stylesheets/main.css b/stylesheets/main.css index de6376cf..49ed8585 100644 --- a/stylesheets/main.css +++ b/stylesheets/main.css @@ -338,6 +338,16 @@ a.btn, button.btn, .btn-group{ margin-top: 50px; height: calc(100% - 65px); } +#flow-variables{ + padding-left: 0; +} +.flow-items{ + list-style-type: none; +} +.flow-selector{ + width: calc(100% - 42px); + margin: 5px; +} /* MAP */ #map{ From 6e7ab7608b5cace9470c7dcf5d77ee4919ea2640 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Thu, 20 Dec 2018 07:37:35 -0500 Subject: [PATCH 012/122] Added ability to show either nodes or links in Flow Diagram --- components/flow_diagram.html | 49 ++++++++++++++++++++++++++++-------- scripts/common.js | 3 +-- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/components/flow_diagram.html b/components/flow_diagram.html index 8c5b0b74..be659c00 100644 --- a/components/flow_diagram.html +++ b/components/flow_diagram.html @@ -17,6 +17,19 @@
    +
    + +
    +
    + + +
    +
    +
    Variables
    @@ -69,7 +82,12 @@ let width = $('#flow').parent().width() - 40, height = $('#flow').parent().height() - 60; - let nodes = app.getVisibleNodes(); + let data; + if(session.style.widgets['flow-showNodes']){ + data = app.getVisibleNodes(); + } else { + data = app.getVisibleLinks(); + } let onlyUnique = (value, index, self) => self.indexOf(value) === index; @@ -78,7 +96,7 @@ let source_values = [], target_values = [], all_values = [], labels = []; order.forEach((variable, i) => { - let values = nodes.map(n => n[variable]+'').filter(onlyUnique); + let values = data.map(n => n[variable]+'').filter(onlyUnique); values.forEach(value => all_values.push(variable + '-' + value + '-' + i)); if(i < order.length-1){ values.forEach(value => source_values.push(variable + '-' + value + '-' + i)); @@ -96,7 +114,7 @@ for(let i = 0; i < order.length-1; i++){ let source_variable = order[i]; let target_variable = order[i+1]; - nodes.forEach(n => link_matrix[source_variable + '-' + n[source_variable] + '-' + i][target_variable + '-' + n[target_variable] + '-' + (i+1)]++); + data.forEach(n => link_matrix[source_variable + '-' + n[source_variable] + '-' + i][target_variable + '-' + n[target_variable] + '-' + (i+1)]++); } let source = [], target = [], value = []; @@ -111,25 +129,23 @@ }); }); - let data = { - type: "sankey", + Plotly.react('flow', [{ + type: 'sankey', showLegend: false, - orientation: "h", + orientation: 'h', arrangement: 'perpendicular', node: { pad: 15, thickness: 30, line: { - color: "black", + color: 'black', width: 0.5 }, label: labels.map(app.titleize), color: 'blue' }, link: { source, target, value } - }; - - Plotly.react('flow', [data], { + }], { width: width, height: height }, { @@ -149,8 +165,19 @@ } }); + $('#flow-showNodes').parent().on('click', function(){ + session.style.widgets['flow-showNodes'] = true; + $('.flow-selector').html(session.data.nodeFields.map(v => '').join('')); + }); + + $('#flow-showLinks').parent().on('click', function(){ + session.style.widgets['flow-showNodes'] = false; + $('.flow-selector').html(session.data.linkFields.map(v => '').join('')); + }); + $('#flow-add-variable').on('click', function(){ - $('#flow-variables').append(`
  • `); + let fields = session.style.widgets['flow-showNodes'] ? session.data.nodeFields : session.data.linkFields; + $('#flow-variables').append(`
  • `); sortable('#flow-variables')[0].addEventListener('sortupdate', drawFlowDiagram); diff --git a/scripts/common.js b/scripts/common.js index 1a417530..464cd39d 100644 --- a/scripts/common.js +++ b/scripts/common.js @@ -28,8 +28,7 @@ app.defaultWidgets = { 'bubble-x': 'None', 'bubble-y': 'None', 'bubble-size': 5, - 'flow-source-variable': 'selected', - 'flow-target-variable': 'cluster', + 'flow-showNodes': 'selected', 'heatmap-metric': 'tn93', 'heatmap-invertX': false, 'heatmap-invertY': false, From fcd94cf1383204d24c9b757b321a4ec9f50a5954 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Thu, 20 Dec 2018 07:58:29 -0500 Subject: [PATCH 013/122] Added Arrangement control to Flow Diagram Not that important or useful, but... --- components/flow_diagram.html | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/components/flow_diagram.html b/components/flow_diagram.html index be659c00..1c9fc662 100644 --- a/components/flow_diagram.html +++ b/components/flow_diagram.html @@ -37,6 +37,17 @@
    +
    +
    Arrangement
    +
    + +
    +
    @@ -133,7 +144,7 @@ type: 'sankey', showLegend: false, orientation: 'h', - arrangement: 'perpendicular', + arrangement: session.style.widgets['flow-arrangement'], node: { pad: 15, thickness: 30, @@ -189,6 +200,11 @@ }); }).trigger('click').trigger('click'); + $('#flow-arrangement').on('change', function(e){ + session.style.widgets['flow-arrangement'] = e.target.value; + drawFlowDiagram(); + }); + $('#flow-export').click(function(){ let network = $('#flow')[0]; let content = app.unparseSVG(network); From 3f28fe4807561e3e0f5f68165ef995c5a9357010 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Thu, 20 Dec 2018 07:58:50 -0500 Subject: [PATCH 014/122] Set Flow Diagram color based on dataset of origin --- components/flow_diagram.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/flow_diagram.html b/components/flow_diagram.html index 1c9fc662..bd965332 100644 --- a/components/flow_diagram.html +++ b/components/flow_diagram.html @@ -153,7 +153,7 @@ width: 0.5 }, label: labels.map(app.titleize), - color: 'blue' + color: session.style.widgets['flow-showNodes'] ? session.style.widgets['node-color'] : session.style.widgets['link-color'] }, link: { source, target, value } }], { From 50901b862fdb507e2a045c26b56e1c1c63b548b5 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Thu, 20 Dec 2018 08:04:58 -0500 Subject: [PATCH 015/122] Fixed Flow Exporting --- components/flow_diagram.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/flow_diagram.html b/components/flow_diagram.html index bd965332..bee2e525 100644 --- a/components/flow_diagram.html +++ b/components/flow_diagram.html @@ -205,8 +205,8 @@ drawFlowDiagram(); }); - $('#flow-export').click(function(){ - let network = $('#flow')[0]; + $('#flow-export').on('click', function(){ + let network = $('#flow .main-svg').get(0); let content = app.unparseSVG(network); let filetype = $('#export-flow-file-type').val(); if(filetype === 'svg'){ From b28b2cbeeb4301b7bcd4a9ee9d95540881831198 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Fri, 21 Dec 2018 10:38:33 -0500 Subject: [PATCH 016/122] Fixed long-standing map resizing bug --- components/geo_map.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/geo_map.html b/components/geo_map.html index 691e4352..d1010b0b 100644 --- a/components/geo_map.html +++ b/components/geo_map.html @@ -770,6 +770,12 @@ .on('node-color-change', drawNodes) .on('link-color-change link-threshold-change link_visibility', drawLinks); + layout.on('stateChanged', function(){ + setTimeout(function(){ + map.invalidateSize(); + }, 80); + }); + setTimeout(function(){ matchCoordinates(); drawNodes(); From fef22102d1fb59e0c601ad64c1975565819e14c7 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Fri, 21 Dec 2018 10:40:47 -0500 Subject: [PATCH 017/122] Got Layout loading working Added a MicroReact Mode, resolving #46 --- components/files.html | 10 +++------- index.html | 9 ++++++++- scripts/common.js | 10 +++++++--- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/components/files.html b/components/files.html index 3ce6c8f4..e0a8ed89 100644 --- a/components/files.html +++ b/components/files.html @@ -917,14 +917,10 @@ $('#network-statistics').fadeIn(); session.meta.loadTime = Date.now() - session.meta.startTime; if(oldSession){ - app.loadLayout(session.layout, true); + layout.root.contentItems[0].remove(); + setTimeout(function(){app.loadLayout(session.layout)}, 80); } else { - app.loadLayout({ - type: 'stack', - content: [{ - type: $('#default-View').val() - }] - }, true); + app.launchView($('#default-View').val()); } if(localStorage.getItem('stash-auto') === 'true'){ temp.autostash = { diff --git a/index.html b/index.html index d1d0a269..0fb2d47e 100644 --- a/index.html +++ b/index.html @@ -72,8 +72,9 @@ @@ -879,6 +880,12 @@ } }); + $('#MicroReactTab').on('click', function(){ + var l = {"type":"column","content":[{"type":"row","content":[{"type":"stack","content":[{"type":"geo_map"}]},{"type":"stack","content":[{"type":"phylogenetic_tree"}]}]},{"type":"stack","content":[{"type":"timeline"}]}]}; + app.loadLayout(l); + setTimeout(function(){ app.loadLayout(l); }, 80); + }) + if(window.navigator.onLine){ $('#HelpTab') .removeClass('viewbutton') diff --git a/scripts/common.js b/scripts/common.js index 464cd39d..3220bb41 100644 --- a/scripts/common.js +++ b/scripts/common.js @@ -807,10 +807,14 @@ app.cacheLayout = function(contentItem){ return {'type': contentItem.componentName}; }; -app.loadLayout = function(component, first){ - if(first) app.lastItem = layout.root.contentItems[0]; +app.loadLayout = function(component, parent){ + if(!parent){ + parent = layout.root; + try { parent.contentItems[0].remove(); } catch(e){} + } if(['stack', 'row', 'column'].includes(component.type)){ - component.content.map(app.loadLayout); + parent.addChild({type: component.type}); + component.content.forEach(function(c){ app.loadLayout(c, _.last(parent.contentItems)); }); } else { app.launchView(component.type); } From 98e316b582f74e849e2c03064716eec33be8ed31 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Fri, 21 Dec 2018 16:04:16 -0500 Subject: [PATCH 018/122] Hotfix alignment distance computation bug --- scripts/compute-links.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/compute-links.js b/scripts/compute-links.js index 8f8b63e1..357a99f9 100644 --- a/scripts/compute-links.js +++ b/scripts/compute-links.js @@ -5,7 +5,7 @@ function snps(s1, s2){ var i = Math.min(s1.length, s2.length); var sum = 0; while(--i >= 0){ - if(s1[i] !== s2[i] & s1[i] !== 17 & s2[i] !== 17) sum++; + if(s1[i] !== s2[i] & s1[i] !== '-' & s2[i] !== '-') sum++; } return sum; } @@ -23,8 +23,8 @@ onmessage = function(e){ target: target.id, origin: ['Genetic Distance'] }; - if(metrics.includes('tn93')) link.tn93 = tn93.onInts(source['_seqInt'], target['_seqInt'], 'AVERAGE'); - if(metrics.includes('snps')) link.snps = snps(source['_seqInt'], target['_seqInt']); + if(metrics.includes('tn93')) link.tn93 = tn93(source['seq'], target['seq'], 'AVERAGE'); + if(metrics.includes('snps')) link.snps = snps(source['seq'], target['seq']); output[t++] = link; } } From bf703afff1719d8767853f94c40e11287dc9f915 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Fri, 21 Dec 2018 16:12:51 -0500 Subject: [PATCH 019/122] Update Cache --- microbetrace.appcache | 6 ++---- sw.js | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/microbetrace.appcache b/microbetrace.appcache index c486806f..99425862 100644 --- a/microbetrace.appcache +++ b/microbetrace.appcache @@ -1,5 +1,5 @@ CACHE MANIFEST -# 2018-12-18 +# 2018-12-21 CACHE: index.html @@ -20,7 +20,6 @@ components/sequences.html components/table.html components/timeline.html components/waterfall.html -scripts/align-nbeam.js scripts/align-sw.js scripts/common.js scripts/compute-consensus-distances.js @@ -49,12 +48,12 @@ node_modules/tn93/dist/tn93.min.js node_modules/d3/dist/d3.min.js node_modules/d3-force-attract/dist/d3-force-attract.min.js node_modules/d3-symbol-extra/build/d3-symbol-extra.min.js +node_modules/html5sortable/dist/html5sortable.min.js node_modules/plotly.js/dist/plotly.min.js node_modules/tabulator-tables/dist/js/tabulator.min.js node_modules/3d-force-graph/dist/3d-force-graph.min.js node_modules/leaflet/dist/leaflet.js node_modules/alignment-viewer/dist/alignment-viewer.min.js -node_modules/d3-sankey/build/d3-sankey.min.js node_modules/marked/marked.min.js node_modules/jszip/dist/jszip.min.js node_modules/localforage/dist/localforage.min.js @@ -65,7 +64,6 @@ node_modules/neighborjoining/dist/neighborjoining.min.js vendor/bootstrap-filestyle.min.js vendor/d3.v3.min.js vendor/FileSaver.min.js -vendor/ntseq.js vendor/phylotree.js vendor/shpwrite.js stylesheets/main.css diff --git a/sw.js b/sw.js index abb9e2ab..ac36534c 100644 --- a/sw.js +++ b/sw.js @@ -1,4 +1,4 @@ -var CACHE = 'MicrobeTraceD2018-12-18'; +var CACHE = 'MicrobeTraceD2018-12-21'; self.addEventListener('install', function(event) { event.waitUntil( @@ -21,7 +21,6 @@ self.addEventListener('install', function(event) { 'components/table.html', 'components/timeline.html', 'components/waterfall.html', - 'scripts/align-nbeam.js', 'scripts/align-sw.js', 'scripts/common.js', 'scripts/compute-consensus-distances.js', @@ -50,12 +49,12 @@ self.addEventListener('install', function(event) { 'node_modules/d3/dist/d3.min.js', 'node_modules/d3-force-attract/dist/d3-force-attract.min.js', 'node_modules/d3-symbol-extra/build/d3-symbol-extra.min.js', + 'node_modules/html5sortable/dist/html5sortable.min.js', 'node_modules/plotly.js/dist/plotly.min.js', 'node_modules/tabulator-tables/dist/js/tabulator.min.js', 'node_modules/3d-force-graph/dist/3d-force-graph.min.js', 'node_modules/leaflet/dist/leaflet.js', 'node_modules/alignment-viewer/dist/alignment-viewer.min.js', - 'node_modules/d3-sankey/build/d3-sankey.min.js', 'node_modules/marked/marked.min.js', 'node_modules/jszip/dist/jszip.min.js', 'node_modules/localforage/dist/localforage.min.js', @@ -65,7 +64,6 @@ self.addEventListener('install', function(event) { 'vendor/bootstrap-filestyle.min.js', 'vendor/d3.v3.min.js', 'vendor/FileSaver.min.js', - 'vendor/ntseq.js', 'vendor/phylotree.js', 'vendor/shpwrite.js', 'stylesheets/main.css', From ac5d70ebd33ab1fd3c58eb612ec88f86141b3591 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Wed, 2 Jan 2019 13:15:13 -0500 Subject: [PATCH 020/122] Sped up Flow Diagram Data munger a bit --- components/flow_diagram.html | 52 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/components/flow_diagram.html b/components/flow_diagram.html index bee2e525..7bbf292f 100644 --- a/components/flow_diagram.html +++ b/components/flow_diagram.html @@ -100,45 +100,57 @@ data = app.getVisibleLinks(); } - let onlyUnique = (value, index, self) => self.indexOf(value) === index; - let order = []; $($('#flow-variables').find('select')).each(function(i){ order.push($(this).val()); }); - - let source_values = [], target_values = [], all_values = [], labels = []; - order.forEach((variable, i) => { - let values = data.map(n => n[variable]+'').filter(onlyUnique); - values.forEach(value => all_values.push(variable + '-' + value + '-' + i)); - if(i < order.length-1){ - values.forEach(value => source_values.push(variable + '-' + value + '-' + i)); + let variables = order.length; + + let values = [], source_values = [], target_values = [], all_values = [], labels = []; + for(let i = 0; i < variables; i++){ + variable = order[i]; + let n = data.length; + for(let j = 0; j < n; j++){ + let value = data[j][variable]+''; + if(!values.includes(value)) values.push(value); } - if(i > 0){ - values.forEach(value => target_values.push(variable + '-' + value + '-' + i)); + n = values.length; + for(let j = 0; j < n; j++){ + labels.push(app.titleize(variable + ' ' + values[j])); + let value = variable + '-' + values[j] + '-' + i; + if(i < variables-1) source_values.push(value); + if(i > 0) target_values.push(value); + all_values.push(value); } - values.forEach(value => labels.push(app.titleize(variable + ' ' + value))); - }); + } let link_matrix = {}, target_list = {}; target_values.forEach(target => target_list[target] = 0); source_values.forEach(source => link_matrix[source] = Object.assign({}, target_list)); - for(let i = 0; i < order.length-1; i++){ + let m = order.length-1, n = data.length; + for(let i = 0; i < m; i++){ let source_variable = order[i]; let target_variable = order[i+1]; - data.forEach(n => link_matrix[source_variable + '-' + n[source_variable] + '-' + i][target_variable + '-' + n[target_variable] + '-' + (i+1)]++); + for(let j = 0; j < n; j++){ + let point = data[j]; + link_matrix[source_variable + '-' + point[source_variable] + '-' + i][target_variable + '-' + point[target_variable] + '-' + (i+1)]++; + } } let source = [], target = [], value = []; - source_values.forEach(s => { - target_values.forEach(t => { + m = source_values.length, n = target_values.length; + for(let i = 0; i < m; i++){ + let s = source_values[i]; + let index = all_values.indexOf(s); + for(let j = 0; j < n; j++){ + let t = target_values[j]; if(link_matrix[s][t] > 0){ - source.push(all_values.indexOf(s)); + source.push(index); target.push(all_values.indexOf(t)); value.push(link_matrix[s][t]); } - }); - }); + } + } Plotly.react('flow', [{ type: 'sankey', From 5684460f0baa9aded4cf2cd9247819d3118599c9 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Fri, 4 Jan 2019 12:18:33 -0500 Subject: [PATCH 021/122] Fixed an old bug in the cacheing script --- sw.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sw.sh b/sw.sh index a1608a78..a3e39d51 100755 --- a/sw.sh +++ b/sw.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ls components/ | sed -e 's/^/components\//' | sed "s/.*/ '&',/" >> temp @@ -43,7 +43,7 @@ self.addEventListener('fetch', function(event) { // Open the cache where the assets were stored and search for the requested // resource. Notice that in case of no matching, the promise still resolves -// but it does with `undefined` as value. +// but it does with \`undefined\` as value. function fromCache(request){ return caches.open(CACHE).then(function(cache){ return cache.match(request).then(function(matching){ From 44e22dff51f2db3514195d3193ff7376feb7a4a6 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Fri, 4 Jan 2019 13:02:51 -0500 Subject: [PATCH 022/122] Turned the ie-warning into a modal --- components/files.html | 7 ------- index.html | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/components/files.html b/components/files.html index e0a8ed89..a4a9ad3b 100644 --- a/components/files.html +++ b/components/files.html @@ -2,13 +2,6 @@

    Drag-and-Drop Files here, or click "Add File(s)" to load data.

    -
    - This page does not support Internet Explorer. To use MicrobeTrace, please switch to one of the following browsers:
    - Chrome / - Edge / - Safari / - Firefox -
    + +