spectrum-generator
Advanced tools
Comparing version
324
lib/index.js
@@ -1,309 +0,15 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var mlPeakShapeGenerator = require('ml-peak-shape-generator'); | ||
var d3Random = require('d3-random'); | ||
var XSAdd = require('ml-xsadd'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var XSAdd__default = /*#__PURE__*/_interopDefaultLegacy(XSAdd); | ||
function addBaseline(data, baselineFct) { | ||
if (!baselineFct) return data; | ||
let xs = data.x; | ||
let ys = data.y; | ||
for (let i = 0; i < xs.length; i++) { | ||
ys[i] += baselineFct(xs[i]); | ||
} | ||
return data; | ||
} | ||
function addNoise(data, percent = 0, options = {}) { | ||
const { distribution = 'uniform', seed } = options; | ||
let generateRandomNumber; | ||
switch (distribution) { | ||
case 'uniform': { | ||
generateRandomNumber = getRandom(d3Random.randomUniform, seed, -0.5, 0.5); | ||
break; | ||
} | ||
case 'normal': { | ||
generateRandomNumber = getRandom(d3Random.randomNormal, seed); | ||
break; | ||
} | ||
default: | ||
throw new Error(`Unknown distribution ${options.distribution}`); | ||
} | ||
if (!percent) return data; | ||
let ys = data.y; | ||
let factor = (percent * findMax(ys)) / 100; | ||
for (let i = 0; i < ys.length; i++) { | ||
ys[i] += generateRandomNumber() * factor; | ||
} | ||
return data; | ||
} | ||
function getRandom(func, seed, ...args) { | ||
return typeof seed === 'number' | ||
? func.source(new XSAdd__default['default'](seed).random)(...args) | ||
: func(...args); | ||
} | ||
function findMax(array) { | ||
let max = Number.MIN_VALUE; | ||
for (let item of array) { | ||
if (item > max) max = item; | ||
} | ||
return max; | ||
} | ||
class SpectrumGenerator { | ||
/** | ||
* | ||
* @param {object} [options={}] | ||
* @param {number} [options.from=0] | ||
* @param {number} [options.to=0] | ||
* @param {function} [options.nbPoints=10001] | ||
* @param {number} [options.factor] default value depends of the shape in order to cover 99.99% of the surface | ||
* @param {object} [options.shape={kind:'gaussian'}] | ||
* @param {string} [options.shape.kind] kind of shape, gaussian, lorentzian or pseudovoigt | ||
* @param {object} [options.shape.options] options for the shape (like `mu` for pseudovoigt) | ||
*/ | ||
constructor(options = {}) { | ||
options = Object.assign( | ||
{}, | ||
{ | ||
from: 0, | ||
to: 1000, | ||
nbPoints: 10001, | ||
peakWidthFct: () => 5, | ||
shape: { | ||
kind: 'gaussian', | ||
}, | ||
}, | ||
options, | ||
); | ||
this.from = options.from; | ||
this.to = options.to; | ||
this.nbPoints = options.nbPoints; | ||
this.interval = (this.to - this.from) / (this.nbPoints - 1); | ||
this.peakWidthFct = options.peakWidthFct; | ||
this.maxPeakHeight = Number.MIN_SAFE_INTEGER; | ||
let shapeGenerator = mlPeakShapeGenerator.getShapeGenerator(options.shape); | ||
this.shape = shapeGenerator; | ||
assertNumber(this.from, 'from'); | ||
assertNumber(this.to, 'to'); | ||
assertInteger(this.nbPoints, 'nbPoints'); | ||
if (this.to <= this.from) { | ||
throw new RangeError('to option must be larger than from'); | ||
} | ||
if (typeof this.peakWidthFct !== 'function') { | ||
throw new TypeError('peakWidthFct option must be a function'); | ||
} | ||
this.reset(); | ||
} | ||
addPeaks(peaks, options) { | ||
if ( | ||
!Array.isArray(peaks) && | ||
(typeof peaks !== 'object' || | ||
peaks.x === undefined || | ||
peaks.y === undefined || | ||
!Array.isArray(peaks.x) || | ||
!Array.isArray(peaks.y) || | ||
peaks.x.length !== peaks.y.length) | ||
) { | ||
throw new TypeError( | ||
'peaks must be an array or an object containing x[] and y[]', | ||
); | ||
} | ||
if (Array.isArray(peaks)) { | ||
for (const peak of peaks) { | ||
this.addPeak(peak, options); | ||
} | ||
} else { | ||
for (let i = 0; i < peaks.x.length; i++) { | ||
this.addPeak([peaks.x[i], peaks.y[i]], options); | ||
} | ||
} | ||
return this; | ||
} | ||
/** | ||
* | ||
* @param {[x,y]|[x,y,w]|{x,y,width}} [peak] | ||
* @param {*} options | ||
*/ | ||
addPeak(peak, options = {}) { | ||
if ( | ||
typeof peak !== 'object' || | ||
(peak.length !== 2 && | ||
peak.length !== 3 && | ||
(peak.x === undefined || peak.y === undefined)) | ||
) { | ||
throw new Error( | ||
'peak must be an array with two (or three) values or an object with {x,y,width?}', | ||
); | ||
} | ||
let xPosition; | ||
let intensity; | ||
let peakWidth; | ||
let peakOptions; | ||
if (Array.isArray(peak)) { | ||
[xPosition, intensity, peakWidth, peakOptions] = peak; | ||
} else { | ||
xPosition = peak.x; | ||
intensity = peak.y; | ||
peakWidth = peak.width; | ||
peakOptions = peak.options; | ||
} | ||
if (intensity > this.maxPeakHeight) this.maxPeakHeight = intensity; | ||
let { | ||
width = peakWidth === undefined | ||
? this.peakWidthFct(xPosition) | ||
: peakWidth, | ||
widthLeft, | ||
widthRight, | ||
shape: shapeOptions, | ||
} = options; | ||
if (peakOptions) { | ||
Object.assign(shapeOptions || {}, peakOptions || {}); | ||
} | ||
let shapeGenerator = shapeOptions | ||
? mlPeakShapeGenerator.getShapeGenerator(shapeOptions) | ||
: this.shape; | ||
if (!widthLeft) widthLeft = width; | ||
if (!widthRight) widthRight = width; | ||
let factor = | ||
options.factor === undefined | ||
? shapeGenerator.getFactor() | ||
: options.factor; | ||
const firstValue = xPosition - (widthLeft / 2) * factor; | ||
const lastValue = xPosition + (widthRight / 2) * factor; | ||
const firstPoint = Math.max( | ||
0, | ||
Math.floor((firstValue - this.from) / this.interval), | ||
); | ||
const lastPoint = Math.min( | ||
this.nbPoints - 1, | ||
Math.ceil((lastValue - this.from) / this.interval), | ||
); | ||
const middlePoint = Math.round((xPosition - this.from) / this.interval); | ||
// PEAK SHAPE MAY BE ASYMMETRC (widthLeft and widthRight) ! | ||
// we calculate the left part of the shape | ||
shapeGenerator.setFWHM(widthLeft); | ||
for (let index = firstPoint; index < Math.max(middlePoint, 0); index++) { | ||
this.data.y[index] += | ||
intensity * shapeGenerator.fct(this.data.x[index] - xPosition); | ||
} | ||
// we calculate the right part of the gaussian | ||
shapeGenerator.setFWHM(widthRight); | ||
for ( | ||
let index = Math.min(middlePoint, lastPoint); | ||
index <= lastPoint; | ||
index++ | ||
) { | ||
this.data.y[index] += | ||
intensity * shapeGenerator.fct(this.data.x[index] - xPosition); | ||
} | ||
return this; | ||
} | ||
addBaseline(baselineFct) { | ||
addBaseline(this.data, baselineFct); | ||
return this; | ||
} | ||
addNoise(percent, options) { | ||
addNoise(this.data, percent, options); | ||
return this; | ||
} | ||
getSpectrum(options = {}) { | ||
if (typeof options === 'boolean') { | ||
options = { copy: options }; | ||
} | ||
const { copy = true, threshold = 0 } = options; | ||
if (threshold) { | ||
let minPeakHeight = this.maxPeakHeight * threshold; | ||
let x = []; | ||
let y = []; | ||
for (let i = 0; i < this.data.x.length; i++) { | ||
if (this.data.y[i] >= minPeakHeight) { | ||
x.push(this.data.x[i]); | ||
y.push(this.data.y[i]); | ||
} | ||
} | ||
return { x, y }; | ||
} | ||
if (copy) { | ||
return { | ||
x: this.data.x.slice(), | ||
y: this.data.y.slice(), | ||
}; | ||
} else { | ||
return this.data; | ||
} | ||
} | ||
reset() { | ||
const spectrum = (this.data = { | ||
x: new Float64Array(this.nbPoints), | ||
y: new Float64Array(this.nbPoints), | ||
}); | ||
for (let i = 0; i < this.nbPoints; i++) { | ||
spectrum.x[i] = this.from + i * this.interval; | ||
} | ||
return this; | ||
} | ||
} | ||
function assertInteger(value, name) { | ||
if (!Number.isInteger(value)) { | ||
throw new TypeError(`${name} option must be an integer`); | ||
} | ||
} | ||
function assertNumber(value, name) { | ||
if (!Number.isFinite(value)) { | ||
throw new TypeError(`${name} option must be a number`); | ||
} | ||
} | ||
function generateSpectrum(peaks, options = {}) { | ||
const generator = new SpectrumGenerator(options); | ||
generator.addPeaks(peaks, options); | ||
if (options.baseline) generator.addBaseline(options.baseline); | ||
if (options.noise) generator.addNoise(options.noise.percent, options.noise); | ||
return generator.getSpectrum({ | ||
threshold: options.threshold, | ||
}); | ||
} | ||
exports.SpectrumGenerator = SpectrumGenerator; | ||
exports.generateSpectrum = generateSpectrum; | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__exportStar(require("./SpectrumGenerator"), exports); | ||
__exportStar(require("./Spectrum2DGenerator"), exports); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "spectrum-generator", | ||
"version": "4.7.1", | ||
"version": "4.8.0", | ||
"description": "generate a spectrum from discrete peaks", | ||
"main": "lib/index.js", | ||
"module": "src/index.js", | ||
"types": "spectrum-generator.d.ts", | ||
"main": "./lib/index.js", | ||
"module": "./lib-esm/index.js", | ||
"types": "./lib/index.d.ts", | ||
"keywords": [], | ||
"author": "Luc Patiny", | ||
"contributors": [ | ||
"Michaël Zasso", | ||
"Océane Patiny", | ||
"J. Alejandro Bolaños A." | ||
], | ||
"license": "MIT", | ||
"files": [ | ||
"spectrum-generator.d.ts", | ||
"src", | ||
"lib", | ||
"src" | ||
"lib-esm" | ||
], | ||
"scripts": { | ||
"build": "cheminfo-build --entry src/index.js --root SpectrumGenerator", | ||
"check-types": "tsc --noEmit", | ||
"clean": "rimraf lib lib-esm", | ||
"eslint": "eslint src --cache", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"example": "node -r esm examples/generateSpectrum.js", | ||
"prepublishOnly": "rollup -c", | ||
"test": "npm run test-coverage && npm run eslint", | ||
"test-coverage": "jest --coverage", | ||
"test-only": "jest" | ||
"prepack": "npm run tsc", | ||
"prettier": "prettier --check src", | ||
"prettier-write": "prettier --write src", | ||
"test": "npm run test-coverage && npm run eslint && npm run prettier && npm run check-types", | ||
"test-coverage": "npm run test-only -- --coverage", | ||
"test-only": "jest", | ||
"tsc": "npm run clean && npm run tsc-cjs && npm run tsc-esm", | ||
"tsc-cjs": "tsc --project tsconfig.cjs.json", | ||
"tsc-esm": "tsc --project tsconfig.esm.json" | ||
}, | ||
@@ -27,9 +40,2 @@ "repository": { | ||
}, | ||
"keywords": [], | ||
"author": "Luc Patiny", | ||
"contributors": [ | ||
"Michaël Zasso", | ||
"Océane Patiny" | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -40,24 +46,24 @@ "url": "https://github.com/cheminfo/spectrum-generator/issues" | ||
"jest": { | ||
"preset": "ts-jest", | ||
"testEnvironment": "node" | ||
}, | ||
"devDependencies": { | ||
"@babel/plugin-transform-modules-commonjs": "^7.13.8", | ||
"@types/jest": "^26.0.21", | ||
"cheminfo-build": "^1.1.10", | ||
"convert-to-jcamp": "^4.2.0", | ||
"eslint": "^7.22.0", | ||
"eslint-config-cheminfo": "^5.2.3", | ||
"esm": "^3.2.25", | ||
"jest": "^26.6.3", | ||
"@types/d3-random": "^3.0.1", | ||
"@types/jest": "^26.0.24", | ||
"eslint": "^7.32.0", | ||
"eslint-config-cheminfo-typescript": "^8.0.9", | ||
"jest": "^27.0.6", | ||
"ml-array-max": "^1.2.3", | ||
"ml-savitzky-golay-generalized": "^2.0.3", | ||
"ml-spectra-processing": "^5.8.0", | ||
"prettier": "^2.2.1", | ||
"rollup": "^2.42.3", | ||
"typescript": "^4.2.3" | ||
"prettier": "^2.3.2", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^27.0.4", | ||
"typescript": "^4.3.5" | ||
}, | ||
"dependencies": { | ||
"d3-random": "^2.2.2", | ||
"ml-peak-shape-generator": "^1.0.0", | ||
"ml-peak-shape-generator": "^2.0.1", | ||
"ml-xsadd": "^2.0.0" | ||
} | ||
} |
@@ -112,5 +112,5 @@ # spectrum-generator | ||
[npm-url]: https://www.npmjs.com/package/spectrum-generator | ||
[ci-image]: https://github.com/cheminfo/spectrum-generator/workflows/Node.js%20CI/badge.svg?branch=master | ||
[ci-image]: https://github.com/cheminfo/spectrum-generator/workflows/Node.js%20CI/badge.svg?branch=main | ||
[ci-url]: https://github.com/cheminfo/spectrum-generator/actions?query=workflow%3A%22Node.js+CI%22 | ||
[download-image]: https://img.shields.io/npm/dm/spectrum-generator.svg | ||
[download-url]: https://www.npmjs.com/package/spectrum-generator |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
106897
111.7%12
-7.69%40
110.53%2038
59.22%1
Infinity%+ Added
- Removed