Comparing version 3.0.0 to 3.1.0
@@ -0,1 +1,13 @@ | ||
## [3.1.0](https://github.com/cheminfo/xy-parser/compare/v3.0.0...v3.1.0) (2021-03-19) | ||
### Features | ||
* add bestGuess and numberColumns options ([3bf5f86](https://github.com/cheminfo/xy-parser/commit/3bf5f8687d67b5c34921a11f184214d056ba4383)) | ||
### Bug Fixes | ||
* improve readme ([0889efc](https://github.com/cheminfo/xy-parser/commit/0889efce4a4ef27ab58bd685442066a9fe8ef449)) | ||
0.0.0 / HEAD | ||
@@ -2,0 +14,0 @@ ============ |
689
lib/index.js
@@ -5,2 +5,41 @@ 'use strict'; | ||
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; | ||
} | ||
/** | ||
@@ -40,3 +79,586 @@ * In place modification of the 2 arrays to make X unique and sum the Y if X has the same value | ||
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; | ||
} | ||
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; | ||
} | ||
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); | ||
} | ||
} | ||
} | ||
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 (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; | ||
}; | ||
} | ||
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; | ||
} | ||
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]); | ||
} | ||
} | ||
return bins; | ||
} | ||
histogram.value = function(_) { | ||
return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), histogram) : value; | ||
}; | ||
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 | ||
@@ -49,2 +671,4 @@ * @param {string} text - csv or tsv strings | ||
* @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 | ||
@@ -62,2 +686,4 @@ * @param {number} [options.minNumberColumns = (Math.min(xColumn, yColumn)+1)] - A number that specifies the minimum number of y columns | ||
keepInfo = false, | ||
bestGuess = false, | ||
numberColumns = Number.MAX_SAFE_INTEGER, | ||
maxNumberColumns = Number.MAX_SAFE_INTEGER, | ||
@@ -72,5 +698,5 @@ minNumberColumns = 2, | ||
let maxY = Number.MIN_VALUE; | ||
let result = { x: [], y: [] }; | ||
let matrix = []; | ||
let info = []; | ||
let position = 0; | ||
for (let l = 0; l < lines.length; l++) { | ||
@@ -86,17 +712,59 @@ let line = lines[l].trim(); | ||
fields && | ||
fields.length >= minNumberColumns && | ||
fields.length >= minNumberColumns && // we filter lines that have not enough or too many columns | ||
fields.length <= maxNumberColumns | ||
) { | ||
let x = parseFloat(fields[xColumn].replace(',', '.')); | ||
let y = parseFloat(fields[yColumn].replace(',', '.')); | ||
if (y > maxY) maxY = y; | ||
result.x.push(x); | ||
result.y.push(y); | ||
matrix.push(fields.map((value) => parseFloat(value.replace(',', '.')))); | ||
position++; | ||
} | ||
} else if (line) { | ||
info.push({ position: result.x.length, value: 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) { | ||
@@ -107,2 +775,3 @@ uniqueX(result); | ||
if (rescale) { | ||
let maxY = max(result.y); | ||
for (let i = 0; i < result.y.length; i++) { | ||
@@ -109,0 +778,0 @@ result.y[i] /= maxY; |
{ | ||
"name": "xy-parser", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"description": "Parse a text-file and convert it to an array of XY points", | ||
@@ -23,3 +23,3 @@ "main": "lib/index.js", | ||
"type": "git", | ||
"url": "git+https://github.com/cheminfo-js/xy-parser.git" | ||
"url": "git+https://github.com/cheminfo/xy-parser.git" | ||
}, | ||
@@ -33,5 +33,5 @@ "keywords": [ | ||
"bugs": { | ||
"url": "https://github.com/cheminfo-js/xy-parser/issues" | ||
"url": "https://github.com/cheminfo/xy-parser/issues" | ||
}, | ||
"homepage": "https://github.com/cheminfo-js/xy-parser#readme", | ||
"homepage": "https://github.com/cheminfo/xy-parser#readme", | ||
"jest": { | ||
@@ -41,15 +41,16 @@ "testEnvironment": "node" | ||
"devDependencies": { | ||
"@types/jest": "^26.0.21", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", | ||
"cheminfo-build": "^1.0.3", | ||
"cheminfo-build": "^1.1.10", | ||
"cheminfo-tools": "^1.23.3", | ||
"codecov": "^3.6.1", | ||
"eslint": "^6.5.1", | ||
"eslint-config-cheminfo": "^2.0.3", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-jest": "^22.17.0", | ||
"eslint-plugin-no-only-tests": "^2.3.1", | ||
"eslint-plugin-prettier": "^3.1.1", | ||
"jest": "^24.9.0", | ||
"prettier": "^1.18.2", | ||
"rollup": "^1.23.1", | ||
"codecov": "^3.8.1", | ||
"eslint": "^7.22.0", | ||
"eslint-config-cheminfo": "^5.2.3", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-jest": "^24.3.2", | ||
"eslint-plugin-no-only-tests": "^2.4.0", | ||
"eslint-plugin-prettier": "^3.3.1", | ||
"jest": "^26.6.3", | ||
"prettier": "^2.2.1", | ||
"rollup": "^2.42.0", | ||
"rollup-plugin-commonjs": "^10.1.0", | ||
@@ -59,4 +60,6 @@ "rollup-plugin-node-resolve": "^5.2.0" | ||
"dependencies": { | ||
"ml-arrayxy-uniquex": "1.0.1" | ||
"ml-array-max": "^1.2.2", | ||
"ml-arrayxy-uniquex": "1.0.2", | ||
"ml-spectra-processing": "^5.8.0" | ||
} | ||
} |
# xy-parser | ||
[![NPM version][npm-image]][npm-url] | ||
[![build status][travis-image]][travis-url] | ||
[![Test coverage][codecov-image]][codecov-url] | ||
[![npm download][download-image]][download-url] | ||
[![NPM version][npm-image]][npm-url] | ||
[![build status][travis-image]][travis-url] | ||
[![Test coverage][codecov-image]][codecov-url] | ||
[![npm download][download-image]][download-url] | ||
@@ -15,5 +15,7 @@ Parse a text-file and convert it to an array of XY points. | ||
## Usage | ||
```js | ||
import {parseXY} from 'xy-parser'; | ||
const data = `1 2 | ||
import { parseXY } from "xy-parser"; | ||
const data = `My file | ||
1 2 | ||
3 4 | ||
@@ -24,22 +26,43 @@ 5 6 | ||
/* result -> | ||
{ | ||
x: [1, 3, 5, 7], | ||
y: [2, 4, 6, 8] | ||
{ | ||
x: [1, 3, 5, 7], | ||
y: [2, 4, 6, 8] | ||
} | ||
} | ||
*/ | ||
const result2 = parseXY(data, { keepInfo: true }); | ||
/* result2 -> | ||
data: { | ||
x: [1, 3, 5, 7], | ||
y: [2, 4, 6, 8] | ||
}, | ||
info: [ | ||
'My file' | ||
] | ||
} | ||
*/ | ||
``` | ||
## [API Documentation](https://cheminfo-js.github.io/xy-parser/) | ||
The `bestGuess` option will try to determine which columns should be used. | ||
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. | ||
If there are many columns maybe we have a format like X1, Y1, X2, Y2, ... in this cases if one | ||
column on two is a monotone series we will parse it correctly. | ||
## [API Documentation](https://cheminfo.github.io/xy-parser/) | ||
## License | ||
[MIT](./LICENSE) | ||
[MIT](./LICENSE) | ||
[npm-image]: https://img.shields.io/npm/v/xy-parser.svg?style=flat-square | ||
[npm-url]: https://www.npmjs.com/package/xy-parser | ||
[travis-image]: https://img.shields.io/travis/cheminfo-js/xy-parser/master.svg?style=flat-square | ||
[travis-url]: https://travis-ci.org/cheminfo-js/xy-parser | ||
[codecov-image]: https://img.shields.io/codecov/c/github/cheminfo-js/xy-parser.svg?style=flat-square | ||
[codecov-url]: https://codecov.io/gh/cheminfo-js/xy-parser | ||
[travis-image]: https://img.shields.io/travis/cheminfo/xy-parser/master.svg?style=flat-square | ||
[travis-url]: https://travis-ci.org/cheminfo/xy-parser | ||
[codecov-image]: https://img.shields.io/codecov/c/github/cheminfo/xy-parser.svg?style=flat-square | ||
[codecov-url]: https://codecov.io/gh/cheminfo/xy-parser | ||
[download-image]: https://img.shields.io/npm/dm/xy-parser.svg?style=flat-square | ||
[download-url]: https://www.npmjs.com/package/xy-parser |
@@ -40,3 +40,3 @@ import { readFileSync } from 'fs'; | ||
test('Test with some spaces', () => { | ||
test('with some spaces', () => { | ||
let filename = 'text4.txt'; | ||
@@ -52,3 +52,3 @@ let data = readFileSync(path + filename).toString(); | ||
test('Test with some spaces and taking second and third column', () => { | ||
test('with some spaces and taking second and third column', () => { | ||
let filename = 'text5.txt'; | ||
@@ -63,3 +63,3 @@ let data = readFileSync(path + filename).toString(); | ||
test('Test with some non numeric lines', () => { | ||
test('with some non numeric lines', () => { | ||
let filename = 'text6.txt'; | ||
@@ -71,3 +71,3 @@ let data = readFileSync(path + filename).toString(); | ||
test('Test with some non numeric lines and keeping info', () => { | ||
test('with some non numeric lines and keeping info', () => { | ||
let filename = 'text6.txt'; | ||
@@ -88,3 +88,3 @@ let data = readFileSync(path + filename).toString(); | ||
test('Test with comma as decimal delimiter', () => { | ||
test('with comma as decimal delimiter', () => { | ||
let filename = 'text7.txt'; | ||
@@ -96,3 +96,3 @@ let data = readFileSync(path + filename).toString(); | ||
test('Test with scientific notation', () => { | ||
test('with scientific notation', () => { | ||
let filename = 'text8.txt'; | ||
@@ -109,3 +109,3 @@ let data = readFileSync(path + filename).toString(); | ||
test('Test large IV scientific notation file', () => { | ||
test('large IV scientific notation file', () => { | ||
let filename = 'text9.txt'; | ||
@@ -112,0 +112,0 @@ let data = readFileSync(path + filename).toString(); |
@@ -0,3 +1,4 @@ | ||
import mlArrayMax from 'ml-array-max'; | ||
import uniqueXFunction from 'ml-arrayxy-uniquex'; | ||
import { xIsMonotone } from 'ml-spectra-processing'; | ||
/** | ||
@@ -11,2 +12,4 @@ * Parse a text-file and convert it to an array of XY points | ||
* @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 | ||
@@ -24,2 +27,4 @@ * @param {number} [options.minNumberColumns = (Math.min(xColumn, yColumn)+1)] - A number that specifies the minimum number of y columns | ||
keepInfo = false, | ||
bestGuess = false, | ||
numberColumns = Number.MAX_SAFE_INTEGER, | ||
maxNumberColumns = Number.MAX_SAFE_INTEGER, | ||
@@ -34,5 +39,5 @@ minNumberColumns = 2, | ||
let maxY = Number.MIN_VALUE; | ||
let result = { x: [], y: [] }; | ||
let matrix = []; | ||
let info = []; | ||
let position = 0; | ||
for (let l = 0; l < lines.length; l++) { | ||
@@ -48,17 +53,59 @@ let line = lines[l].trim(); | ||
fields && | ||
fields.length >= minNumberColumns && | ||
fields.length >= minNumberColumns && // we filter lines that have not enough or too many columns | ||
fields.length <= maxNumberColumns | ||
) { | ||
let x = parseFloat(fields[xColumn].replace(',', '.')); | ||
let y = parseFloat(fields[yColumn].replace(',', '.')); | ||
if (y > maxY) maxY = y; | ||
result.x.push(x); | ||
result.y.push(y); | ||
matrix.push(fields.map((value) => parseFloat(value.replace(',', '.')))); | ||
position++; | ||
} | ||
} else if (line) { | ||
info.push({ position: result.x.length, value: 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) { | ||
@@ -69,2 +116,3 @@ uniqueXFunction(result); | ||
if (rescale) { | ||
let maxY = mlArrayMax(result.y); | ||
for (let i = 0; i < result.y.length; i++) { | ||
@@ -71,0 +119,0 @@ result.y[i] /= maxY; |
Sorry, the diff of this file is not supported yet
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
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
36405
10
966
67
3
16
4
+ Addedml-array-max@^1.2.2
+ Addedml-spectra-processing@^5.8.0
+ Addedassign-deep@1.0.1(transitive)
+ Addedassign-symbols@2.0.2(transitive)
+ Addedcheminfo-types@0.5.0(transitive)
+ Addedd3-array@0.7.1(transitive)
+ Addedfft.js@4.0.4(transitive)
+ Addedis-any-array@1.0.12.0.1(transitive)
+ Addedmedian-quickselect@1.0.1(transitive)
+ Addedml-array-max@1.2.4(transitive)
+ Addedml-array-mean@1.1.6(transitive)
+ Addedml-array-median@1.1.6(transitive)
+ Addedml-array-min@1.2.3(transitive)
+ Addedml-array-rescale@1.3.7(transitive)
+ Addedml-array-sequential-fill@1.1.8(transitive)
+ Addedml-array-standard-deviation@1.1.8(transitive)
+ Addedml-array-sum@1.1.6(transitive)
+ Addedml-array-variance@1.1.8(transitive)
+ Addedml-arrayxy-uniquex@1.0.2(transitive)
+ Addedml-gsd@6.9.2(transitive)
+ Addedml-levenberg-marquardt@3.1.1(transitive)
+ Addedml-matrix@6.12.0(transitive)
+ Addedml-peak-shape-generator@1.0.02.0.2(transitive)
+ Addedml-savitzky-golay-generalized@2.0.3(transitive)
+ Addedml-spectra-fitting@1.0.0(transitive)
+ Addedml-spectra-processing@5.10.06.8.0(transitive)
+ Addedspline-interpolator@1.0.0(transitive)
- Removedml-arrayxy-uniquex@1.0.1(transitive)
Updatedml-arrayxy-uniquex@1.0.2