isotopic-distribution
Advanced tools
Comparing version 0.8.0 to 0.9.1
{ | ||
"name": "isotopic-distribution", | ||
"version": "0.8.0", | ||
"version": "0.9.1", | ||
"description": "Calculate the isotopic distribution of a molecular formula", | ||
@@ -21,7 +21,7 @@ "main": "src/index.js", | ||
"dependencies": { | ||
"chemical-elements": "^0.7.0", | ||
"mf-parser": "^0.8.0", | ||
"mf-utilities": "^0.8.0", | ||
"chemical-elements": "^0.9.1", | ||
"mf-parser": "^0.9.1", | ||
"mf-utilities": "^0.9.1", | ||
"spectrum-generator": "^1.1.0" | ||
} | ||
} |
@@ -6,14 +6,14 @@ 'use strict'; | ||
describe('test distribution append', () => { | ||
it('should append one distribution to another', () => { | ||
let dist1 = new Distribution(); | ||
dist1.push(1, 2); | ||
dist1.push(2, 3); | ||
let dist2 = new Distribution(); | ||
dist2.push(2, 4); | ||
dist2.push(3, 5); | ||
it('should append one distribution to another', () => { | ||
let dist1 = new Distribution(); | ||
dist1.push(1, 2); | ||
dist1.push(2, 3); | ||
let dist2 = new Distribution(); | ||
dist2.push(2, 4); | ||
dist2.push(3, 5); | ||
dist1.append(dist2); | ||
dist1.sortX(); | ||
expect(dist1.array).toEqual([{ x: 1, y: 2 }, { x: 2, y: 3 }, { x: 2, y: 4 }, { x: 3, y: 5 }]); | ||
}); | ||
dist1.append(dist2); | ||
dist1.sortX(); | ||
expect(dist1.array).toStrictEqual([{ x: 1, y: 2 }, { x: 2, y: 3 }, { x: 2, y: 4 }, { x: 3, y: 5 }]); | ||
}); | ||
}); |
@@ -6,75 +6,72 @@ 'use strict'; | ||
describe('test Distribution', () => { | ||
it('create array', () => { | ||
let array = new Distribution(); | ||
array.push(1, 2); | ||
array.push(2, 3); | ||
expect(array).toHaveLength(2); | ||
}); | ||
it('create array', () => { | ||
let array = new Distribution(); | ||
array.push(1, 2); | ||
array.push(2, 3); | ||
expect(array).toHaveLength(2); | ||
}); | ||
it('join array 0', () => { | ||
let array = new Distribution(); | ||
array.join(); | ||
expect(array.array).toStrictEqual([]); | ||
}); | ||
it('join array 0', () => { | ||
let array = new Distribution(); | ||
array.join(); | ||
expect(array.array).toEqual([]); | ||
}); | ||
it('join array 1', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.join(); | ||
expect(array.array).toStrictEqual([{ x: 1, y: 1 }]); | ||
}); | ||
it('join array 1', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.join(); | ||
expect(array.array).toEqual([{ x: 1, y: 1 }]); | ||
}); | ||
it('join array', () => { | ||
let array = new Distribution(); | ||
array.push(0, 0); | ||
array.push(1, 1); | ||
array.join(); | ||
expect(array.array).toStrictEqual([{ x: 0, y: 0 }, { x: 1, y: 1 }]); | ||
}); | ||
it('join array', () => { | ||
let array = new Distribution(); | ||
array.push(0, 0); | ||
array.push(1, 1); | ||
array.join(); | ||
expect(array.array).toEqual([{ x: 0, y: 0 }, { x: 1, y: 1 }]); | ||
}); | ||
it('really join array', () => { | ||
let array = new Distribution(); | ||
array.push(0, 0); | ||
array.push(1, 1); | ||
array.join(1); | ||
expect(array.array).toStrictEqual([{ x: 1, y: 1 }]); | ||
}); | ||
it('really join array', () => { | ||
let array = new Distribution(); | ||
array.push(0, 0); | ||
array.push(1, 1); | ||
array.join(1); | ||
expect(array.array).toEqual([{ x: 1, y: 1 }]); | ||
}); | ||
it('really join array shifted', () => { | ||
let array = new Distribution(); | ||
array.push(1, 0); | ||
array.push(2, 1); | ||
array.join(1); | ||
expect(array.array).toStrictEqual([{ x: 2, y: 1 }]); | ||
}); | ||
it('really join array shifted', () => { | ||
let array = new Distribution(); | ||
array.push(1, 0); | ||
array.push(2, 1); | ||
array.join(1); | ||
expect(array.array).toEqual([{ x: 2, y: 1 }]); | ||
}); | ||
it('really join array shifted weighted', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.push(2, 3); | ||
array.join(1); | ||
expect(array.array).toStrictEqual([{ x: 1.75, y: 4 }]); | ||
}); | ||
it('really join array shifted weighted', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.push(2, 3); | ||
array.join(1); | ||
expect(array.array).toEqual([{ x: 1.75, y: 4 }]); | ||
}); | ||
it('really join array shifted weighted 3', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.push(2, 3); | ||
array.push(2.25, 1); | ||
array.join(1); | ||
expect(array.array).toStrictEqual([{ x: 1.85, y: 5 }]); | ||
}); | ||
it('really join array shifted weighted 3', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.push(2, 3); | ||
array.push(2.25, 1); | ||
array.join(1); | ||
expect(array.array).toEqual([{ x: 1.85, y: 5 }]); | ||
}); | ||
it('really join array shifted weighted 4', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.push(2, 3); | ||
array.push(2.25, 1); | ||
array.push(5, 1); | ||
array.join(1); | ||
expect(array.array).toEqual([{ x: 1.85, y: 5 }, { x: 5, y: 1 }]); | ||
}); | ||
it('really join array shifted weighted 4', () => { | ||
let array = new Distribution(); | ||
array.push(1, 1); | ||
array.push(2, 3); | ||
array.push(2.25, 1); | ||
array.push(5, 1); | ||
array.join(1); | ||
expect(array.array).toStrictEqual([{ x: 1.85, y: 5 }, { x: 5, y: 1 }]); | ||
}); | ||
}); |
@@ -6,16 +6,14 @@ 'use strict'; | ||
describe('test isotopicDistribution', () => { | ||
it('create distribution of C1 and getGaussian', () => { | ||
let isotopicDistribution = new IsotopicDistribution('C', { fwhm: 0.1 }); | ||
let gaussian = isotopicDistribution.getGaussian({ | ||
from: 11.00, | ||
to: 13.00, | ||
}); | ||
expect(gaussian.x).toHaveLength(201); | ||
expect(Math.min(...gaussian.x)).toBe(11); | ||
expect(Math.max(...gaussian.x)).toBe(13); | ||
expect(Math.min(...gaussian.y)).toBe(0); | ||
expect(Math.max(...gaussian.y)).toBe(0.9893); | ||
it('create distribution of C1 and getGaussian', () => { | ||
let isotopicDistribution = new IsotopicDistribution('C', { fwhm: 0.1 }); | ||
let gaussian = isotopicDistribution.getGaussian({ | ||
from: 11.00, | ||
to: 13.00, | ||
}); | ||
expect(gaussian.x).toHaveLength(201); | ||
expect(Math.min(...gaussian.x)).toBe(11); | ||
expect(Math.max(...gaussian.x)).toBe(13); | ||
expect(Math.min(...gaussian.y)).toBe(0); | ||
expect(Math.max(...gaussian.y)).toBe(0.9893); | ||
}); | ||
}); |
@@ -6,3 +6,3 @@ 'use strict'; | ||
describe('test isotopicDistribution', () => { | ||
it.only('create distribution of CH0', () => { | ||
it('create distribution of CH0', () => { | ||
let isotopicDistribution = new IsotopicDistribution('CH0'); | ||
@@ -13,2 +13,14 @@ let distribution = isotopicDistribution.getDistribution(); | ||
it('create distribution of CN default res', () => { | ||
let isotopicDistribution = new IsotopicDistribution('CN'); | ||
let distribution = isotopicDistribution.getDistribution(); | ||
expect(distribution).toHaveLength(3); | ||
}); | ||
it('create distribution of CN high res', () => { | ||
let isotopicDistribution = new IsotopicDistribution('CN', { fwhm: 0 }); | ||
let distribution = isotopicDistribution.getDistribution(); | ||
expect(distribution).toHaveLength(4); | ||
}); | ||
it('create distribution of C1000', () => { | ||
@@ -87,4 +99,4 @@ let isotopicDistribution = new IsotopicDistribution('C1000'); | ||
expect(isotopicDistribution.confidence).toBeGreaterThan(0.99999); | ||
expect(xy.x[0]).toEqual(120); | ||
expect(xy.y[0]).toEqual(100); | ||
expect(xy.x[0]).toStrictEqual(120); | ||
expect(xy.y[0]).toStrictEqual(100); | ||
}); | ||
@@ -98,3 +110,3 @@ | ||
let element = distribution.array[25]; | ||
expect(element).toEqual({ x: 505.52516825500203, y: 1 }); | ||
expect(element).toStrictEqual({ x: 505.52516825500203, y: 1 }); | ||
}); | ||
@@ -108,3 +120,3 @@ | ||
distribution.sortY(); | ||
expect(distribution.array[0]).toEqual({ x: 13017.858890698088, y: 1 }); | ||
expect(distribution.array[0]).toStrictEqual({ x: 13017.858890698088, y: 1 }); | ||
}); | ||
@@ -118,3 +130,3 @@ | ||
distribution.sortY(); | ||
expect(distribution.array[0]).toEqual({ x: 27024.926947823435, y: 1 }); | ||
expect(distribution.array[0]).toStrictEqual({ x: 27024.926947823435, y: 1 }); | ||
}); | ||
@@ -128,3 +140,3 @@ | ||
distribution.sortY(); | ||
expect(distribution.array[0]).toEqual({ x: 71076.21791348715, y: 1 }); | ||
expect(distribution.array[0]).toStrictEqual({ x: 71076.21791348715, y: 1 }); | ||
}); | ||
@@ -131,0 +143,0 @@ |
@@ -6,15 +6,15 @@ 'use strict'; | ||
describe('test distribution multiply', () => { | ||
it('should yield the product', () => { | ||
let dist1 = new Distribution(); | ||
dist1.push(1, 2); | ||
dist1.push(2, 3); | ||
let dist2 = new Distribution(); | ||
dist2.push(1, 2); | ||
dist2.push(2, 3); | ||
let dist3 = dist1.multiply(dist2); | ||
it('should yield the product', () => { | ||
let dist1 = new Distribution(); | ||
dist1.push(1, 2); | ||
dist1.push(2, 3); | ||
let dist2 = new Distribution(); | ||
dist2.push(1, 2); | ||
dist2.push(2, 3); | ||
let dist3 = dist1.multiply(dist2); | ||
dist3.sortX(); | ||
expect(dist1.array).toEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
expect(dist3.array).toEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
}); | ||
dist3.sortX(); | ||
expect(dist1.array).toStrictEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
expect(dist3.array).toStrictEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
}); | ||
}); |
@@ -6,10 +6,10 @@ 'use strict'; | ||
describe('test distribution normalize', () => { | ||
it('should yield the product', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.normalize(); | ||
it('should yield the product', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.normalize(); | ||
expect(dist.array).toEqual([{ x: 1, y: 0.4 }, { x: 2, y: 0.6 }]); | ||
}); | ||
expect(dist.array).toStrictEqual([{ x: 1, y: 0.4 }, { x: 2, y: 0.6 }]); | ||
}); | ||
}); |
@@ -6,43 +6,43 @@ 'use strict'; | ||
describe('test distribution power', () => { | ||
it('power 2', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.power(2); | ||
expect(dist.array).toEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
}); | ||
it('power 2', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.power(2); | ||
expect(dist.array).toStrictEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
}); | ||
it('power 3 - 1 peak', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 1); | ||
dist.power(3); | ||
expect(dist.array).toEqual([{ x: 3, y: 1 }]); | ||
}); | ||
it('power 3 - 1 peak', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 1); | ||
dist.power(3); | ||
expect(dist.array).toStrictEqual([{ x: 3, y: 1 }]); | ||
}); | ||
it('power 3 - 2 peaks', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 1); | ||
dist.push(2, 1); | ||
dist.power(3); | ||
expect(dist.array).toEqual([{ x: 3, y: 1 }, { x: 4, y: 3 }, { x: 5, y: 3 }, { x: 6, y: 1 }]); | ||
}); | ||
it('power 3 - 2 peaks', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 1); | ||
dist.push(2, 1); | ||
dist.power(3); | ||
expect(dist.array).toStrictEqual([{ x: 3, y: 1 }, { x: 4, y: 3 }, { x: 5, y: 3 }, { x: 6, y: 1 }]); | ||
}); | ||
it('power 1000 - 2 peaks', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 1); | ||
dist.push(2, 1); | ||
dist.power(1000); | ||
expect(dist.array).toHaveLength(1001); | ||
expect(dist.array[1]).toEqual({ x: 1001, y: 1000 }); | ||
}); | ||
it('power 1000 - 2 peaks', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 1); | ||
dist.push(2, 1); | ||
dist.power(1000); | ||
expect(dist.array).toHaveLength(1001); | ||
expect(dist.array[1]).toStrictEqual({ x: 1001, y: 1000 }); | ||
}); | ||
it('power 100000 - 10 peaks', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 0.5); | ||
dist.push(2, 0.5); | ||
dist.power(100000); | ||
let sum = dist.array.reduce((s, a) => s + a.y, 0); | ||
expect(sum).toBeGreaterThan(0.99); | ||
expect(sum).toBeLessThan(1); | ||
}); | ||
it('power 100000 - 10 peaks', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 0.5); | ||
dist.push(2, 0.5); | ||
dist.power(100000); | ||
let sum = dist.array.reduce((s, a) => s + a.y, 0); | ||
expect(sum).toBeGreaterThan(0.99); | ||
expect(sum).toBeLessThan(1); | ||
}); | ||
}); |
@@ -6,9 +6,9 @@ 'use strict'; | ||
describe('test array-object-xy square', () => { | ||
it('should yield the product', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.square(); | ||
expect(dist.array).toEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
}); | ||
it('should yield the product', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.square(); | ||
expect(dist.array).toStrictEqual([{ x: 2, y: 4 }, { x: 3, y: 12 }, { x: 4, y: 9 }]); | ||
}); | ||
}); |
@@ -6,14 +6,12 @@ 'use strict'; | ||
describe('test distribution topY', () => { | ||
it('create array', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.push(2, 1); | ||
dist.push(2, 4); | ||
dist.topY(2); | ||
it('create array', () => { | ||
let dist = new Distribution(); | ||
dist.push(1, 2); | ||
dist.push(2, 3); | ||
dist.push(2, 1); | ||
dist.push(2, 4); | ||
dist.topY(2); | ||
expect(dist.array).toEqual([{ x: 2, y: 4 }, { x: 2, y: 3 }]); | ||
}); | ||
expect(dist.array).toStrictEqual([{ x: 2, y: 4 }, { x: 2, y: 3 }]); | ||
}); | ||
}); |
'use strict'; | ||
class Distribution { | ||
constructor(array) { | ||
if (Array.isArray(array)) { | ||
this.array = array; | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
} else { | ||
this.array = []; | ||
this.xSorted = true; | ||
this.ySorted = true; | ||
} | ||
constructor(array) { | ||
if (Array.isArray(array)) { | ||
this.array = array; | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
} else { | ||
this.array = []; | ||
this.xSorted = true; | ||
this.ySorted = true; | ||
} | ||
} | ||
get length() { | ||
return this.array.length; | ||
} | ||
get length() { | ||
return this.array.length; | ||
} | ||
get xs() { | ||
return this.array.map((p) => p.x); | ||
} | ||
get xs() { | ||
return this.array.map((p) => p.x); | ||
} | ||
get ys() { | ||
return this.array.map((p) => p.y); | ||
} | ||
get ys() { | ||
return this.array.map((p) => p.y); | ||
} | ||
get minX() { | ||
if (!this.xSorted) this.sortX(); | ||
return this.array[0].x; | ||
} | ||
get minX() { | ||
if (!this.xSorted) this.sortX(); | ||
return this.array[0].x; | ||
} | ||
get maxX() { | ||
if (!this.xSorted) this.sortX(); | ||
return this.array[this.array.length - 1].x; | ||
} | ||
get maxX() { | ||
if (!this.xSorted) this.sortX(); | ||
return this.array[this.array.length - 1].x; | ||
} | ||
get minY() { | ||
if (!this.ySorted) this.sortY(); | ||
return this.array[0].y; | ||
} | ||
get minY() { | ||
if (!this.ySorted) this.sortY(); | ||
return this.array[0].y; | ||
} | ||
get maxY() { | ||
if (!this.ySorted) this.sortY(); | ||
return this.array[this.array.length - 1]; | ||
} | ||
get maxY() { | ||
if (!this.ySorted) this.sortY(); | ||
return this.array[this.array.length - 1]; | ||
} | ||
} | ||
Distribution.prototype.setArray = function setArray(array) { | ||
this.array = array; | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
this.array = array; | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
}; | ||
Distribution.prototype.move = function move(other) { | ||
this.xSorted = other.xSorted; | ||
this.ySorted = other.ySorted; | ||
this.array = other.array; | ||
this.xSorted = other.xSorted; | ||
this.ySorted = other.ySorted; | ||
this.array = other.array; | ||
}; | ||
Distribution.prototype.copy = function copy() { | ||
let distCopy = new this.constructor(); | ||
distCopy.xSorted = this.xSorted; | ||
distCopy.ySorted = this.ySorted; | ||
distCopy.array = JSON.parse(JSON.stringify(this.array)); | ||
return distCopy; | ||
let distCopy = new this.constructor(); | ||
distCopy.xSorted = this.xSorted; | ||
distCopy.ySorted = this.ySorted; | ||
distCopy.array = JSON.parse(JSON.stringify(this.array)); | ||
return distCopy; | ||
}; | ||
Distribution.prototype.push = function push(x, y) { | ||
this.array.push({ x, y }); | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
this.array.push({ x, y }); | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
}; | ||
@@ -81,7 +80,7 @@ | ||
Distribution.prototype.append = function append(distribution) { | ||
for (let item of distribution.array) { | ||
this.array.push(item); | ||
} | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
for (let item of distribution.array) { | ||
this.array.push(item); | ||
} | ||
this.xSorted = false; | ||
this.ySorted = false; | ||
}; | ||
@@ -88,0 +87,0 @@ |
'use strict'; | ||
const Distribution = require('./Distribution'); | ||
const ELECTRON_MASS = require('chemical-elements').ELECTRON_MASS; | ||
const SpectrumGenerator = require('spectrum-generator').SpectrumGenerator; | ||
// for each element we need to find the isotopes | ||
const MF = require('mf-parser').MF; | ||
@@ -13,169 +9,195 @@ const preprocessIonizations = require('mf-utilities/src/preprocessIonizations'); | ||
const Distribution = require('./Distribution'); | ||
/** | ||
* An object containing two arrays | ||
* @typedef {object} XY | ||
* @property {Array<number>} x - The x array | ||
* @property {Array<number>} y - The y array | ||
*/ | ||
* An object containing two arrays | ||
* @typedef {object} XY | ||
* @property {Array<number>} x - The x array | ||
* @property {Array<number>} y - The y array | ||
*/ | ||
class IsotopicDistribution { | ||
/** | ||
* Class that manage isotopic distribution | ||
* @param {string} mf - Molecular formula | ||
* @param {object} [options={}] | ||
* @param {string} [options.ionizations=''] - string containing a comma separated list of modifications | ||
* @param {number} [options.fwhm=0.01] - Amount of Dalton under which 2 peaks are joined | ||
* @param {number} [options.maxLines=5000] - Maximal number of lines during calculations | ||
* @param {number} [options.minY=1e-8] - Minimal signal height during calculations | ||
* @param {number} [options.allowNeutral=true] - Should we keep the distribution if the molecule has no charge | ||
*/ | ||
constructor(mf, options = {}) { | ||
this.ionizations = preprocessIonizations(options.ionizations); | ||
this.mf = new MF(mf); | ||
this.mfInfo = this.mf.getInfo(); | ||
let parts = this.mfInfo.parts || [this.mfInfo]; | ||
this.parts = []; | ||
for (let partOriginal of parts) { | ||
// we calculate information for each part | ||
for (const ionization of this.ionizations) { | ||
let part = JSON.parse(JSON.stringify(partOriginal)); | ||
part.em = part.monoisotopicMass; // TODO: To remove !!! we change the name !? | ||
part.isotopesInfo = new MF(part.mf).getIsotopesInfo(); | ||
part.confidence = 0; | ||
let msInfo = getMsInfo(part, { | ||
ionization | ||
}); | ||
part.ionization = msInfo.ionization; | ||
part.ms = msInfo.ms; | ||
this.parts.push(part); | ||
} | ||
} | ||
this.cachedDistribution = undefined; | ||
this.fwhm = options.fwhm === undefined ? 0.01 : options.fwhm; | ||
// if fwhm is under 1e-8 there are some artifacts in the spectra | ||
if (this.fwhm < 1e-8) this.fwhm = 1e-8; | ||
this.minY = options.minY === undefined ? 1e-8 : options.minY; | ||
this.maxLines = options.maxLines || 5000; | ||
this.allowNeutral = | ||
options.allowNeutral === undefined ? true : options.allowNeutral; | ||
} | ||
/** | ||
* Class that manage isotopic distribution | ||
* @param {string} mf - Molecular formula | ||
* @param {object} [options={}] | ||
* @param {string} [options.ionizations=''] - string containing a comma separated list of modifications | ||
* @param {number} [options.fwhm=0.01] - Amount of Dalton under which 2 peaks are joined | ||
* @param {number} [options.maxLines=5000] - Maximal number of lines during calculations | ||
* @param {number} [options.minY=1e-8] - Minimal signal height during calculations | ||
*/ | ||
getParts() { | ||
return this.parts; | ||
} | ||
constructor(mf, options = {}) { | ||
this.ionizations = preprocessIonizations(options.ionizations); | ||
this.mf = new MF(mf); | ||
this.mfInfo = this.mf.getInfo(); | ||
let parts = this.mfInfo.parts || [this.mfInfo]; | ||
this.parts = []; | ||
for (let partOriginal of parts) { // we calculate information for each part | ||
for (const ionization of this.ionizations) { | ||
let part = JSON.parse(JSON.stringify(partOriginal)); | ||
part.em = part.monoisotopicMass; // TODO: To remove !!! we change the name !? | ||
part.isotopesInfo = (new MF(part.mf)).getIsotopesInfo(); | ||
part.confidence = 0; | ||
part.ionization = ionization; | ||
part.ms = getMsInfo(part, { | ||
ionization, | ||
}); | ||
this.parts.push(part); | ||
} | ||
/** | ||
* @return {Distribution} returns the total distribution (for all parts) | ||
*/ | ||
getDistribution() { | ||
if (this.cachedDistribution) return this.cachedDistribution; | ||
let options = { | ||
maxLines: this.maxLines, | ||
minY: this.minY, | ||
deltaX: this.fwhm | ||
}; | ||
let finalDistribution = new Distribution(); | ||
this.confidence = 0; | ||
// TODO need to cache each part without ionization | ||
// in case of many ionization we don't need to recalculate everything ! | ||
for (let part of this.parts) { | ||
let totalDistribution = new Distribution([ | ||
{ | ||
x: 0, | ||
y: 1 | ||
} | ||
this.options = options; | ||
this.fwhm = options.fwhm || 0.01; | ||
this.minY = options.minY || 1e-8; | ||
this.maxLines = options.maxLines || 5000; | ||
} | ||
]); | ||
let charge = part.ms.charge; | ||
let absoluteCharge = Math.abs(charge); | ||
if (charge || this.allowNeutral) { | ||
for (let isotope of part.isotopesInfo.isotopes) { | ||
if (isotope.number) { | ||
let isotopeDistribution = new Distribution(isotope.distribution); | ||
isotopeDistribution.power(isotope.number, options); | ||
totalDistribution.multiply(isotopeDistribution, options); | ||
} | ||
} | ||
this.confidence += totalDistribution.array.reduce( | ||
(sum, value) => sum + value.y, | ||
0 | ||
); | ||
getParts() { | ||
return this.parts; | ||
} | ||
// we finally deal with the charge | ||
/** | ||
* @return {Distribution} returns the total distribution (for all parts) | ||
*/ | ||
getDistribution() { | ||
let options = { | ||
maxLines: this.maxLines, | ||
minY: this.minY, | ||
deltaX: this.fwhm, | ||
}; | ||
let finalDistribution; | ||
this.confidence = 0; | ||
for (let i = 0; i < this.parts.length; i++) { | ||
let part = this.parts[i]; | ||
let totalDistribution = new Distribution([{ x: 0, y: 1 }]); | ||
if (charge) { | ||
totalDistribution.array.forEach((e) => { | ||
e.x = | ||
(e.x + part.ionization.em - ELECTRON_MASS * charge) / | ||
absoluteCharge; | ||
}); | ||
} | ||
for (let isotope of part.isotopesInfo.isotopes) { | ||
if (isotope.number) { | ||
let isotopeDistribution = new Distribution(isotope.distribution); | ||
isotopeDistribution.power(isotope.number, options); | ||
totalDistribution.multiply(isotopeDistribution, options); | ||
} | ||
} | ||
this.confidence += totalDistribution.array.reduce((sum, value) => (sum + value.y), 0); | ||
if (totalDistribution.array) { | ||
totalDistribution.sortX(); | ||
part.fromX = totalDistribution.array[0].x; | ||
part.toX = | ||
totalDistribution.array[totalDistribution.array.length - 1].x; | ||
} | ||
// we finally deal with the charge | ||
let charge = part.isotopesInfo.charge + part.ionization.charge; | ||
let absoluteCharge = Math.abs(charge); | ||
if (charge) { | ||
totalDistribution.array.forEach((e) => { | ||
e.x = (e.x + part.ionization.em - ELECTRON_MASS * charge) / absoluteCharge; | ||
}); | ||
} | ||
part.isotopicDistribution = totalDistribution.array; | ||
if (totalDistribution.array) { | ||
totalDistribution.sortX(); | ||
part.fromX = totalDistribution.array[0].x; | ||
part.toX = totalDistribution.array[totalDistribution.array.length - 1].x; | ||
} | ||
part.isotopicDistribution = totalDistribution.array; | ||
if (i === 0) { | ||
finalDistribution = totalDistribution; | ||
} else { | ||
finalDistribution.append(totalDistribution); | ||
} | ||
if (finalDistribution.array.length === 0) { | ||
finalDistribution = totalDistribution; | ||
} else { | ||
finalDistribution.append(totalDistribution); | ||
} | ||
finalDistribution.join(this.fwhm); | ||
this.confidence /= this.parts.length; | ||
return finalDistribution; | ||
} | ||
} | ||
if (finalDistribution) finalDistribution.join(this.fwhm); | ||
this.confidence /= this.parts.length; | ||
this.cachedDistribution = finalDistribution; | ||
return finalDistribution; | ||
} | ||
getCSV() { | ||
return this.getText(','); | ||
} | ||
getCSV() { | ||
return this.getText(','); | ||
} | ||
getTSV() { | ||
return this.getText('\t'); | ||
} | ||
getTSV() { | ||
return this.getText('\t'); | ||
getTable() { | ||
return this.getDistribution().array; | ||
} | ||
getText(delimiter = '\t') { | ||
let points = this.getDistribution().array; | ||
let csv = []; | ||
for (let point of points) { | ||
csv.push( | ||
`${point.x.toFixed(5)}${delimiter}${(point.y * 100).toFixed(3)}` | ||
); | ||
} | ||
return csv.join('\n'); | ||
} | ||
getText(delimiter) { | ||
let points = this.getDistribution().array; | ||
let csv = []; | ||
for (let point of points) { | ||
csv.push(`${point.x.toFixed(5)}${delimiter}${(point.y * 100).toFixed(3)}`); | ||
} | ||
return csv.join('\n'); | ||
/** | ||
* Returns the isotopic distirubtion | ||
* @return {XY} an object containing 2 properties: x:[] and y:[] | ||
*/ | ||
getXY() { | ||
let points = this.getDistribution().array; | ||
if (points.length === 0) return []; | ||
let maxY = points[0].y; | ||
for (let point of points) { | ||
if (point.y > maxY) maxY = point.y; | ||
} | ||
maxY /= 100; | ||
/** | ||
* Returns the isotopic distirubtion | ||
* @return {XY} an object containing 2 properties: x:[] and y:[] | ||
*/ | ||
getXY() { | ||
let points = this.getDistribution().array; | ||
if (points.length === 0) return []; | ||
let maxY = points[0].y; | ||
for (let point of points) { | ||
if (point.y > maxY) maxY = point.y; | ||
} | ||
maxY /= 100; | ||
return { | ||
x: points.map((a) => a.x), | ||
y: points.map((a) => a.y / maxY) | ||
}; | ||
} | ||
return { | ||
x: points.map((a) => a.x), | ||
y: points.map((a) => a.y / maxY) | ||
}; | ||
} | ||
/** | ||
* Returns the isotopic distirubtion as the sum of gaussians | ||
* @return {XY} isotopic distribution as an object containing 2 properties: x:[] and y:[] | ||
*/ | ||
/** | ||
* Returns the isotopic distirubtion as the sum of gaussians | ||
* @return {XY} isotopic distribution as an object containing 2 properties: x:[] and y:[] | ||
*/ | ||
getGaussian(options = {}) { | ||
let distribution = this.getDistribution(); | ||
let points = distribution.array; | ||
let pointsPerUnit = 10 / this.fwhm; | ||
if (points.length === 0) return []; | ||
let gaussianOptions = { | ||
start: Math.floor(options.from || distribution.minX - 10), | ||
end: Math.ceil(options.to || distribution.maxX + 10), | ||
pointsPerUnit, | ||
getWidth: options.getWidth ? options.getWidth : () => this.fwhm, | ||
maxSize: options.maxSize | ||
}; | ||
getGaussian(options = {}) { | ||
let distribution = this.getDistribution(); | ||
let points = distribution.array; | ||
let pointsPerUnit = 10 / this.fwhm; | ||
if (points.length === 0) return []; | ||
let gaussianOptions = { | ||
start: Math.floor(options.from || distribution.minX - 10), | ||
end: Math.ceil(options.to || distribution.maxX + 10), | ||
pointsPerUnit, | ||
getWidth: options.getWidth ? options.getWidth : () => this.fwhm, | ||
maxSize: options.maxSize | ||
}; | ||
let spectrumGenerator = new SpectrumGenerator(gaussianOptions); | ||
for (let point of points) { | ||
spectrumGenerator.addPeak([point.x, point.y]); | ||
} | ||
let spectrum = spectrumGenerator.getSpectrum(); | ||
return spectrum; | ||
let spectrumGenerator = new SpectrumGenerator(gaussianOptions); | ||
for (let point of points) { | ||
spectrumGenerator.addPeak([point.x, point.y]); | ||
} | ||
let spectrum = spectrumGenerator.getSpectrum(); | ||
return spectrum; | ||
} | ||
} | ||
module.exports = IsotopicDistribution; |
@@ -8,25 +8,25 @@ 'use strict'; | ||
module.exports = function joinX(threshold = Number.EPSILON) { | ||
// when we join we will use the center of mass | ||
let result = []; | ||
this.sortX(); | ||
let current = { | ||
x: Number.MIN_SAFE_INTEGER, | ||
y: 0 | ||
}; | ||
for (let item of this.array) { | ||
if ((item.x - current.x) <= threshold) { | ||
// weighted sum | ||
current.x = item.y / (current.y + item.y) * (item.x - current.x) + current.x; | ||
current.y += item.y; | ||
} else { | ||
current = { | ||
x: item.x, | ||
y: item.y | ||
}; | ||
result.push(current); | ||
} | ||
// when we join we will use the center of mass | ||
let result = []; | ||
this.sortX(); | ||
let current = { | ||
x: Number.MIN_SAFE_INTEGER, | ||
y: 0 | ||
}; | ||
for (let item of this.array) { | ||
if ((item.x - current.x) <= threshold) { | ||
// weighted sum | ||
current.x = item.y / (current.y + item.y) * (item.x - current.x) + current.x; | ||
current.y += item.y; | ||
} else { | ||
current = { | ||
x: item.x, | ||
y: item.y | ||
}; | ||
result.push(current); | ||
} | ||
this.array = result; | ||
this.ySorted = false; | ||
return this; | ||
} | ||
this.array = result; | ||
this.ySorted = false; | ||
return this; | ||
}; |
@@ -8,11 +8,11 @@ 'use strict'; | ||
module.exports = function maxToOne() { | ||
if (this.array.length === 0) return this; | ||
let currentMax = this.array[0].y; | ||
for (let item of this.array) { | ||
if (item.y > currentMax) currentMax = item.y; | ||
} | ||
for (let item of this.array) { | ||
item.y /= currentMax; | ||
} | ||
return this; | ||
if (this.array.length === 0) return this; | ||
let currentMax = this.array[0].y; | ||
for (let item of this.array) { | ||
if (item.y > currentMax) currentMax = item.y; | ||
} | ||
for (let item of this.array) { | ||
item.y /= currentMax; | ||
} | ||
return this; | ||
}; |
@@ -5,26 +5,26 @@ 'use strict'; | ||
module.exports = function multiply(b, options = {}) { | ||
const { | ||
minY = 1e-8, | ||
maxLines = 5000, | ||
deltaX = 1e-2, | ||
} = options; | ||
const result = new this.constructor(); | ||
const { | ||
minY = 1e-8, | ||
maxLines = 5000, | ||
deltaX = 1e-2, | ||
} = options; | ||
const result = new this.constructor(); | ||
this.sortY(); | ||
b.sortY(); | ||
this.sortY(); | ||
b.sortY(); | ||
for (let entryA of this.array) { | ||
for (let entryB of b.array) { | ||
let y = entryA.y * entryB.y; | ||
if (y > minY) result.push(entryA.x + entryB.x, y); | ||
if (result.length > maxLines) { | ||
result.join(deltaX); | ||
result.topY(maxLines / 2); | ||
} | ||
} | ||
for (let entryA of this.array) { | ||
for (let entryB of b.array) { | ||
let y = entryA.y * entryB.y; | ||
if (y > minY) result.push(entryA.x + entryB.x, y); | ||
if (result.length > maxLines) { | ||
result.join(deltaX); | ||
result.topY(maxLines / 2); | ||
} | ||
} | ||
result.join(deltaX); | ||
result.topY(maxLines / 2); | ||
this.move(result); | ||
return this; | ||
} | ||
result.join(deltaX); | ||
result.topY(maxLines / 2); | ||
this.move(result); | ||
return this; | ||
}; |
@@ -8,10 +8,10 @@ 'use strict'; | ||
module.exports = function normalize() { | ||
let sum = 0; | ||
for (let item of this.array) { | ||
sum += item.y; | ||
} | ||
for (let item of this.array) { | ||
item.y /= sum; | ||
} | ||
return this; | ||
let sum = 0; | ||
for (let item of this.array) { | ||
sum += item.y; | ||
} | ||
for (let item of this.array) { | ||
item.y /= sum; | ||
} | ||
return this; | ||
}; |
@@ -6,19 +6,19 @@ 'use strict'; | ||
module.exports = function power(p, options = {}) { | ||
if (p <= 0) throw new Error('power must be larger than 0'); | ||
if (p === 1) return this; | ||
if (p === 2) { | ||
return this.square(); | ||
} | ||
if (p <= 0) throw new Error('power must be larger than 0'); | ||
if (p === 1) return this; | ||
if (p === 2) { | ||
return this.square(); | ||
} | ||
p--; | ||
let base = this.copy(); //linear time | ||
while (p !== 0) { | ||
if ((p & 1) !== 0) { | ||
this.multiply(base, options); //executed <= log2(p) times | ||
} | ||
p >>= 1; | ||
if (p !== 0) base.square(options);//executed <= log2(p) times | ||
p--; | ||
let base = this.copy(); // linear time | ||
while (p !== 0) { | ||
if ((p & 1) !== 0) { | ||
this.multiply(base, options); // executed <= log2(p) times | ||
} | ||
p >>= 1; | ||
if (p !== 0) base.square(options);// executed <= log2(p) times | ||
} | ||
return this; | ||
return this; | ||
}; |
'use strict'; | ||
module.exports = function sortX() { | ||
this.ySorted = false; | ||
if (this.xSorted) return this; | ||
this.array.sort((a, b) => a.x - b.x); | ||
this.xSorted = true; | ||
return this; | ||
this.ySorted = false; | ||
if (this.xSorted) return this; | ||
this.array.sort((a, b) => a.x - b.x); | ||
this.xSorted = true; | ||
return this; | ||
}; |
'use strict'; | ||
module.exports = function sortY() { | ||
this.xSorted = false; | ||
if (this.ySorted) return this; | ||
this.array.sort((a, b) => b.y - a.y); | ||
this.ySorted = true; | ||
return this; | ||
this.xSorted = false; | ||
if (this.ySorted) return this; | ||
this.array.sort((a, b) => b.y - a.y); | ||
this.ySorted = true; | ||
return this; | ||
}; |
'use strict'; | ||
module.exports = function square(options = {}) { | ||
return this.multiply(this, options); | ||
return this.multiply(this, options); | ||
}; |
'use strict'; | ||
module.exports = function topY(limit) { | ||
if (!limit) return this; | ||
if (this.array.length <= limit) return this; | ||
this.sortY(); | ||
this.array.splice(limit); | ||
return this; | ||
if (!limit) return this; | ||
if (this.array.length <= limit) return this; | ||
this.sortY(); | ||
this.array.splice(limit); | ||
return this; | ||
}; |
733
29422
+ Addedatom-sorter@0.9.1(transitive)
+ Addedchemical-elements@0.9.1(transitive)
+ Addedchemical-groups@0.9.1(transitive)
+ Addedmf-parser@0.9.1(transitive)
+ Addedmf-utilities@0.9.1(transitive)
- Removedatom-sorter@0.8.0(transitive)
- Removedchemical-elements@0.7.0(transitive)
- Removedchemical-groups@0.8.0(transitive)
- Removedmf-parser@0.8.0(transitive)
- Removedmf-utilities@0.8.0(transitive)
Updatedchemical-elements@^0.9.1
Updatedmf-parser@^0.9.1
Updatedmf-utilities@^0.9.1