Comparing version 3.2.0 to 4.0.0
# Changelog | ||
## [4.0.0](https://www.github.com/cheminfo/xy-parser/compare/v3.2.0...v4.0.0) (2021-11-09) | ||
### ⚠ BREAKING CHANGES | ||
* migrate to typescript | ||
### Features | ||
* migrate to typescript ([b067462](https://www.github.com/cheminfo/xy-parser/commit/b067462c1006045b7ec4fa9eed089ef3dcabeb1b)) | ||
## [3.2.0](https://www.github.com/cheminfo/xy-parser/compare/v3.1.1...v3.2.0) (2021-07-14) | ||
@@ -4,0 +15,0 @@ |
886
lib/index.js
@@ -1,802 +0,114 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseXY = void 0; | ||
const ensure_string_1 = require("ensure-string"); | ||
const ml_array_max_1 = __importDefault(require("ml-array-max")); | ||
const ml_arrayxy_uniquex_1 = __importDefault(require("ml-arrayxy-uniquex")); | ||
const ml_spectra_processing_1 = require("ml-spectra-processing"); | ||
/** | ||
* Ensure that the data is string. If it is an ArrayBuffer it will be converted to string using TextDecoder. | ||
* @param {string|ArrayBuffer} blob | ||
* @param {object} [options={}] | ||
* @param {string} [options.encoding='utf8'] | ||
* @returns {string} | ||
* Parse a text-file and convert it to an array of XY points. | ||
* | ||
* @param text - Csv or tsv strings. | ||
* @param [options={}] - | ||
* @param [options.rescale = false] - Will set the maximum value to 1. | ||
* @param [options.uniqueX = false] - Make the X values unique (works only with 'xxyy' format). If the X value is repeated the sum of Y is done. | ||
* @param [options.xColumn = 0] - A number that specifies the x column. | ||
* @param [options.yColumn = 1] - A number that specifies the y column. | ||
* @param [options.bestGuess=false] - Will try to guess which columns are the best. | ||
* @param [options.numberColumns=Number.MAX_SAFE_INTEGER] - If the file has 10 columns and you specify here 2 it will reflow the file. | ||
* @param [options.maxNumberColumns = (Math.max(xColumn, yColumn)+1)] - A number that specifies the maximum number of y columns. | ||
* @param [options.minNumberColumns = (Math.min(xColumn, yColumn)+1)] - A number that specifies the minimum number of y columns. | ||
* @param [options.keepInfo = false] - Should we keep the non numeric lines. In this case the system will return an object {data, info}. | ||
* @returns - | ||
*/ | ||
function ensureString(blob, options = {}) { | ||
const { encoding = 'utf8' } = options; | ||
if (ArrayBuffer.isView(blob) || blob instanceof ArrayBuffer) { | ||
const decoder = new TextDecoder(encoding); | ||
return decoder.decode(blob); | ||
} | ||
return blob; | ||
} | ||
const toString$1 = Object.prototype.toString; | ||
function isAnyArray(object) { | ||
return toString$1.call(object).endsWith('Array]'); | ||
} | ||
function max(input) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
if (!isAnyArray(input)) { | ||
throw new TypeError('input must be an array'); | ||
} | ||
if (input.length === 0) { | ||
throw new TypeError('input must not be empty'); | ||
} | ||
var _options$fromIndex = options.fromIndex, | ||
fromIndex = _options$fromIndex === void 0 ? 0 : _options$fromIndex, | ||
_options$toIndex = options.toIndex, | ||
toIndex = _options$toIndex === void 0 ? input.length : _options$toIndex; | ||
if (fromIndex < 0 || fromIndex >= input.length || !Number.isInteger(fromIndex)) { | ||
throw new Error('fromIndex must be a positive integer smaller than length'); | ||
} | ||
if (toIndex <= fromIndex || toIndex > input.length || !Number.isInteger(toIndex)) { | ||
throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length'); | ||
} | ||
var maxValue = input[fromIndex]; | ||
for (var i = fromIndex + 1; i < toIndex; i++) { | ||
if (input[i] > maxValue) maxValue = input[i]; | ||
} | ||
return maxValue; | ||
} | ||
/** | ||
* In place modification of the 2 arrays to make X unique and sum the Y if X has the same value | ||
* @param {object} [points={}] : Object of points contains property x (an array) and y (an array) | ||
* @return points | ||
*/ | ||
function uniqueX(points = {}) { | ||
const { x, y } = points; | ||
if (x.length < 2) return; | ||
if (x.length !== y.length) { | ||
throw new Error('The X and Y arrays mush have the same length'); | ||
} | ||
let current = x[0]; | ||
let counter = 0; | ||
for (let i = 1; i < x.length; i++) { | ||
if (current !== x[i]) { | ||
counter++; | ||
current = x[i]; | ||
x[counter] = x[i]; | ||
if (i !== counter) { | ||
y[counter] = 0; | ||
} | ||
} | ||
if (i !== counter) { | ||
y[counter] += y[i]; | ||
} | ||
} | ||
x.length = counter + 1; | ||
y.length = counter + 1; | ||
} | ||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | ||
function createCommonjsModule(fn, module) { | ||
return module = { exports: {} }, fn(module, module.exports), module.exports; | ||
} | ||
createCommonjsModule(function (module) { | ||
(function(){function a(d){for(var e=0,f=d.length-1,g=void 0,h=void 0,i=void 0,j=c(e,f);!0;){if(f<=e)return d[j];if(f==e+1)return d[e]>d[f]&&b(d,e,f),d[j];for(g=c(e,f),d[g]>d[f]&&b(d,g,f),d[e]>d[f]&&b(d,e,f),d[g]>d[e]&&b(d,g,e),b(d,g,e+1),h=e+1,i=f;!0;){do h++;while(d[e]>d[h]);do i--;while(d[i]>d[e]);if(i<h)break;b(d,h,i);}b(d,e,i),i<=j&&(e=h),i>=j&&(f=i-1);}}var b=function b(d,e,f){var _ref;return _ref=[d[f],d[e]],d[e]=_ref[0],d[f]=_ref[1],_ref},c=function c(d,e){return ~~((d+e)/2)};module.exports?module.exports=a:window.median=a;})(); | ||
}); | ||
/** | ||
* Returns true if x is monotone | ||
* @param {Array} array | ||
* @return {boolean} | ||
*/ | ||
function xIsMonotone(array) { | ||
if (array.length <= 2) { | ||
return true; | ||
} | ||
if (array[0] === array[1]) { | ||
// maybe a constant series | ||
for (let i = 1; i < array.length - 1; i++) { | ||
if (array[i] !== array[i + 1]) return false; | ||
} | ||
return true; | ||
} | ||
if (array[0] < array[array.length - 1]) { | ||
for (let i = 0; i < array.length - 1; i++) { | ||
if (array[i] >= array[i + 1]) return false; | ||
} | ||
} else { | ||
for (let i = 0; i < array.length - 1; i++) { | ||
if (array[i] <= array[i + 1]) return false; | ||
} | ||
} | ||
return true; | ||
} | ||
createCommonjsModule(function (module, exports) { | ||
(function (global, factory) { | ||
factory(exports) ; | ||
}(commonjsGlobal, function (exports) { | ||
function ascending(a, b) { | ||
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; | ||
} | ||
function bisector(compare) { | ||
if (compare.length === 1) compare = ascendingComparator(compare); | ||
return { | ||
left: function(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
while (lo < hi) { | ||
var mid = lo + hi >>> 1; | ||
if (compare(a[mid], x) < 0) lo = mid + 1; | ||
else hi = mid; | ||
function parseXY(text, options = {}) { | ||
let { rescale = false, uniqueX = false, xColumn = 0, yColumn = 1, keepInfo = false, bestGuess = false, numberColumns = Number.MAX_SAFE_INTEGER, maxNumberColumns = Number.MAX_SAFE_INTEGER, minNumberColumns = 2, } = options; | ||
text = (0, ensure_string_1.ensureString)(text); | ||
maxNumberColumns = Math.max(maxNumberColumns, xColumn + 1, yColumn + 1); | ||
minNumberColumns = Math.max(xColumn + 1, yColumn + 1, minNumberColumns); | ||
let lines = text.split(/[\r\n]+/); | ||
let matrix = []; | ||
let info = []; | ||
let position = 0; | ||
lines.forEach((line) => { | ||
line = line.trim(); | ||
// we will consider only lines that contains only numbers | ||
if (/[0-9]+/.test(line) && /^[0-9eE,;. \t+-]+$/.test(line)) { | ||
let fields = line.split(/,[; \t]+|[; \t]+/); | ||
if (fields.length === 1) { | ||
fields = line.split(/[,; \t]+/); | ||
} | ||
if (fields && | ||
fields.length >= minNumberColumns && // we filter lines that have not enough or too many columns | ||
fields.length <= maxNumberColumns) { | ||
matrix.push(fields.map((value) => parseFloat(value.replace(',', '.')))); | ||
position++; | ||
} | ||
} | ||
return lo; | ||
}, | ||
right: function(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
while (lo < hi) { | ||
var mid = lo + hi >>> 1; | ||
if (compare(a[mid], x) > 0) hi = mid; | ||
else lo = mid + 1; | ||
else if (line) { | ||
info.push({ position, value: line }); | ||
} | ||
return lo; | ||
} | ||
}; | ||
} | ||
function ascendingComparator(f) { | ||
return function(d, x) { | ||
return ascending(f(d), x); | ||
}; | ||
} | ||
var ascendingBisect = bisector(ascending); | ||
var bisectRight = ascendingBisect.right; | ||
var bisectLeft = ascendingBisect.left; | ||
function descending(a, b) { | ||
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; | ||
} | ||
function number$1(x) { | ||
return x === null ? NaN : +x; | ||
} | ||
function variance(array, f) { | ||
var n = array.length, | ||
m = 0, | ||
a, | ||
d, | ||
s = 0, | ||
i = -1, | ||
j = 0; | ||
if (f == null) { | ||
while (++i < n) { | ||
if (!isNaN(a = number$1(array[i]))) { | ||
d = a - m; | ||
m += d / ++j; | ||
s += d * (a - m); | ||
}); | ||
if (bestGuess) { | ||
if (matrix[0] && | ||
matrix[0].length === 3 && | ||
options.xColumn === undefined && | ||
options.yColumn === undefined) { | ||
// is the first column a seuqnetial number ? | ||
let skipFirstColumn = true; | ||
for (let i = 0; i < matrix.length - 1; i++) { | ||
if (Math.abs(matrix[i][0] - matrix[i + 1][0]) !== 1) { | ||
skipFirstColumn = false; | ||
} | ||
} | ||
if (skipFirstColumn) { | ||
xColumn = 1; | ||
yColumn = 2; | ||
} | ||
} | ||
} | ||
if (matrix[0] && matrix[0].length > 3) { | ||
const xs = []; | ||
for (let row of matrix) { | ||
for (let i = xColumn; i < row.length; i += 2) { | ||
xs.push(row[i]); | ||
} | ||
} | ||
if ((0, ml_spectra_processing_1.xIsMonotone)(xs)) { | ||
numberColumns = 2; | ||
} | ||
} | ||
} | ||
else { | ||
while (++i < n) { | ||
if (!isNaN(a = number$1(f(array[i], i, array)))) { | ||
d = a - m; | ||
m += d / ++j; | ||
s += d * (a - m); | ||
if (numberColumns) { | ||
const newMatrix = []; | ||
for (const row of matrix) { | ||
for (let i = 0; i < row.length; i += numberColumns) { | ||
newMatrix.push(row.slice(i, i + numberColumns)); | ||
} | ||
} | ||
} | ||
matrix = newMatrix; | ||
} | ||
if (j > 1) return s / (j - 1); | ||
} | ||
function deviation(array, f) { | ||
var v = variance(array, f); | ||
return v ? Math.sqrt(v) : v; | ||
} | ||
function extent(array, f) { | ||
var i = -1, | ||
n = array.length, | ||
a, | ||
b, | ||
c; | ||
if (f == null) { | ||
while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; } | ||
while (++i < n) if ((b = array[i]) != null) { | ||
if (a > b) a = b; | ||
if (c < b) c = b; | ||
} | ||
} | ||
else { | ||
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = c = b; break; } | ||
while (++i < n) if ((b = f(array[i], i, array)) != null) { | ||
if (a > b) a = b; | ||
if (c < b) c = b; | ||
} | ||
} | ||
return [a, c]; | ||
} | ||
function constant(x) { | ||
return function() { | ||
return x; | ||
const result = { | ||
x: matrix.map((row) => row[xColumn]), | ||
y: matrix.map((row) => row[yColumn]), | ||
}; | ||
} | ||
function identity(x) { | ||
return x; | ||
} | ||
function range(start, stop, step) { | ||
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step; | ||
var i = -1, | ||
n = Math.max(0, Math.ceil((stop - start) / step)) | 0, | ||
range = new Array(n); | ||
while (++i < n) { | ||
range[i] = start + i * step; | ||
if (uniqueX) { | ||
(0, ml_arrayxy_uniquex_1.default)(result); | ||
} | ||
return range; | ||
} | ||
var e10 = Math.sqrt(50); | ||
var e5 = Math.sqrt(10); | ||
var e2 = Math.sqrt(2); | ||
function ticks(start, stop, count) { | ||
var step = tickStep(start, stop, count); | ||
return range( | ||
Math.ceil(start / step) * step, | ||
Math.floor(stop / step) * step + step / 2, // inclusive | ||
step | ||
); | ||
} | ||
function tickStep(start, stop, count) { | ||
var step0 = Math.abs(stop - start) / Math.max(0, count), | ||
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), | ||
error = step0 / step1; | ||
if (error >= e10) step1 *= 10; | ||
else if (error >= e5) step1 *= 5; | ||
else if (error >= e2) step1 *= 2; | ||
return stop < start ? -step1 : step1; | ||
} | ||
function sturges(values) { | ||
return Math.ceil(Math.log(values.length) / Math.LN2) + 1; | ||
} | ||
function number(x) { | ||
return +x; | ||
} | ||
function histogram() { | ||
var value = identity, | ||
domain = extent, | ||
threshold = sturges; | ||
function histogram(data) { | ||
var i, | ||
n = data.length, | ||
x, | ||
values = new Array(n); | ||
// Coerce values to numbers. | ||
for (i = 0; i < n; ++i) { | ||
values[i] = +value(data[i], i, data); | ||
} | ||
var xz = domain(values), | ||
x0 = +xz[0], | ||
x1 = +xz[1], | ||
tz = threshold(values, x0, x1); | ||
// Convert number of thresholds into uniform thresholds. | ||
if (!Array.isArray(tz)) tz = ticks(x0, x1, +tz); | ||
// Coerce thresholds to numbers, ignoring any outside the domain. | ||
var m = tz.length; | ||
for (i = 0; i < m; ++i) tz[i] = +tz[i]; | ||
while (tz[0] <= x0) tz.shift(), --m; | ||
while (tz[m - 1] >= x1) tz.pop(), --m; | ||
var bins = new Array(m + 1), | ||
bin; | ||
// Initialize bins. | ||
for (i = 0; i <= m; ++i) { | ||
bin = bins[i] = []; | ||
bin.x0 = i > 0 ? tz[i - 1] : x0; | ||
bin.x1 = i < m ? tz[i] : x1; | ||
} | ||
// Assign data to bins by value, ignoring any outside the domain. | ||
for (i = 0; i < n; ++i) { | ||
x = values[i]; | ||
if (x0 <= x && x <= x1) { | ||
bins[bisectRight(tz, x, 0, m)].push(data[i]); | ||
if (rescale) { | ||
let maxY = (0, ml_array_max_1.default)(result.y); | ||
for (let i = 0; i < result.y.length; i++) { | ||
result.y[i] /= maxY; | ||
} | ||
} | ||
return bins; | ||
} | ||
histogram.value = function(_) { | ||
return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), histogram) : value; | ||
if (!keepInfo) | ||
return result; | ||
return { | ||
info, | ||
data: result, | ||
}; | ||
histogram.domain = function(_) { | ||
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([+_[0], +_[1]]), histogram) : domain; | ||
}; | ||
histogram.thresholds = function(_) { | ||
if (!arguments.length) return threshold; | ||
threshold = typeof _ === "function" ? _ | ||
: Array.isArray(_) ? constant(Array.prototype.map.call(_, number)) | ||
: constant(+_); | ||
return histogram; | ||
}; | ||
return histogram; | ||
} | ||
function quantile(array, p, f) { | ||
if (f == null) f = number$1; | ||
if (!(n = array.length)) return; | ||
if ((p = +p) <= 0 || n < 2) return +f(array[0], 0, array); | ||
if (p >= 1) return +f(array[n - 1], n - 1, array); | ||
var n, | ||
h = (n - 1) * p, | ||
i = Math.floor(h), | ||
a = +f(array[i], i, array), | ||
b = +f(array[i + 1], i + 1, array); | ||
return a + (b - a) * (h - i); | ||
} | ||
function freedmanDiaconis(values, min, max) { | ||
values.sort(ascending); | ||
return Math.ceil((max - min) / (2 * (quantile(values, 0.75) - quantile(values, 0.25)) * Math.pow(values.length, -1 / 3))); | ||
} | ||
function scott(values, min, max) { | ||
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3))); | ||
} | ||
function max(array, f) { | ||
var i = -1, | ||
n = array.length, | ||
a, | ||
b; | ||
if (f == null) { | ||
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } | ||
while (++i < n) if ((b = array[i]) != null && b > a) a = b; | ||
} | ||
else { | ||
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; } | ||
while (++i < n) if ((b = f(array[i], i, array)) != null && b > a) a = b; | ||
} | ||
return a; | ||
} | ||
function mean(array, f) { | ||
var s = 0, | ||
n = array.length, | ||
a, | ||
i = -1, | ||
j = n; | ||
if (f == null) { | ||
while (++i < n) if (!isNaN(a = number$1(array[i]))) s += a; else --j; | ||
} | ||
else { | ||
while (++i < n) if (!isNaN(a = number$1(f(array[i], i, array)))) s += a; else --j; | ||
} | ||
if (j) return s / j; | ||
} | ||
function median(array, f) { | ||
var numbers = [], | ||
n = array.length, | ||
a, | ||
i = -1; | ||
if (f == null) { | ||
while (++i < n) if (!isNaN(a = number$1(array[i]))) numbers.push(a); | ||
} | ||
else { | ||
while (++i < n) if (!isNaN(a = number$1(f(array[i], i, array)))) numbers.push(a); | ||
} | ||
return quantile(numbers.sort(ascending), 0.5); | ||
} | ||
function merge(arrays) { | ||
var n = arrays.length, | ||
m, | ||
i = -1, | ||
j = 0, | ||
merged, | ||
array; | ||
while (++i < n) j += arrays[i].length; | ||
merged = new Array(j); | ||
while (--n >= 0) { | ||
array = arrays[n]; | ||
m = array.length; | ||
while (--m >= 0) { | ||
merged[--j] = array[m]; | ||
} | ||
} | ||
return merged; | ||
} | ||
function min(array, f) { | ||
var i = -1, | ||
n = array.length, | ||
a, | ||
b; | ||
if (f == null) { | ||
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } | ||
while (++i < n) if ((b = array[i]) != null && a > b) a = b; | ||
} | ||
else { | ||
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; } | ||
while (++i < n) if ((b = f(array[i], i, array)) != null && a > b) a = b; | ||
} | ||
return a; | ||
} | ||
function pairs(array) { | ||
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n); | ||
while (i < n) pairs[i] = [p, p = array[++i]]; | ||
return pairs; | ||
} | ||
function permute(array, indexes) { | ||
var i = indexes.length, permutes = new Array(i); | ||
while (i--) permutes[i] = array[indexes[i]]; | ||
return permutes; | ||
} | ||
function scan(array, compare) { | ||
if (!(n = array.length)) return; | ||
var i = 0, | ||
n, | ||
j = 0, | ||
xi, | ||
xj = array[j]; | ||
if (!compare) compare = ascending; | ||
while (++i < n) if (compare(xi = array[i], xj) < 0 || compare(xj, xj) !== 0) xj = xi, j = i; | ||
if (compare(xj, xj) === 0) return j; | ||
} | ||
function shuffle(array, i0, i1) { | ||
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0), | ||
t, | ||
i; | ||
while (m) { | ||
i = Math.random() * m-- | 0; | ||
t = array[m + i0]; | ||
array[m + i0] = array[i + i0]; | ||
array[i + i0] = t; | ||
} | ||
return array; | ||
} | ||
function sum(array, f) { | ||
var s = 0, | ||
n = array.length, | ||
a, | ||
i = -1; | ||
if (f == null) { | ||
while (++i < n) if (a = +array[i]) s += a; // Note: zero and null are equivalent. | ||
} | ||
else { | ||
while (++i < n) if (a = +f(array[i], i, array)) s += a; | ||
} | ||
return s; | ||
} | ||
function transpose(matrix) { | ||
if (!(n = matrix.length)) return []; | ||
for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) { | ||
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) { | ||
row[j] = matrix[j][i]; | ||
} | ||
} | ||
return transpose; | ||
} | ||
function length(d) { | ||
return d.length; | ||
} | ||
function zip() { | ||
return transpose(arguments); | ||
} | ||
var version = "0.7.1"; | ||
exports.version = version; | ||
exports.bisect = bisectRight; | ||
exports.bisectRight = bisectRight; | ||
exports.bisectLeft = bisectLeft; | ||
exports.ascending = ascending; | ||
exports.bisector = bisector; | ||
exports.descending = descending; | ||
exports.deviation = deviation; | ||
exports.extent = extent; | ||
exports.histogram = histogram; | ||
exports.thresholdFreedmanDiaconis = freedmanDiaconis; | ||
exports.thresholdScott = scott; | ||
exports.thresholdSturges = sturges; | ||
exports.max = max; | ||
exports.mean = mean; | ||
exports.median = median; | ||
exports.merge = merge; | ||
exports.min = min; | ||
exports.pairs = pairs; | ||
exports.permute = permute; | ||
exports.quantile = quantile; | ||
exports.range = range; | ||
exports.scan = scan; | ||
exports.shuffle = shuffle; | ||
exports.sum = sum; | ||
exports.ticks = ticks; | ||
exports.tickStep = tickStep; | ||
exports.transpose = transpose; | ||
exports.variance = variance; | ||
exports.zip = zip; | ||
})); | ||
}); | ||
/*! | ||
* assign-symbols <https://github.com/jonschlinkert/assign-symbols> | ||
* | ||
* Copyright (c) 2015-present, Jon Schlinkert. | ||
* Licensed under the MIT License. | ||
*/ | ||
const toString = Object.prototype.toString; | ||
const isEnumerable = Object.prototype.propertyIsEnumerable; | ||
const getSymbols = Object.getOwnPropertySymbols; | ||
var assignSymbols = (target, ...args) => { | ||
if (!isObject(target)) { | ||
throw new TypeError('expected the first argument to be an object'); | ||
} | ||
if (args.length === 0 || typeof Symbol !== 'function' || typeof getSymbols !== 'function') { | ||
return target; | ||
} | ||
for (let arg of args) { | ||
let names = getSymbols(arg); | ||
for (let key of names) { | ||
if (isEnumerable.call(arg, key)) { | ||
target[key] = arg[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
function isObject(val) { | ||
return typeof val === 'function' || toString.call(val) === '[object Object]' || Array.isArray(val); | ||
} | ||
createCommonjsModule(function (module) { | ||
const toString = Object.prototype.toString; | ||
const isValidKey = key => { | ||
return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; | ||
}; | ||
const assign = module.exports = (target, ...args) => { | ||
let i = 0; | ||
if (isPrimitive(target)) target = args[i++]; | ||
if (!target) target = {}; | ||
for (; i < args.length; i++) { | ||
if (isObject(args[i])) { | ||
for (const key of Object.keys(args[i])) { | ||
if (isValidKey(key)) { | ||
if (isObject(target[key]) && isObject(args[i][key])) { | ||
assign(target[key], args[i][key]); | ||
} else { | ||
target[key] = args[i][key]; | ||
} | ||
} | ||
} | ||
assignSymbols(target, args[i]); | ||
} | ||
} | ||
return target; | ||
}; | ||
function isObject(val) { | ||
return typeof val === 'function' || toString.call(val) === '[object Object]'; | ||
} | ||
function isPrimitive(val) { | ||
return typeof val === 'object' ? val === null : typeof val !== 'function'; | ||
} | ||
}); | ||
/** | ||
* Parse a text-file and convert it to an array of XY points | ||
* @param {string} text - csv or tsv strings | ||
* @param {object} [options={}] | ||
* @param {boolean} [options.rescale = false] - will set the maximum value to 1 | ||
* @param {boolean} [options.uniqueX = false] - Make the X values unique (works only with 'xxyy' format). If the X value is repeated the sum of Y is done. | ||
* @param {number} [options.xColumn = 0] - A number that specifies the x column | ||
* @param {number} [options.yColumn = 1] - A number that specifies the y column | ||
* @param {boolean} [options.bestGuess=false] Will try to guess which columns are the best | ||
* @param {number} [options.numberColumns=Number.MAX_SAFE_INTEGER] If the file has 10 columns and you specify here 2 it will reflow the file | ||
* @param {number} [options.maxNumberColumns = (Math.max(xColumn, yColumn)+1)] - A number that specifies the maximum number of y columns | ||
* @param {number} [options.minNumberColumns = (Math.min(xColumn, yColumn)+1)] - A number that specifies the minimum number of y columns | ||
* @param {boolean} [options.keepInfo = false] - shoud we keep the non numeric lines. In this case the system will return an object {data, info} | ||
* @return {object{x:<Array<number>>,y:<Array<number>>} | ||
*/ | ||
function parseXY(text, options = {}) { | ||
let { | ||
rescale = false, | ||
uniqueX: uniqueX$1 = false, | ||
xColumn = 0, | ||
yColumn = 1, | ||
keepInfo = false, | ||
bestGuess = false, | ||
numberColumns = Number.MAX_SAFE_INTEGER, | ||
maxNumberColumns = Number.MAX_SAFE_INTEGER, | ||
minNumberColumns = 2, | ||
} = options; | ||
text = ensureString(text); | ||
maxNumberColumns = Math.max(maxNumberColumns, xColumn + 1, yColumn + 1); | ||
minNumberColumns = Math.max(xColumn + 1, yColumn + 1, minNumberColumns); | ||
let lines = text.split(/[\r\n]+/); | ||
let matrix = []; | ||
let info = []; | ||
let position = 0; | ||
for (let l = 0; l < lines.length; l++) { | ||
let line = lines[l].trim(); | ||
// we will consider only lines that contains only numbers | ||
if (line.match(/[0-9]+/) && line.match(/^[0-9eE,;. \t+-]+$/)) { | ||
let fields = line.split(/,[; \t]+|[; \t]+/); | ||
if (fields.length === 1) { | ||
fields = line.split(/[,; \t]+/); | ||
} | ||
if ( | ||
fields && | ||
fields.length >= minNumberColumns && // we filter lines that have not enough or too many columns | ||
fields.length <= maxNumberColumns | ||
) { | ||
matrix.push(fields.map((value) => parseFloat(value.replace(",", ".")))); | ||
position++; | ||
} | ||
} else if (line) { | ||
info.push({ position, value: line }); | ||
} | ||
} | ||
if (bestGuess) { | ||
if ( | ||
matrix[0] && | ||
matrix[0].length === 3 && | ||
options.xColumn === undefined && | ||
options.yColumn === undefined | ||
) { | ||
// is the first column a seuqnetial number ? | ||
let skipFirstColumn = true; | ||
for (let i = 0; i < matrix.length - 1; i++) { | ||
if (Math.abs(matrix[i][0] - matrix[i + 1][0]) !== 1) { | ||
skipFirstColumn = false; | ||
} | ||
} | ||
if (skipFirstColumn) { | ||
xColumn = 1; | ||
yColumn = 2; | ||
} | ||
} | ||
if (matrix[0] && matrix[0].length > 3) { | ||
let xs = []; | ||
for (let row of matrix) { | ||
for (let i = xColumn; i < row.length; i += 2) { | ||
xs.push(row[i]); | ||
} | ||
} | ||
if (xIsMonotone(xs)) { | ||
numberColumns = 2; | ||
} | ||
} | ||
} | ||
if (numberColumns) { | ||
const newMatrix = []; | ||
for (const row of matrix) { | ||
for (let i = 0; i < row.length; i += numberColumns) { | ||
newMatrix.push(row.slice(i, i + numberColumns)); | ||
} | ||
} | ||
matrix = newMatrix; | ||
} | ||
const result = { | ||
x: matrix.map((row) => row[xColumn]), | ||
y: matrix.map((row) => row[yColumn]), | ||
}; | ||
if (uniqueX$1) { | ||
uniqueX(result); | ||
} | ||
if (rescale) { | ||
let maxY = max(result.y); | ||
for (let i = 0; i < result.y.length; i++) { | ||
result.y[i] /= maxY; | ||
} | ||
} | ||
if (!keepInfo) return result; | ||
return { | ||
info, | ||
data: result, | ||
}; | ||
} | ||
exports.parseXY = parseXY; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "xy-parser", | ||
"version": "3.2.0", | ||
"version": "4.0.0", | ||
"description": "Parse a text-file and convert it to an array of XY points", | ||
"main": "lib/index.js", | ||
"module": "src/index.js", | ||
"main": "./lib/index.js", | ||
"module": "./lib-esm/index.js", | ||
"types": "./lib/index.d.ts", | ||
"files": [ | ||
"lib", | ||
"src" | ||
"src", | ||
"lib-esm" | ||
], | ||
"scripts": { | ||
"build": "rollup -c && cheminfo-build --root XYParser", | ||
"build-doc": "cheminfo doc", | ||
"check-types": "tsc --noEmit", | ||
"clean": "rimraf lib lib-esm", | ||
"eslint": "eslint src", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"prepublishOnly": "rollup -c", | ||
"test": "npm run testonly && npm run eslint", | ||
"prepack": "npm run tsc", | ||
"prettier": "prettier --check src", | ||
"prettier-write": "prettier --write src", | ||
"test": "npm run test-only && npm run eslint && npm run check-types", | ||
"test-coverage": "jest --coverage", | ||
"testonly": "jest" | ||
"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" | ||
}, | ||
@@ -35,29 +43,21 @@ "repository": { | ||
"homepage": "https://github.com/cheminfo/xy-parser#readme", | ||
"jest": { | ||
"testEnvironment": "node" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^26.0.24", | ||
"@types/jest": "^27.0.2", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", | ||
"cheminfo-build": "^1.1.11", | ||
"cheminfo-tools": "^1.23.3", | ||
"codecov": "^3.8.2", | ||
"eslint": "^7.30.0", | ||
"eslint-config-cheminfo": "^5.2.4", | ||
"eslint-plugin-import": "^2.23.4", | ||
"eslint-plugin-jest": "^24.3.6", | ||
"eslint-plugin-no-only-tests": "^2.6.0", | ||
"eslint-plugin-prettier": "^3.4.0", | ||
"jest": "^27.0.6", | ||
"prettier": "^2.3.2", | ||
"rollup": "^2.53.1", | ||
"rollup-plugin-commonjs": "^10.1.0", | ||
"rollup-plugin-node-resolve": "^5.2.0" | ||
"codecov": "^3.8.3", | ||
"eslint": "^8.2.0", | ||
"eslint-config-cheminfo-typescript": "^10.2.2", | ||
"jest": "^27.3.1", | ||
"prettier": "^2.4.1", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^27.0.7", | ||
"typescript": "^4.4.4" | ||
}, | ||
"dependencies": { | ||
"ensure-string": "^0.1.1", | ||
"ensure-string": "^1.1.0", | ||
"ml-array-max": "^1.2.3", | ||
"ml-arrayxy-uniquex": "1.0.2", | ||
"ml-spectra-processing": "^6.7.1" | ||
"ml-spectra-processing": "^6.8.0" | ||
} | ||
} |
@@ -15,5 +15,6 @@ # xy-parser | ||
[![NPM version][npm-image]][npm-url] | ||
[![Test coverage][codecov-image]][codecov-url] | ||
[![npm download][download-image]][download-url] | ||
[![NPM version][npm-image]][npm-url] | ||
[![Test coverage][codecov-image]][codecov-url] | ||
[![npm download][download-image]][download-url] | ||
[![DOI](https://www.zenodo.org/badge/35540080.svg)](https://www.zenodo.org/badge/latestdoi/35540080) | ||
@@ -59,3 +60,3 @@ </h3> | ||
If there are 3 columns and the first column is a sequential number starting at '1' it looks | ||
If there are 3 columns and the first column is a sequential number starting at '1' it looks | ||
like this is a line number, we will ignore it. | ||
@@ -62,0 +63,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
38744
11
18
77
0
642
1
+ Addedcheminfo-types@1.8.1(transitive)
+ Addedensure-string@1.2.0(transitive)
+ Addedisutf8@4.0.1(transitive)
- Removedensure-string@0.1.1(transitive)
Updatedensure-string@^1.1.0
Updatedml-spectra-processing@^6.8.0