diff --git a/.babelrc b/.babelrc index 60cad8d..52b84f7 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,7 @@ { + "presets": [ + ["@babel/env", {"modules": false}] ] -} \ No newline at end of file +} diff --git a/dist/d3-regression.cjs.js b/dist/d3-regression.cjs.js index 8271f81..ea9f596 100644 --- a/dist/d3-regression.cjs.js +++ b/dist/d3-regression.cjs.js @@ -1,873 +1,764 @@ -// https://github.com/HarryStevens/d3-regression#readme Version 1.3.10. Copyright 2022 Harry Stevens. +// https://github.com/HarryStevens/d3-regression#readme Version 1.3.10. Copyright 2025 Harry Stevens. 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); -function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); -} - -function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; -} - -function _iterableToArrayLimit(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; -} - -function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); -} - -// Adapted from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js +/** + * Adapted from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js + */ function points(data, x, y, sort) { - data = data.filter(function (d, i) { - var u = x(d, i), - v = y(d, i); - return u != null && isFinite(u) && v != null && isFinite(v); - }); - - if (sort) { - data.sort(function (a, b) { - return x(a) - x(b); + data = data.filter(function (d, i) { + var u = x(d, i), v = y(d, i); + return u != null && isFinite(u) && v != null && isFinite(v); }); - } - - var n = data.length, - X = new Float64Array(n), - Y = new Float64Array(n); // extract values, calculate means - - var ux = 0, - uy = 0, - xv, - yv, - d; - - for (var i = 0; i < n;) { - d = data[i]; - X[i] = xv = +x(d, i, data); - Y[i] = yv = +y(d, i, data); - ++i; - ux += (xv - ux) / i; - uy += (yv - uy) / i; - } // mean center the data - - - for (var _i = 0; _i < n; ++_i) { - X[_i] -= ux; - Y[_i] -= uy; - } - - return [X, Y, ux, uy]; + if (sort) { + data.sort(function (a, b) { return x(a) - x(b); }); + } + var n = data.length, X = new Float64Array(n), Y = new Float64Array(n); + // extract values, calculate means + var ux = 0, uy = 0, xv, yv, d; + for (var i = 0; i < n;) { + d = data[i]; + X[i] = xv = +x(d, i, data); + Y[i] = yv = +y(d, i, data); + ++i; + ux += (xv - ux) / i; + uy += (yv - uy) / i; + } + // mean center the data + for (var i = 0; i < n; ++i) { + X[i] -= ux; + Y[i] -= uy; + } + return [X, Y, ux, uy]; } +/** + * Iterates over valid data points, invoking a callback for each. + */ function visitPoints(data, x, y, cb) { - var iterations = 0; - - for (var i = 0, n = data.length; i < n; i++) { - var d = data[i], - dx = +x(d, i, data), - dy = +y(d, i, data); - - if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { - cb(dx, dy, iterations++); + var iterations = 0; + for (var i = 0; i < data.length; i++) { + var d = data[i]; + var dx = +x(d, i, data); + var dy = +y(d, i, data); + if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { + cb(dx, dy, iterations++); + } } - } } -// return the coefficient of determination, or R squared. - +/** + * Given a dataset, x- and y-accessors, the mean center of the y-values (uY), + * and a prediction function, return the coefficient of determination, R^2. + */ function determination(data, x, y, uY, predict) { - var SSE = 0, - SST = 0; - visitPoints(data, x, y, function (dx, dy) { - var sse = dy - predict(dx), - sst = dy - uY; - SSE += sse * sse; - SST += sst * sst; - }); - return 1 - SSE / SST; + var SSE = 0, // Sum of Squared Errors + SST = 0; // Total Sum of Squares + visitPoints(data, x, y, function (dx, dy) { + var sse = dy - predict(dx); + var sst = dy - uY; + SSE += sse * sse; + SST += sst * sst; + }); + return 1 - SSE / SST; } -// Returns the angle of a line in degrees. +/** + * Returns the angle of a line in degrees. + */ function angle(line) { - return Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * 180 / Math.PI; -} // Returns the midpoint of a line. - + return (Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * + (180 / Math.PI)); +} +/** + * Returns the midpoint of a line. + */ function midpoint(line) { - return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2]; + return [ + (line[0][0] + line[1][0]) / 2, + (line[0][1] + line[1][1]) / 2 + ]; } -// returns a smooth line. - +/** + * Given a start point (xmin), an end point (xmax), + * and a prediction function, returns a smooth line. + */ function interpose(xmin, xmax, predict) { - var l = Math.log(xmax - xmin) * Math.LOG10E + 1 | 0; - var precision = 1 * Math.pow(10, -l / 2 - 1), - maxIter = 1e4; - var points = [px(xmin), px(xmax)], - iter = 0; - - while (find(points) && iter < maxIter) { - } - - return points; - - function px(x) { - return [x, predict(x)]; - } - - function find(points) { - iter++; - var n = points.length; - var found = false; - - for (var i = 0; i < n - 1; i++) { - var p0 = points[i], - p1 = points[i + 1], - m = midpoint([p0, p1]), - mp = px(m[0]), - a0 = angle([p0, m]), - a1 = angle([p0, mp]), - a = Math.abs(a0 - a1); - - if (a > precision) { - points.splice(i + 1, 0, mp); - found = true; - } + var l = (Math.log(xmax - xmin) * Math.LOG10E + 1) | 0; + var precision = Math.pow(10, -l / 2 - 1); + var maxIter = 1e4; + var points = [px(xmin), px(xmax)]; + var iter = 0; + while (find(points) && iter < maxIter) + ; + return points; + function px(x) { + return [x, predict(x)]; + } + function find(points) { + iter++; + var n = points.length; + var found = false; + for (var i = 0; i < n - 1; i++) { + var p0 = points[i]; + var p1 = points[i + 1]; + var m = midpoint([p0, p1]); + var mp = px(m[0]); + var a0 = angle([p0, m]); + var a1 = angle([p0, mp]); + var a = Math.abs(a0 - a1); + if (a > precision) { + points.splice(i + 1, 0, mp); + found = true; + } + } + return found; } - - return found; - } } -// Ordinary Least Squares from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js +/** + * Ordinary Least Squares from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js + */ function ols(uX, uY, uXY, uX2) { - var delta = uX2 - uX * uX, - slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, - intercept = uY - slope * uX; - return [intercept, slope]; + var delta = uX2 - uX * uX, slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, intercept = uY - slope * uX; + return [intercept, slope]; } -function exponential () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function exponential(data) { - var n = 0, - Y = 0, - YL = 0, - XY = 0, - XYL = 0, - X2Y = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - var ly = Math.log(dy), - xy = dx * dy; - ++n; - Y += (dy - Y) / n; - XY += (xy - XY) / n; - X2Y += (dx * xy - X2Y) / n; - YL += (dy * ly - YL) / n; - XYL += (xy * ly - XYL) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - a = Math.exp(a); - - var fn = function fn(x) { - return a * Math.exp(b * x); - }, - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - exponential.domain = function (arr) { - return arguments.length ? (domain = arr, exponential) : domain; - }; - - exponential.x = function (fn) { - return arguments.length ? (x = fn, exponential) : x; - }; - - exponential.y = function (fn) { - return arguments.length ? (y = fn, exponential) : y; - }; - - return exponential; +function exponential() { + var y = function (d) { return d[1]; }, x = function (d) { return d[0]; }, domain; + var exponentialRegression = function (data) { + var n = 0, Y = 0, YL = 0, XY = 0, XYL = 0, X2Y = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + var ly = Math.log(dy), xy = dx * dy; + ++n; + Y += (dy - Y) / n; + XY += (xy - XY) / n; + X2Y += (dx * xy - X2Y) / n; + YL += (dy * ly - YL) / n; + XYL += (xy * ly - XYL) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), a = _a[0], b = _a[1]; + a = Math.exp(a); + var fn = function (xx) { return a * Math.exp(b * xx); }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + exponentialRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return exponentialRegression; + }; + exponentialRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return exponentialRegression; + }; + exponentialRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return exponentialRegression; + }; + return exponentialRegression; } -function linear () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function linear(data) { - var n = 0, - X = 0, - // sum of x - Y = 0, - // sum of y - XY = 0, - // sum of x * y - X2 = 0, - // sum of x * x - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - ++n; - X += (dx - X) / n; - Y += (dy - Y) / n; - XY += (dx * dy - XY) / n; - X2 += (dx * dx - X2) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - intercept = _ols2[0], - slope = _ols2[1], - fn = function fn(x) { - return slope * x + intercept; - }, - out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - linear.domain = function (arr) { - return arguments.length ? (domain = arr, linear) : domain; - }; - - linear.x = function (fn) { - return arguments.length ? (x = fn, linear) : x; - }; - - linear.y = function (fn) { - return arguments.length ? (y = fn, linear) : y; - }; - - return linear; +function linear() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var linearRegression = function (data) { + var n = 0, X = 0, // sum of x + Y = 0, // sum of y + XY = 0, // sum of x*y + X2 = 0, // sum of x*x + xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + ++n; + X += (dx - X) / n; + Y += (dy - Y) / n; + XY += (dx * dy - XY) / n; + X2 += (dx * dx - X2) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), intercept = _a[0], slope = _a[1]; + var fn = function (xx) { return slope * xx + intercept; }; + var out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + linearRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return linearRegression; + }; + linearRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return linearRegression; + }; + linearRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return linearRegression; + }; + return linearRegression; } -// Returns the medium value of an array of numbers. +/** + * Returns the median value of an array of numbers. + */ function median(arr) { - arr.sort(function (a, b) { - return a - b; - }); - var i = arr.length / 2; - return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; + arr.sort(function (a, b) { return a - b; }); + var i = arr.length / 2; + return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; } -var maxiters = 2, - epsilon = 1e-12; -function loess () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - bandwidth = .3; - - function loess(data) { - var _points = points(data, x, y, true), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length, - bw = Math.max(2, ~~(bandwidth * n)), - yhat = new Float64Array(n), - residuals = new Float64Array(n), - robustWeights = new Float64Array(n).fill(1); - - for (var iter = -1; ++iter <= maxiters;) { - var interval = [0, bw - 1]; - - for (var i = 0; i < n; ++i) { - var dx = xv[i], - i0 = interval[0], - i1 = interval[1], - edge = dx - xv[i0] > xv[i1] - dx ? i0 : i1; - var W = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - denom = 1 / Math.abs(xv[edge] - dx || 1); // Avoid singularity - - for (var k = i0; k <= i1; ++k) { - var xk = xv[k], - yk = yv[k], - w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k], - xkw = xk * w; - W += w; - X += xkw; - Y += yk * w; - XY += yk * xkw; - X2 += xk * xkw; - } // Linear regression fit - - - var _ols = ols(X / W, Y / W, XY / W, X2 / W), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - yhat[i] = a + b * dx; - residuals[i] = Math.abs(yv[i] - yhat[i]); - updateInterval(xv, i + 1, interval); - } - - if (iter === maxiters) { - break; - } - - var medianResidual = median(residuals); - if (Math.abs(medianResidual) < epsilon) break; - - for (var _i = 0, arg, _w; _i < n; ++_i) { - arg = residuals[_i] / (6 * medianResidual); // Default to epsilon (rather than zero) for large deviations - // Keeping weights tiny but non-zero prevents singularites - - robustWeights[_i] = arg >= 1 ? epsilon : (_w = 1 - arg * arg) * _w; - } - } - - return output(xv, yhat, ux, uy); - } - - loess.bandwidth = function (bw) { - return arguments.length ? (bandwidth = bw, loess) : bandwidth; - }; - - loess.x = function (fn) { - return arguments.length ? (x = fn, loess) : x; - }; - - loess.y = function (fn) { - return arguments.length ? (y = fn, loess) : y; - }; - - return loess; -} // Weighting kernel for local regression - +// Adapted from science.js by Jason Davies +var maxiters = 2, epsilon = 1e-12; +function loess() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, bandwidth = 0.3; + var loessRegression = function loessRegression(data) { + var _a = points(data, function (dd) { return x(dd); }, function (dd) { return y(dd); }, true), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var bw = Math.max(2, ~~(bandwidth * n)); // # of nearest neighbors + var yhat = new Float64Array(n); + var residuals = new Float64Array(n); + var robustWeights = new Float64Array(n).fill(1); + for (var iter = -1; ++iter <= maxiters;) { + var interval = [0, bw - 1]; + for (var i = 0; i < n; ++i) { + var dx = xv[i]; + var i0 = interval[0]; + var i1 = interval[1]; + var edge = (dx - xv[i0]) > (xv[i1] - dx) ? i0 : i1; + var W = 0, X = 0, Y = 0, XY = 0, X2 = 0; + var denom = 1 / Math.abs(xv[edge] - dx || 1); + for (var k = i0; k <= i1; ++k) { + var xk = xv[k]; + var yk = yv[k]; + var w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k]; + var xkw = xk * w; + W += w; + X += xkw; + Y += yk * w; + XY += yk * xkw; + X2 += xk * xkw; + } + // Linear regression fit + var _b = ols(X / W, Y / W, XY / W, X2 / W), a = _b[0], b = _b[1]; + yhat[i] = a + b * dx; + residuals[i] = Math.abs(yv[i] - yhat[i]); + updateInterval(xv, i + 1, interval); + } + if (iter === maxiters) { + break; + } + var medianResidual = median(residuals); + if (Math.abs(medianResidual) < epsilon) + break; + for (var i = 0, arg = void 0, w = void 0; i < n; ++i) { + arg = residuals[i] / (6 * medianResidual); + // Default to epsilon (rather than zero) for large deviations + // Keeping weights tiny but non-zero prevents singularites + robustWeights[i] = (arg >= 1) ? epsilon : ((w = 1 - arg * arg) * w); + } + } + return output(xv, yhat, ux, uy); + }; + loessRegression.bandwidth = function (bw) { + if (!arguments.length) + return bandwidth; + bandwidth = bw; + return loessRegression; + }; + loessRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return loessRegression; + }; + loessRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return loessRegression; + }; + return loessRegression; +} +// Weighting kernel for local regression function tricube(x) { - return (x = 1 - x * x * x) * x * x; -} // Advance sliding window interval of nearest neighbors - - + return (x = 1 - x * x * x) * x * x; +} +// Advance sliding window interval of nearest neighbors function updateInterval(xv, i, interval) { - var val = xv[i], - left = interval[0], - right = interval[1] + 1; - if (right >= xv.length) return; // Step right if distance to new right edge is <= distance to old left edge - // Step when distance is equal to ensure movement over duplicate x values - - while (i > left && xv[right] - val <= val - xv[left]) { - interval[0] = ++left; - interval[1] = right; - ++right; - } -} // Generate smoothed output points + var val = xv[i], left = interval[0], right = interval[1] + 1; + if (right >= xv.length) + return; + // Step right if distance to new right edge is <= distance to old left edge + // Step when distance is equal to ensure movement over duplicate x values + while (i > left && (xv[right] - val) <= (val - xv[left])) { + interval[0] = ++left; + interval[1] = right; + ++right; + } +} +// Generate smoothed output points // Average points with repeated x values - - function output(xv, yhat, ux, uy) { - var n = xv.length, - out = []; - var i = 0, - cnt = 0, - prev = [], - v; - - for (; i < n; ++i) { - v = xv[i] + ux; - - if (prev[0] === v) { - // Average output values via online update - prev[1] += (yhat[i] - prev[1]) / ++cnt; - } else { - // Add new output point - cnt = 0; - prev[1] += uy; - prev = [v, yhat[i]]; - out.push(prev); + var n = xv.length, out = []; + var i = 0, cnt = 0, prev = [], v; + for (; i < n; ++i) { + v = xv[i] + ux; + if (prev[0] === v) { + // Average output values via online update + prev[1] += (yhat[i] - prev[1]) / (++cnt); + } + else { + // Add new output point + cnt = 0; + prev[1] += uy; + prev = [v, yhat[i]]; + out.push(prev); + } } - } - - prev[1] += uy; - return out; -} - -function logarithmic () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - base = Math.E, - domain; - - function logarithmic(data) { - var n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity, - lb = Math.log(base); - visitPoints(data, x, y, function (dx, dy) { - var lx = Math.log(dx) / lb; - ++n; - X += (lx - X) / n; - Y += (dy - Y) / n; - XY += (lx * dy - XY) / n; - X2 += (lx * lx - X2) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - intercept = _ols2[0], - slope = _ols2[1], - fn = function fn(x) { - return slope * Math.log(x) / lb + intercept; - }, - out = interpose(xmin, xmax, fn); - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); + prev[1] += uy; return out; - } - - logarithmic.domain = function (arr) { - return arguments.length ? (domain = arr, logarithmic) : domain; - }; - - logarithmic.x = function (fn) { - return arguments.length ? (x = fn, logarithmic) : x; - }; - - logarithmic.y = function (fn) { - return arguments.length ? (y = fn, logarithmic) : y; - }; - - logarithmic.base = function (n) { - return arguments.length ? (base = n, logarithmic) : base; - }; - - return logarithmic; } -function quad () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function quadratic(data) { - var _points = points(data, x, y), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length; - - var X2 = 0, - X3 = 0, - X4 = 0, - XY = 0, - X2Y = 0, - i, - dx, - dy, - x2; - - for (i = 0; i < n;) { - dx = xv[i]; - dy = yv[i++]; - x2 = dx * dx; - X2 += (x2 - X2) / i; - X3 += (x2 * dx - X3) / i; - X4 += (x2 * x2 - X4) / i; - XY += (dx * dy - XY) / i; - X2Y += (x2 * dy - X2Y) / i; - } - - var Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - n0++; - Y += (dy - Y) / n0; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var X2X2 = X4 - X2 * X2, - d = X2 * X2X2 - X3 * X3, - a = (X2Y * X2 - XY * X3) / d, - b = (XY * X2X2 - X2Y * X3) / d, - c = -a * X2, - fn = function fn(x) { - x = x - ux; - return a * x * x + b * x + c + uy; +function logarithmic() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, base = Math.E, domain; + var logarithmicRegression = function (data) { + var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity, lb = Math.log(base); + visitPoints(data, x, y, function (dx, dy) { + var lx = Math.log(dx) / lb; + ++n; + X += (lx - X) / n; + Y += (dy - Y) / n; + XY += (lx * dy - XY) / n; + X2 += (lx * lx - X2) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), intercept = _a[0], slope = _a[1]; + var fn = function (xx) { return slope * Math.log(xx) / lb + intercept; }; + var out = interpose(xmin, xmax, fn); + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; }; - - var out = interpose(xmin, xmax, fn); - out.a = a; - out.b = b - 2 * a * ux; - out.c = c - b * ux + a * ux * ux + uy; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - quadratic.domain = function (arr) { - return arguments.length ? (domain = arr, quadratic) : domain; - }; - - quadratic.x = function (fn) { - return arguments.length ? (x = fn, quadratic) : x; - }; - - quadratic.y = function (fn) { - return arguments.length ? (y = fn, quadratic) : y; - }; - - return quadratic; + logarithmicRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return logarithmicRegression; + }; + logarithmicRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return logarithmicRegression; + }; + logarithmicRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return logarithmicRegression; + }; + logarithmicRegression.base = function (b) { + if (!arguments.length) + return base; + base = b; + return logarithmicRegression; + }; + return logarithmicRegression; } -// Source: https://github.com/Tom-Alexander/regression-js/blob/master/src/regression.js#L246 -// License: https://github.com/Tom-Alexander/regression-js/blob/master/LICENSE -// ...with ideas from vega-statistics by Jeffrey Heer -// Source: https://github.com/vega/vega/blob/f21cb8792b4e0cbe2b1a3fd44b0f5db370dbaadb/packages/vega-statistics/src/regression/poly.js -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE - -function polynomial () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - order = 3, - domain; - - function polynomial(data) { - // Use more efficient methods for lower orders - if (order === 1) { - var o = linear().x(x).y(y).domain(domain)(data); - o.coefficients = [o.b, o.a]; - delete o.a; - delete o.b; - return o; - } - - if (order === 2) { - var _o = quad().x(x).y(y).domain(domain)(data); - - _o.coefficients = [_o.c, _o.b, _o.a]; - delete _o.a; - delete _o.b; - delete _o.c; - return _o; - } - - var _points = points(data, x, y), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length, - lhs = [], - rhs = [], - k = order + 1; - - var Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - ++n0; - Y += (dy - Y) / n0; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - var i, j, l, v, c; - - for (i = 0; i < k; ++i) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i) * yv[l]; - } - - lhs.push(v); - c = new Float64Array(k); - - for (j = 0; j < k; ++j) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i + j); +function quadratic() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var quadraticRegression = function quadraticRegression(data) { + var _a = points(data, function (dd) { return x(dd); }, function (dd) { return y(dd); }), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var X2 = 0, X3 = 0, X4 = 0, XY = 0, X2Y = 0, i, dx, dy, x2; + for (i = 0; i < n;) { + dx = xv[i]; + dy = yv[i++]; + x2 = dx * dx; + X2 += (x2 - X2) / i; + X3 += ((x2 * dx) - X3) / i; + X4 += ((x2 * x2) - X4) / i; + XY += ((dx * dy) - XY) / i; + X2Y += ((x2 * dy) - X2Y) / i; } - - c[j] = v; - } - - rhs.push(c); - } - - rhs.push(lhs); - - var coef = gaussianElimination(rhs), - fn = function fn(x) { - x -= ux; - var y = uy + coef[0] + coef[1] * x + coef[2] * x * x; - - for (i = 3; i < k; ++i) { - y += coef[i] * Math.pow(x, i); - } - - return y; - }, - out = interpose(xmin, xmax, fn); - - out.coefficients = uncenter(k, coef, -ux, uy); - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - polynomial.domain = function (arr) { - return arguments.length ? (domain = arr, polynomial) : domain; - }; - - polynomial.x = function (fn) { - return arguments.length ? (x = fn, polynomial) : x; - }; - - polynomial.y = function (fn) { - return arguments.length ? (y = fn, polynomial) : y; - }; - - polynomial.order = function (n) { - return arguments.length ? (order = n, polynomial) : order; - }; - - return polynomial; + var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx2, dy2) { + n0++; + Y += (dy2 - Y) / n0; + if (!domain) { + if (dx2 < xmin) + xmin = dx2; + if (dx2 > xmax) + xmax = dx2; + } + }); + var X2X2 = X4 - (X2 * X2); + var d = (X2 * X2X2 - X3 * X3); + var a = (X2Y * X2 - XY * X3) / d; + var b = (XY * X2X2 - X2Y * X3) / d; + var c = -a * X2; + var fn = function (xx) { + var shifted = xx - ux; + return a * shifted * shifted + b * shifted + c + uy; + }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b - 2 * a * ux; + out.c = c - b * ux + a * ux * ux + uy; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + quadraticRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return quadraticRegression; + }; + quadraticRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return quadraticRegression; + }; + quadraticRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return quadraticRegression; + }; + return quadraticRegression; } +// Adapted from regression-js by Tom Alexander +function polynomial() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, order = 3, domain; + var polynomialRegression = function polynomialRegression(data) { + // Shortcut for lower-order polynomials: + if (order === 1) { + var o = linear().x(x).y(y).domain(domain)(data); + var result = [o[0], o[1]]; + result.coefficients = [o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + if (order === 2) { + var o = quadratic().x(x).y(y).domain(domain)(data); + var result = [o[0], o[1]]; + result.coefficients = [o.c, o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + var _a = points(data, x, y), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var k = order + 1; + var lhs = []; + var rhs = []; + var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + n0++; + Y += (dy - Y) / n0; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + // Build normal equations + for (var i = 0; i < k; i++) { + // LHS + var v = 0; + for (var l = 0; l < n; l++) { + v += Math.pow(xv[l], i) * yv[l]; + } + lhs.push(v); + // RHS + var c = new Float64Array(k); + for (var j = 0; j < k; j++) { + var v2 = 0; + for (var l = 0; l < n; l++) { + v2 += Math.pow(xv[l], i + j); + } + c[j] = v2; + } + rhs.push(c); + } + rhs.push(new Float64Array(lhs)); + var coef = gaussianElimination(rhs); + var fn = function (xx) { + var shifted = xx - ux; + var val = uy + coef[0]; + for (var i = 1; i < k; i++) { + val += coef[i] * Math.pow(shifted, i); + } + return val; + }; + var out = interpose(xmin, xmax, fn); + out.coefficients = uncenter(k, coef, -ux, uy); + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + polynomialRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return polynomialRegression; + }; + polynomialRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return polynomialRegression; + }; + polynomialRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return polynomialRegression; + }; + polynomialRegression.order = function (n) { + if (!arguments.length) + return order; + order = n; + return polynomialRegression; + }; + return polynomialRegression; +} function uncenter(k, a, x, y) { - var z = Array(k); - var i, j, v, c; // initialize to zero - - for (i = 0; i < k; ++i) { - z[i] = 0; - } // polynomial expansion - - - for (i = k - 1; i >= 0; --i) { - v = a[i]; - c = 1; - z[i] += v; - - for (j = 1; j <= i; ++j) { - c *= (i + 1 - j) / j; // binomial coefficent - - z[i - j] += v * Math.pow(x, j) * c; + var z = new Array(k).fill(0); + for (var i = k - 1; i >= 0; --i) { + var v = a[i]; + z[i] += v; + var c = 1; + for (var j = 1; j <= i; ++j) { + c *= (i + 1 - j) / j; // binomial coefficient + z[i - j] += v * Math.pow(x, j) * c; + } } - } // bias term - - - z[0] += y; - return z; -} // Given an array for a two-dimensional matrix and the polynomial order, -// solve A * x = b using Gaussian elimination. - - + // bias term + z[0] += y; + return z; +} +// Solve A * x = b using Gaussian elimination function gaussianElimination(matrix) { - var n = matrix.length - 1, - coef = []; - var i, j, k, r, t; - - for (i = 0; i < n; ++i) { - r = i; // max row - - for (j = i + 1; j < n; ++j) { - if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { - r = j; - } - } - - for (k = i; k < n + 1; ++k) { - t = matrix[k][i]; - matrix[k][i] = matrix[k][r]; - matrix[k][r] = t; - } - - for (j = i + 1; j < n; ++j) { - for (k = n; k >= i; k--) { - matrix[k][j] -= matrix[k][i] * matrix[i][j] / matrix[i][i]; - } + var n = matrix.length - 1; + var coef = new Array(n); + for (var i = 0; i < n; i++) { + var r = i; + // find pivot row + for (var j = i + 1; j < n; j++) { + if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { + r = j; + } + } + // swap columns + for (var k = i; k < n + 1; k++) { + var t = matrix[k][i]; + matrix[k][i] = matrix[k][r]; + matrix[k][r] = t; + } + // reduce + for (var j = i + 1; j < n; j++) { + for (var k = n; k >= i; k--) { + matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i]; + } + } } - } - - for (j = n - 1; j >= 0; --j) { - t = 0; - - for (k = j + 1; k < n; ++k) { - t += matrix[k][j] * coef[k]; + for (var j = n - 1; j >= 0; j--) { + var t = 0; + for (var k = j + 1; k < n; k++) { + t += matrix[k][j] * coef[k]; + } + coef[j] = (matrix[n][j] - t) / matrix[j][j]; } - - coef[j] = (matrix[n][j] - t) / matrix[j][j]; - } - - return coef; + return coef; } -function power () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function power(data) { - var n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - YS = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - var lx = Math.log(dx), - ly = Math.log(dy); - ++n; - X += (lx - X) / n; - Y += (ly - Y) / n; - XY += (lx * ly - XY) / n; - X2 += (lx * lx - X2) / n; - YS += (dy - YS) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - a = Math.exp(a); - - var fn = function fn(x) { - return a * Math.pow(x, b); - }, - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, YS, fn); - return out; - } - - power.domain = function (arr) { - return arguments.length ? (domain = arr, power) : domain; - }; - - power.x = function (fn) { - return arguments.length ? (x = fn, power) : x; - }; - - power.y = function (fn) { - return arguments.length ? (y = fn, power) : y; - }; +function power() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var powerRegression = function powerRegression(data) { + var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, YS = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + var lx = Math.log(dx), ly = Math.log(dy); + ++n; + X += (lx - X) / n; + Y += (ly - Y) / n; + XY += (lx * ly - XY) / n; + X2 += (lx * lx - X2) / n; + YS += (dy - YS) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), a = _a[0], b = _a[1]; + a = Math.exp(a); + var fn = function (xx) { return a * Math.pow(xx, b); }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, YS, fn); + return out; + }; + powerRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return powerRegression; + }; + powerRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return powerRegression; + }; + powerRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return powerRegression; + }; + return powerRegression; +} - return power; +function sigmoidal() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain, maxIter = 2000, alpha = 1e-4; // learning rate + function sigmoidalRegression(data) { + var n = 0, Xmin = domain ? +domain[0] : Infinity, Xmax = domain ? +domain[1] : -Infinity, Ymin = Infinity, Ymax = -Infinity, sumY = 0; + // Gather data & track min/max for domain if not preset + visitPoints(data, x, y, function (dx, dy) { + n++; + sumY += dy; + if (!domain) { + if (dx < Xmin) + Xmin = dx; + if (dx > Xmax) + Xmax = dx; + } + if (dy < Ymin) + Ymin = dy; + if (dy > Ymax) + Ymax = dy; + }); + if (!domain && (Xmin === Infinity || Xmax === -Infinity)) { + Xmin = 0; + Xmax = 1; + } + // Initialize parameters + var A = Ymax - Ymin; // amplitude + var B = 1; // logistic slope + var C = Ymin; // baseline offset + var M = (Xmin + Xmax) / 2; // midpoint + // Predict function + function f(xx) { + return C + A / (1 + Math.exp(-B * (xx - M))); + } + var _loop_1 = function (iter) { + var dA = 0, dB = 0, dC = 0, dM = 0; + visitPoints(data, x, y, function (dx, dy) { + var yhat = f(dx); + var err = dy - yhat; + var ex = Math.exp(-B * (dx - M)); + var g = 1 / (1 + ex); // logistic + // partial derivatives + var df_dA = g; + var df_dC = 1; + var df_dB = A * g * (1 - g) * (dx - M); + // Note the negative sign for M: + var df_dM = -A * B * g * (1 - g); + var factor = -2 * err; + dA += factor * df_dA; + dB += factor * df_dB; + dC += factor * df_dC; + dM += factor * df_dM; + }); + A -= alpha * (dA / n); + B -= alpha * (dB / n); + C -= alpha * (dC / n); + M -= alpha * (dM / n); + }; + // Gradient Descent + for (var iter = 0; iter < maxIter; iter++) { + _loop_1(); + } + var predict = function (xx) { return C + A / (1 + Math.exp(-B * (xx - M))); }; + var out = interpose(Xmin, Xmax, predict); + out.A = A; + out.B = B; + out.C = C; + out.M = M; + out.predict = predict; + // R^2 + var meanY = sumY / n; + out.rSquared = determination(data, x, y, meanY, predict); + return out; + } + sigmoidalRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return sigmoidalRegression; + }; + sigmoidalRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return sigmoidalRegression; + }; + sigmoidalRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return sigmoidalRegression; + }; + return sigmoidalRegression; } exports.regressionExp = exponential; @@ -876,4 +767,5 @@ exports.regressionLoess = loess; exports.regressionLog = logarithmic; exports.regressionPoly = polynomial; exports.regressionPow = power; -exports.regressionQuad = quad; +exports.regressionQuad = quadratic; +exports.regressionSigmoidal = sigmoidal; diff --git a/dist/d3-regression.esm.js b/dist/d3-regression.esm.js index c1a206b..f4d98e6 100644 --- a/dist/d3-regression.esm.js +++ b/dist/d3-regression.esm.js @@ -1,869 +1,760 @@ -// https://github.com/HarryStevens/d3-regression#readme Version 1.3.10. Copyright 2022 Harry Stevens. -function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); -} - -function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; -} - -function _iterableToArrayLimit(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; -} - -function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); -} - -// Adapted from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js +// https://github.com/HarryStevens/d3-regression#readme Version 1.3.10. Copyright 2025 Harry Stevens. +/** + * Adapted from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js + */ function points(data, x, y, sort) { - data = data.filter(function (d, i) { - var u = x(d, i), - v = y(d, i); - return u != null && isFinite(u) && v != null && isFinite(v); - }); - - if (sort) { - data.sort(function (a, b) { - return x(a) - x(b); + data = data.filter(function (d, i) { + var u = x(d, i), v = y(d, i); + return u != null && isFinite(u) && v != null && isFinite(v); }); - } - - var n = data.length, - X = new Float64Array(n), - Y = new Float64Array(n); // extract values, calculate means - - var ux = 0, - uy = 0, - xv, - yv, - d; - - for (var i = 0; i < n;) { - d = data[i]; - X[i] = xv = +x(d, i, data); - Y[i] = yv = +y(d, i, data); - ++i; - ux += (xv - ux) / i; - uy += (yv - uy) / i; - } // mean center the data - - - for (var _i = 0; _i < n; ++_i) { - X[_i] -= ux; - Y[_i] -= uy; - } - - return [X, Y, ux, uy]; + if (sort) { + data.sort(function (a, b) { return x(a) - x(b); }); + } + var n = data.length, X = new Float64Array(n), Y = new Float64Array(n); + // extract values, calculate means + var ux = 0, uy = 0, xv, yv, d; + for (var i = 0; i < n;) { + d = data[i]; + X[i] = xv = +x(d, i, data); + Y[i] = yv = +y(d, i, data); + ++i; + ux += (xv - ux) / i; + uy += (yv - uy) / i; + } + // mean center the data + for (var i = 0; i < n; ++i) { + X[i] -= ux; + Y[i] -= uy; + } + return [X, Y, ux, uy]; } +/** + * Iterates over valid data points, invoking a callback for each. + */ function visitPoints(data, x, y, cb) { - var iterations = 0; - - for (var i = 0, n = data.length; i < n; i++) { - var d = data[i], - dx = +x(d, i, data), - dy = +y(d, i, data); - - if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { - cb(dx, dy, iterations++); + var iterations = 0; + for (var i = 0; i < data.length; i++) { + var d = data[i]; + var dx = +x(d, i, data); + var dy = +y(d, i, data); + if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { + cb(dx, dy, iterations++); + } } - } } -// return the coefficient of determination, or R squared. - +/** + * Given a dataset, x- and y-accessors, the mean center of the y-values (uY), + * and a prediction function, return the coefficient of determination, R^2. + */ function determination(data, x, y, uY, predict) { - var SSE = 0, - SST = 0; - visitPoints(data, x, y, function (dx, dy) { - var sse = dy - predict(dx), - sst = dy - uY; - SSE += sse * sse; - SST += sst * sst; - }); - return 1 - SSE / SST; + var SSE = 0, // Sum of Squared Errors + SST = 0; // Total Sum of Squares + visitPoints(data, x, y, function (dx, dy) { + var sse = dy - predict(dx); + var sst = dy - uY; + SSE += sse * sse; + SST += sst * sst; + }); + return 1 - SSE / SST; } -// Returns the angle of a line in degrees. +/** + * Returns the angle of a line in degrees. + */ function angle(line) { - return Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * 180 / Math.PI; -} // Returns the midpoint of a line. - + return (Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * + (180 / Math.PI)); +} +/** + * Returns the midpoint of a line. + */ function midpoint(line) { - return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2]; + return [ + (line[0][0] + line[1][0]) / 2, + (line[0][1] + line[1][1]) / 2 + ]; } -// returns a smooth line. - +/** + * Given a start point (xmin), an end point (xmax), + * and a prediction function, returns a smooth line. + */ function interpose(xmin, xmax, predict) { - var l = Math.log(xmax - xmin) * Math.LOG10E + 1 | 0; - var precision = 1 * Math.pow(10, -l / 2 - 1), - maxIter = 1e4; - var points = [px(xmin), px(xmax)], - iter = 0; - - while (find(points) && iter < maxIter) { - } - - return points; - - function px(x) { - return [x, predict(x)]; - } - - function find(points) { - iter++; - var n = points.length; - var found = false; - - for (var i = 0; i < n - 1; i++) { - var p0 = points[i], - p1 = points[i + 1], - m = midpoint([p0, p1]), - mp = px(m[0]), - a0 = angle([p0, m]), - a1 = angle([p0, mp]), - a = Math.abs(a0 - a1); - - if (a > precision) { - points.splice(i + 1, 0, mp); - found = true; - } + var l = (Math.log(xmax - xmin) * Math.LOG10E + 1) | 0; + var precision = Math.pow(10, -l / 2 - 1); + var maxIter = 1e4; + var points = [px(xmin), px(xmax)]; + var iter = 0; + while (find(points) && iter < maxIter) + ; + return points; + function px(x) { + return [x, predict(x)]; + } + function find(points) { + iter++; + var n = points.length; + var found = false; + for (var i = 0; i < n - 1; i++) { + var p0 = points[i]; + var p1 = points[i + 1]; + var m = midpoint([p0, p1]); + var mp = px(m[0]); + var a0 = angle([p0, m]); + var a1 = angle([p0, mp]); + var a = Math.abs(a0 - a1); + if (a > precision) { + points.splice(i + 1, 0, mp); + found = true; + } + } + return found; } - - return found; - } } -// Ordinary Least Squares from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js +/** + * Ordinary Least Squares from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js + */ function ols(uX, uY, uXY, uX2) { - var delta = uX2 - uX * uX, - slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, - intercept = uY - slope * uX; - return [intercept, slope]; + var delta = uX2 - uX * uX, slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, intercept = uY - slope * uX; + return [intercept, slope]; } -function exponential () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function exponential(data) { - var n = 0, - Y = 0, - YL = 0, - XY = 0, - XYL = 0, - X2Y = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - var ly = Math.log(dy), - xy = dx * dy; - ++n; - Y += (dy - Y) / n; - XY += (xy - XY) / n; - X2Y += (dx * xy - X2Y) / n; - YL += (dy * ly - YL) / n; - XYL += (xy * ly - XYL) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - a = Math.exp(a); - - var fn = function fn(x) { - return a * Math.exp(b * x); - }, - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - exponential.domain = function (arr) { - return arguments.length ? (domain = arr, exponential) : domain; - }; - - exponential.x = function (fn) { - return arguments.length ? (x = fn, exponential) : x; - }; - - exponential.y = function (fn) { - return arguments.length ? (y = fn, exponential) : y; - }; - - return exponential; +function exponential() { + var y = function (d) { return d[1]; }, x = function (d) { return d[0]; }, domain; + var exponentialRegression = function (data) { + var n = 0, Y = 0, YL = 0, XY = 0, XYL = 0, X2Y = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + var ly = Math.log(dy), xy = dx * dy; + ++n; + Y += (dy - Y) / n; + XY += (xy - XY) / n; + X2Y += (dx * xy - X2Y) / n; + YL += (dy * ly - YL) / n; + XYL += (xy * ly - XYL) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), a = _a[0], b = _a[1]; + a = Math.exp(a); + var fn = function (xx) { return a * Math.exp(b * xx); }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + exponentialRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return exponentialRegression; + }; + exponentialRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return exponentialRegression; + }; + exponentialRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return exponentialRegression; + }; + return exponentialRegression; } -function linear () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function linear(data) { - var n = 0, - X = 0, - // sum of x - Y = 0, - // sum of y - XY = 0, - // sum of x * y - X2 = 0, - // sum of x * x - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - ++n; - X += (dx - X) / n; - Y += (dy - Y) / n; - XY += (dx * dy - XY) / n; - X2 += (dx * dx - X2) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - intercept = _ols2[0], - slope = _ols2[1], - fn = function fn(x) { - return slope * x + intercept; - }, - out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - linear.domain = function (arr) { - return arguments.length ? (domain = arr, linear) : domain; - }; - - linear.x = function (fn) { - return arguments.length ? (x = fn, linear) : x; - }; - - linear.y = function (fn) { - return arguments.length ? (y = fn, linear) : y; - }; - - return linear; +function linear() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var linearRegression = function (data) { + var n = 0, X = 0, // sum of x + Y = 0, // sum of y + XY = 0, // sum of x*y + X2 = 0, // sum of x*x + xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + ++n; + X += (dx - X) / n; + Y += (dy - Y) / n; + XY += (dx * dy - XY) / n; + X2 += (dx * dx - X2) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), intercept = _a[0], slope = _a[1]; + var fn = function (xx) { return slope * xx + intercept; }; + var out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + linearRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return linearRegression; + }; + linearRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return linearRegression; + }; + linearRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return linearRegression; + }; + return linearRegression; } -// Returns the medium value of an array of numbers. +/** + * Returns the median value of an array of numbers. + */ function median(arr) { - arr.sort(function (a, b) { - return a - b; - }); - var i = arr.length / 2; - return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; + arr.sort(function (a, b) { return a - b; }); + var i = arr.length / 2; + return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; } -var maxiters = 2, - epsilon = 1e-12; -function loess () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - bandwidth = .3; - - function loess(data) { - var _points = points(data, x, y, true), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length, - bw = Math.max(2, ~~(bandwidth * n)), - yhat = new Float64Array(n), - residuals = new Float64Array(n), - robustWeights = new Float64Array(n).fill(1); - - for (var iter = -1; ++iter <= maxiters;) { - var interval = [0, bw - 1]; - - for (var i = 0; i < n; ++i) { - var dx = xv[i], - i0 = interval[0], - i1 = interval[1], - edge = dx - xv[i0] > xv[i1] - dx ? i0 : i1; - var W = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - denom = 1 / Math.abs(xv[edge] - dx || 1); // Avoid singularity - - for (var k = i0; k <= i1; ++k) { - var xk = xv[k], - yk = yv[k], - w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k], - xkw = xk * w; - W += w; - X += xkw; - Y += yk * w; - XY += yk * xkw; - X2 += xk * xkw; - } // Linear regression fit - - - var _ols = ols(X / W, Y / W, XY / W, X2 / W), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - yhat[i] = a + b * dx; - residuals[i] = Math.abs(yv[i] - yhat[i]); - updateInterval(xv, i + 1, interval); - } - - if (iter === maxiters) { - break; - } - - var medianResidual = median(residuals); - if (Math.abs(medianResidual) < epsilon) break; - - for (var _i = 0, arg, _w; _i < n; ++_i) { - arg = residuals[_i] / (6 * medianResidual); // Default to epsilon (rather than zero) for large deviations - // Keeping weights tiny but non-zero prevents singularites - - robustWeights[_i] = arg >= 1 ? epsilon : (_w = 1 - arg * arg) * _w; - } - } - - return output(xv, yhat, ux, uy); - } - - loess.bandwidth = function (bw) { - return arguments.length ? (bandwidth = bw, loess) : bandwidth; - }; - - loess.x = function (fn) { - return arguments.length ? (x = fn, loess) : x; - }; - - loess.y = function (fn) { - return arguments.length ? (y = fn, loess) : y; - }; - - return loess; -} // Weighting kernel for local regression - +// Adapted from science.js by Jason Davies +var maxiters = 2, epsilon = 1e-12; +function loess() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, bandwidth = 0.3; + var loessRegression = function loessRegression(data) { + var _a = points(data, function (dd) { return x(dd); }, function (dd) { return y(dd); }, true), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var bw = Math.max(2, ~~(bandwidth * n)); // # of nearest neighbors + var yhat = new Float64Array(n); + var residuals = new Float64Array(n); + var robustWeights = new Float64Array(n).fill(1); + for (var iter = -1; ++iter <= maxiters;) { + var interval = [0, bw - 1]; + for (var i = 0; i < n; ++i) { + var dx = xv[i]; + var i0 = interval[0]; + var i1 = interval[1]; + var edge = (dx - xv[i0]) > (xv[i1] - dx) ? i0 : i1; + var W = 0, X = 0, Y = 0, XY = 0, X2 = 0; + var denom = 1 / Math.abs(xv[edge] - dx || 1); + for (var k = i0; k <= i1; ++k) { + var xk = xv[k]; + var yk = yv[k]; + var w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k]; + var xkw = xk * w; + W += w; + X += xkw; + Y += yk * w; + XY += yk * xkw; + X2 += xk * xkw; + } + // Linear regression fit + var _b = ols(X / W, Y / W, XY / W, X2 / W), a = _b[0], b = _b[1]; + yhat[i] = a + b * dx; + residuals[i] = Math.abs(yv[i] - yhat[i]); + updateInterval(xv, i + 1, interval); + } + if (iter === maxiters) { + break; + } + var medianResidual = median(residuals); + if (Math.abs(medianResidual) < epsilon) + break; + for (var i = 0, arg = void 0, w = void 0; i < n; ++i) { + arg = residuals[i] / (6 * medianResidual); + // Default to epsilon (rather than zero) for large deviations + // Keeping weights tiny but non-zero prevents singularites + robustWeights[i] = (arg >= 1) ? epsilon : ((w = 1 - arg * arg) * w); + } + } + return output(xv, yhat, ux, uy); + }; + loessRegression.bandwidth = function (bw) { + if (!arguments.length) + return bandwidth; + bandwidth = bw; + return loessRegression; + }; + loessRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return loessRegression; + }; + loessRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return loessRegression; + }; + return loessRegression; +} +// Weighting kernel for local regression function tricube(x) { - return (x = 1 - x * x * x) * x * x; -} // Advance sliding window interval of nearest neighbors - - + return (x = 1 - x * x * x) * x * x; +} +// Advance sliding window interval of nearest neighbors function updateInterval(xv, i, interval) { - var val = xv[i], - left = interval[0], - right = interval[1] + 1; - if (right >= xv.length) return; // Step right if distance to new right edge is <= distance to old left edge - // Step when distance is equal to ensure movement over duplicate x values - - while (i > left && xv[right] - val <= val - xv[left]) { - interval[0] = ++left; - interval[1] = right; - ++right; - } -} // Generate smoothed output points + var val = xv[i], left = interval[0], right = interval[1] + 1; + if (right >= xv.length) + return; + // Step right if distance to new right edge is <= distance to old left edge + // Step when distance is equal to ensure movement over duplicate x values + while (i > left && (xv[right] - val) <= (val - xv[left])) { + interval[0] = ++left; + interval[1] = right; + ++right; + } +} +// Generate smoothed output points // Average points with repeated x values - - function output(xv, yhat, ux, uy) { - var n = xv.length, - out = []; - var i = 0, - cnt = 0, - prev = [], - v; - - for (; i < n; ++i) { - v = xv[i] + ux; - - if (prev[0] === v) { - // Average output values via online update - prev[1] += (yhat[i] - prev[1]) / ++cnt; - } else { - // Add new output point - cnt = 0; - prev[1] += uy; - prev = [v, yhat[i]]; - out.push(prev); + var n = xv.length, out = []; + var i = 0, cnt = 0, prev = [], v; + for (; i < n; ++i) { + v = xv[i] + ux; + if (prev[0] === v) { + // Average output values via online update + prev[1] += (yhat[i] - prev[1]) / (++cnt); + } + else { + // Add new output point + cnt = 0; + prev[1] += uy; + prev = [v, yhat[i]]; + out.push(prev); + } } - } - - prev[1] += uy; - return out; -} - -function logarithmic () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - base = Math.E, - domain; - - function logarithmic(data) { - var n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity, - lb = Math.log(base); - visitPoints(data, x, y, function (dx, dy) { - var lx = Math.log(dx) / lb; - ++n; - X += (lx - X) / n; - Y += (dy - Y) / n; - XY += (lx * dy - XY) / n; - X2 += (lx * lx - X2) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - intercept = _ols2[0], - slope = _ols2[1], - fn = function fn(x) { - return slope * Math.log(x) / lb + intercept; - }, - out = interpose(xmin, xmax, fn); - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); + prev[1] += uy; return out; - } - - logarithmic.domain = function (arr) { - return arguments.length ? (domain = arr, logarithmic) : domain; - }; - - logarithmic.x = function (fn) { - return arguments.length ? (x = fn, logarithmic) : x; - }; - - logarithmic.y = function (fn) { - return arguments.length ? (y = fn, logarithmic) : y; - }; - - logarithmic.base = function (n) { - return arguments.length ? (base = n, logarithmic) : base; - }; - - return logarithmic; } -function quad () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function quadratic(data) { - var _points = points(data, x, y), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length; - - var X2 = 0, - X3 = 0, - X4 = 0, - XY = 0, - X2Y = 0, - i, - dx, - dy, - x2; - - for (i = 0; i < n;) { - dx = xv[i]; - dy = yv[i++]; - x2 = dx * dx; - X2 += (x2 - X2) / i; - X3 += (x2 * dx - X3) / i; - X4 += (x2 * x2 - X4) / i; - XY += (dx * dy - XY) / i; - X2Y += (x2 * dy - X2Y) / i; - } - - var Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - n0++; - Y += (dy - Y) / n0; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var X2X2 = X4 - X2 * X2, - d = X2 * X2X2 - X3 * X3, - a = (X2Y * X2 - XY * X3) / d, - b = (XY * X2X2 - X2Y * X3) / d, - c = -a * X2, - fn = function fn(x) { - x = x - ux; - return a * x * x + b * x + c + uy; +function logarithmic() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, base = Math.E, domain; + var logarithmicRegression = function (data) { + var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity, lb = Math.log(base); + visitPoints(data, x, y, function (dx, dy) { + var lx = Math.log(dx) / lb; + ++n; + X += (lx - X) / n; + Y += (dy - Y) / n; + XY += (lx * dy - XY) / n; + X2 += (lx * lx - X2) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), intercept = _a[0], slope = _a[1]; + var fn = function (xx) { return slope * Math.log(xx) / lb + intercept; }; + var out = interpose(xmin, xmax, fn); + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; }; - - var out = interpose(xmin, xmax, fn); - out.a = a; - out.b = b - 2 * a * ux; - out.c = c - b * ux + a * ux * ux + uy; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - quadratic.domain = function (arr) { - return arguments.length ? (domain = arr, quadratic) : domain; - }; - - quadratic.x = function (fn) { - return arguments.length ? (x = fn, quadratic) : x; - }; - - quadratic.y = function (fn) { - return arguments.length ? (y = fn, quadratic) : y; - }; - - return quadratic; + logarithmicRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return logarithmicRegression; + }; + logarithmicRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return logarithmicRegression; + }; + logarithmicRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return logarithmicRegression; + }; + logarithmicRegression.base = function (b) { + if (!arguments.length) + return base; + base = b; + return logarithmicRegression; + }; + return logarithmicRegression; } -// Source: https://github.com/Tom-Alexander/regression-js/blob/master/src/regression.js#L246 -// License: https://github.com/Tom-Alexander/regression-js/blob/master/LICENSE -// ...with ideas from vega-statistics by Jeffrey Heer -// Source: https://github.com/vega/vega/blob/f21cb8792b4e0cbe2b1a3fd44b0f5db370dbaadb/packages/vega-statistics/src/regression/poly.js -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE - -function polynomial () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - order = 3, - domain; - - function polynomial(data) { - // Use more efficient methods for lower orders - if (order === 1) { - var o = linear().x(x).y(y).domain(domain)(data); - o.coefficients = [o.b, o.a]; - delete o.a; - delete o.b; - return o; - } - - if (order === 2) { - var _o = quad().x(x).y(y).domain(domain)(data); - - _o.coefficients = [_o.c, _o.b, _o.a]; - delete _o.a; - delete _o.b; - delete _o.c; - return _o; - } - - var _points = points(data, x, y), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length, - lhs = [], - rhs = [], - k = order + 1; - - var Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - ++n0; - Y += (dy - Y) / n0; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - var i, j, l, v, c; - - for (i = 0; i < k; ++i) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i) * yv[l]; - } - - lhs.push(v); - c = new Float64Array(k); - - for (j = 0; j < k; ++j) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i + j); +function quadratic() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var quadraticRegression = function quadraticRegression(data) { + var _a = points(data, function (dd) { return x(dd); }, function (dd) { return y(dd); }), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var X2 = 0, X3 = 0, X4 = 0, XY = 0, X2Y = 0, i, dx, dy, x2; + for (i = 0; i < n;) { + dx = xv[i]; + dy = yv[i++]; + x2 = dx * dx; + X2 += (x2 - X2) / i; + X3 += ((x2 * dx) - X3) / i; + X4 += ((x2 * x2) - X4) / i; + XY += ((dx * dy) - XY) / i; + X2Y += ((x2 * dy) - X2Y) / i; } - - c[j] = v; - } - - rhs.push(c); - } - - rhs.push(lhs); - - var coef = gaussianElimination(rhs), - fn = function fn(x) { - x -= ux; - var y = uy + coef[0] + coef[1] * x + coef[2] * x * x; - - for (i = 3; i < k; ++i) { - y += coef[i] * Math.pow(x, i); - } - - return y; - }, - out = interpose(xmin, xmax, fn); - - out.coefficients = uncenter(k, coef, -ux, uy); - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - polynomial.domain = function (arr) { - return arguments.length ? (domain = arr, polynomial) : domain; - }; - - polynomial.x = function (fn) { - return arguments.length ? (x = fn, polynomial) : x; - }; - - polynomial.y = function (fn) { - return arguments.length ? (y = fn, polynomial) : y; - }; - - polynomial.order = function (n) { - return arguments.length ? (order = n, polynomial) : order; - }; - - return polynomial; + var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx2, dy2) { + n0++; + Y += (dy2 - Y) / n0; + if (!domain) { + if (dx2 < xmin) + xmin = dx2; + if (dx2 > xmax) + xmax = dx2; + } + }); + var X2X2 = X4 - (X2 * X2); + var d = (X2 * X2X2 - X3 * X3); + var a = (X2Y * X2 - XY * X3) / d; + var b = (XY * X2X2 - X2Y * X3) / d; + var c = -a * X2; + var fn = function (xx) { + var shifted = xx - ux; + return a * shifted * shifted + b * shifted + c + uy; + }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b - 2 * a * ux; + out.c = c - b * ux + a * ux * ux + uy; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + quadraticRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return quadraticRegression; + }; + quadraticRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return quadraticRegression; + }; + quadraticRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return quadraticRegression; + }; + return quadraticRegression; } +// Adapted from regression-js by Tom Alexander +function polynomial() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, order = 3, domain; + var polynomialRegression = function polynomialRegression(data) { + // Shortcut for lower-order polynomials: + if (order === 1) { + var o = linear().x(x).y(y).domain(domain)(data); + var result = [o[0], o[1]]; + result.coefficients = [o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + if (order === 2) { + var o = quadratic().x(x).y(y).domain(domain)(data); + var result = [o[0], o[1]]; + result.coefficients = [o.c, o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + var _a = points(data, x, y), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var k = order + 1; + var lhs = []; + var rhs = []; + var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + n0++; + Y += (dy - Y) / n0; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + // Build normal equations + for (var i = 0; i < k; i++) { + // LHS + var v = 0; + for (var l = 0; l < n; l++) { + v += Math.pow(xv[l], i) * yv[l]; + } + lhs.push(v); + // RHS + var c = new Float64Array(k); + for (var j = 0; j < k; j++) { + var v2 = 0; + for (var l = 0; l < n; l++) { + v2 += Math.pow(xv[l], i + j); + } + c[j] = v2; + } + rhs.push(c); + } + rhs.push(new Float64Array(lhs)); + var coef = gaussianElimination(rhs); + var fn = function (xx) { + var shifted = xx - ux; + var val = uy + coef[0]; + for (var i = 1; i < k; i++) { + val += coef[i] * Math.pow(shifted, i); + } + return val; + }; + var out = interpose(xmin, xmax, fn); + out.coefficients = uncenter(k, coef, -ux, uy); + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + polynomialRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return polynomialRegression; + }; + polynomialRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return polynomialRegression; + }; + polynomialRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return polynomialRegression; + }; + polynomialRegression.order = function (n) { + if (!arguments.length) + return order; + order = n; + return polynomialRegression; + }; + return polynomialRegression; +} function uncenter(k, a, x, y) { - var z = Array(k); - var i, j, v, c; // initialize to zero - - for (i = 0; i < k; ++i) { - z[i] = 0; - } // polynomial expansion - - - for (i = k - 1; i >= 0; --i) { - v = a[i]; - c = 1; - z[i] += v; - - for (j = 1; j <= i; ++j) { - c *= (i + 1 - j) / j; // binomial coefficent - - z[i - j] += v * Math.pow(x, j) * c; + var z = new Array(k).fill(0); + for (var i = k - 1; i >= 0; --i) { + var v = a[i]; + z[i] += v; + var c = 1; + for (var j = 1; j <= i; ++j) { + c *= (i + 1 - j) / j; // binomial coefficient + z[i - j] += v * Math.pow(x, j) * c; + } } - } // bias term - - - z[0] += y; - return z; -} // Given an array for a two-dimensional matrix and the polynomial order, -// solve A * x = b using Gaussian elimination. - - + // bias term + z[0] += y; + return z; +} +// Solve A * x = b using Gaussian elimination function gaussianElimination(matrix) { - var n = matrix.length - 1, - coef = []; - var i, j, k, r, t; - - for (i = 0; i < n; ++i) { - r = i; // max row - - for (j = i + 1; j < n; ++j) { - if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { - r = j; - } - } - - for (k = i; k < n + 1; ++k) { - t = matrix[k][i]; - matrix[k][i] = matrix[k][r]; - matrix[k][r] = t; - } - - for (j = i + 1; j < n; ++j) { - for (k = n; k >= i; k--) { - matrix[k][j] -= matrix[k][i] * matrix[i][j] / matrix[i][i]; - } + var n = matrix.length - 1; + var coef = new Array(n); + for (var i = 0; i < n; i++) { + var r = i; + // find pivot row + for (var j = i + 1; j < n; j++) { + if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { + r = j; + } + } + // swap columns + for (var k = i; k < n + 1; k++) { + var t = matrix[k][i]; + matrix[k][i] = matrix[k][r]; + matrix[k][r] = t; + } + // reduce + for (var j = i + 1; j < n; j++) { + for (var k = n; k >= i; k--) { + matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i]; + } + } } - } - - for (j = n - 1; j >= 0; --j) { - t = 0; - - for (k = j + 1; k < n; ++k) { - t += matrix[k][j] * coef[k]; + for (var j = n - 1; j >= 0; j--) { + var t = 0; + for (var k = j + 1; k < n; k++) { + t += matrix[k][j] * coef[k]; + } + coef[j] = (matrix[n][j] - t) / matrix[j][j]; } - - coef[j] = (matrix[n][j] - t) / matrix[j][j]; - } - - return coef; + return coef; } -function power () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function power(data) { - var n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - YS = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - var lx = Math.log(dx), - ly = Math.log(dy); - ++n; - X += (lx - X) / n; - Y += (ly - Y) / n; - XY += (lx * ly - XY) / n; - X2 += (lx * lx - X2) / n; - YS += (dy - YS) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - a = Math.exp(a); - - var fn = function fn(x) { - return a * Math.pow(x, b); - }, - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, YS, fn); - return out; - } - - power.domain = function (arr) { - return arguments.length ? (domain = arr, power) : domain; - }; - - power.x = function (fn) { - return arguments.length ? (x = fn, power) : x; - }; - - power.y = function (fn) { - return arguments.length ? (y = fn, power) : y; - }; +function power() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var powerRegression = function powerRegression(data) { + var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, YS = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + var lx = Math.log(dx), ly = Math.log(dy); + ++n; + X += (lx - X) / n; + Y += (ly - Y) / n; + XY += (lx * ly - XY) / n; + X2 += (lx * lx - X2) / n; + YS += (dy - YS) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), a = _a[0], b = _a[1]; + a = Math.exp(a); + var fn = function (xx) { return a * Math.pow(xx, b); }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, YS, fn); + return out; + }; + powerRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return powerRegression; + }; + powerRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return powerRegression; + }; + powerRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return powerRegression; + }; + return powerRegression; +} - return power; +function sigmoidal() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain, maxIter = 2000, alpha = 1e-4; // learning rate + function sigmoidalRegression(data) { + var n = 0, Xmin = domain ? +domain[0] : Infinity, Xmax = domain ? +domain[1] : -Infinity, Ymin = Infinity, Ymax = -Infinity, sumY = 0; + // Gather data & track min/max for domain if not preset + visitPoints(data, x, y, function (dx, dy) { + n++; + sumY += dy; + if (!domain) { + if (dx < Xmin) + Xmin = dx; + if (dx > Xmax) + Xmax = dx; + } + if (dy < Ymin) + Ymin = dy; + if (dy > Ymax) + Ymax = dy; + }); + if (!domain && (Xmin === Infinity || Xmax === -Infinity)) { + Xmin = 0; + Xmax = 1; + } + // Initialize parameters + var A = Ymax - Ymin; // amplitude + var B = 1; // logistic slope + var C = Ymin; // baseline offset + var M = (Xmin + Xmax) / 2; // midpoint + // Predict function + function f(xx) { + return C + A / (1 + Math.exp(-B * (xx - M))); + } + var _loop_1 = function (iter) { + var dA = 0, dB = 0, dC = 0, dM = 0; + visitPoints(data, x, y, function (dx, dy) { + var yhat = f(dx); + var err = dy - yhat; + var ex = Math.exp(-B * (dx - M)); + var g = 1 / (1 + ex); // logistic + // partial derivatives + var df_dA = g; + var df_dC = 1; + var df_dB = A * g * (1 - g) * (dx - M); + // Note the negative sign for M: + var df_dM = -A * B * g * (1 - g); + var factor = -2 * err; + dA += factor * df_dA; + dB += factor * df_dB; + dC += factor * df_dC; + dM += factor * df_dM; + }); + A -= alpha * (dA / n); + B -= alpha * (dB / n); + C -= alpha * (dC / n); + M -= alpha * (dM / n); + }; + // Gradient Descent + for (var iter = 0; iter < maxIter; iter++) { + _loop_1(); + } + var predict = function (xx) { return C + A / (1 + Math.exp(-B * (xx - M))); }; + var out = interpose(Xmin, Xmax, predict); + out.A = A; + out.B = B; + out.C = C; + out.M = M; + out.predict = predict; + // R^2 + var meanY = sumY / n; + out.rSquared = determination(data, x, y, meanY, predict); + return out; + } + sigmoidalRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return sigmoidalRegression; + }; + sigmoidalRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return sigmoidalRegression; + }; + sigmoidalRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return sigmoidalRegression; + }; + return sigmoidalRegression; } -export { exponential as regressionExp, linear as regressionLinear, loess as regressionLoess, logarithmic as regressionLog, polynomial as regressionPoly, power as regressionPow, quad as regressionQuad }; +export { exponential as regressionExp, linear as regressionLinear, loess as regressionLoess, logarithmic as regressionLog, polynomial as regressionPoly, power as regressionPow, quadratic as regressionQuad, sigmoidal as regressionSigmoidal }; diff --git a/dist/d3-regression.js b/dist/d3-regression.js index 6437bff..f6b0111 100644 --- a/dist/d3-regression.js +++ b/dist/d3-regression.js @@ -1,875 +1,766 @@ -// https://github.com/HarryStevens/d3-regression#readme Version 1.3.10. Copyright 2022 Harry Stevens. +// https://github.com/HarryStevens/d3-regression#readme Version 1.3.10. Copyright 2025 Harry Stevens. (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.d3 = {})); }(this, (function (exports) { 'use strict'; - function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); - } - - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; - } - - function _iterableToArrayLimit(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - - // Adapted from vega-statistics by Jeffrey Heer - // License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE - // Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js + /** + * Adapted from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js + */ function points(data, x, y, sort) { - data = data.filter(function (d, i) { - var u = x(d, i), - v = y(d, i); - return u != null && isFinite(u) && v != null && isFinite(v); - }); - - if (sort) { - data.sort(function (a, b) { - return x(a) - x(b); + data = data.filter(function (d, i) { + var u = x(d, i), v = y(d, i); + return u != null && isFinite(u) && v != null && isFinite(v); }); - } - - var n = data.length, - X = new Float64Array(n), - Y = new Float64Array(n); // extract values, calculate means - - var ux = 0, - uy = 0, - xv, - yv, - d; - - for (var i = 0; i < n;) { - d = data[i]; - X[i] = xv = +x(d, i, data); - Y[i] = yv = +y(d, i, data); - ++i; - ux += (xv - ux) / i; - uy += (yv - uy) / i; - } // mean center the data - - - for (var _i = 0; _i < n; ++_i) { - X[_i] -= ux; - Y[_i] -= uy; - } - - return [X, Y, ux, uy]; + if (sort) { + data.sort(function (a, b) { return x(a) - x(b); }); + } + var n = data.length, X = new Float64Array(n), Y = new Float64Array(n); + // extract values, calculate means + var ux = 0, uy = 0, xv, yv, d; + for (var i = 0; i < n;) { + d = data[i]; + X[i] = xv = +x(d, i, data); + Y[i] = yv = +y(d, i, data); + ++i; + ux += (xv - ux) / i; + uy += (yv - uy) / i; + } + // mean center the data + for (var i = 0; i < n; ++i) { + X[i] -= ux; + Y[i] -= uy; + } + return [X, Y, ux, uy]; } + /** + * Iterates over valid data points, invoking a callback for each. + */ function visitPoints(data, x, y, cb) { - var iterations = 0; - - for (var i = 0, n = data.length; i < n; i++) { - var d = data[i], - dx = +x(d, i, data), - dy = +y(d, i, data); - - if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { - cb(dx, dy, iterations++); + var iterations = 0; + for (var i = 0; i < data.length; i++) { + var d = data[i]; + var dx = +x(d, i, data); + var dy = +y(d, i, data); + if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { + cb(dx, dy, iterations++); + } } - } } - // return the coefficient of determination, or R squared. - + /** + * Given a dataset, x- and y-accessors, the mean center of the y-values (uY), + * and a prediction function, return the coefficient of determination, R^2. + */ function determination(data, x, y, uY, predict) { - var SSE = 0, - SST = 0; - visitPoints(data, x, y, function (dx, dy) { - var sse = dy - predict(dx), - sst = dy - uY; - SSE += sse * sse; - SST += sst * sst; - }); - return 1 - SSE / SST; + var SSE = 0, // Sum of Squared Errors + SST = 0; // Total Sum of Squares + visitPoints(data, x, y, function (dx, dy) { + var sse = dy - predict(dx); + var sst = dy - uY; + SSE += sse * sse; + SST += sst * sst; + }); + return 1 - SSE / SST; } - // Returns the angle of a line in degrees. + /** + * Returns the angle of a line in degrees. + */ function angle(line) { - return Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * 180 / Math.PI; - } // Returns the midpoint of a line. - + return (Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * + (180 / Math.PI)); + } + /** + * Returns the midpoint of a line. + */ function midpoint(line) { - return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2]; + return [ + (line[0][0] + line[1][0]) / 2, + (line[0][1] + line[1][1]) / 2 + ]; } - // returns a smooth line. - + /** + * Given a start point (xmin), an end point (xmax), + * and a prediction function, returns a smooth line. + */ function interpose(xmin, xmax, predict) { - var l = Math.log(xmax - xmin) * Math.LOG10E + 1 | 0; - var precision = 1 * Math.pow(10, -l / 2 - 1), - maxIter = 1e4; - var points = [px(xmin), px(xmax)], - iter = 0; - - while (find(points) && iter < maxIter) { - } - - return points; - - function px(x) { - return [x, predict(x)]; - } - - function find(points) { - iter++; - var n = points.length; - var found = false; - - for (var i = 0; i < n - 1; i++) { - var p0 = points[i], - p1 = points[i + 1], - m = midpoint([p0, p1]), - mp = px(m[0]), - a0 = angle([p0, m]), - a1 = angle([p0, mp]), - a = Math.abs(a0 - a1); - - if (a > precision) { - points.splice(i + 1, 0, mp); - found = true; - } + var l = (Math.log(xmax - xmin) * Math.LOG10E + 1) | 0; + var precision = Math.pow(10, -l / 2 - 1); + var maxIter = 1e4; + var points = [px(xmin), px(xmax)]; + var iter = 0; + while (find(points) && iter < maxIter) + ; + return points; + function px(x) { + return [x, predict(x)]; + } + function find(points) { + iter++; + var n = points.length; + var found = false; + for (var i = 0; i < n - 1; i++) { + var p0 = points[i]; + var p1 = points[i + 1]; + var m = midpoint([p0, p1]); + var mp = px(m[0]); + var a0 = angle([p0, m]); + var a1 = angle([p0, mp]); + var a = Math.abs(a0 - a1); + if (a > precision) { + points.splice(i + 1, 0, mp); + found = true; + } + } + return found; } - - return found; - } } - // Ordinary Least Squares from vega-statistics by Jeffrey Heer - // License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE - // Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js + /** + * Ordinary Least Squares from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js + */ function ols(uX, uY, uXY, uX2) { - var delta = uX2 - uX * uX, - slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, - intercept = uY - slope * uX; - return [intercept, slope]; + var delta = uX2 - uX * uX, slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, intercept = uY - slope * uX; + return [intercept, slope]; } - function exponential () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function exponential(data) { - var n = 0, - Y = 0, - YL = 0, - XY = 0, - XYL = 0, - X2Y = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - var ly = Math.log(dy), - xy = dx * dy; - ++n; - Y += (dy - Y) / n; - XY += (xy - XY) / n; - X2Y += (dx * xy - X2Y) / n; - YL += (dy * ly - YL) / n; - XYL += (xy * ly - XYL) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - a = Math.exp(a); - - var fn = function fn(x) { - return a * Math.exp(b * x); - }, - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - exponential.domain = function (arr) { - return arguments.length ? (domain = arr, exponential) : domain; - }; - - exponential.x = function (fn) { - return arguments.length ? (x = fn, exponential) : x; - }; - - exponential.y = function (fn) { - return arguments.length ? (y = fn, exponential) : y; - }; - - return exponential; + function exponential() { + var y = function (d) { return d[1]; }, x = function (d) { return d[0]; }, domain; + var exponentialRegression = function (data) { + var n = 0, Y = 0, YL = 0, XY = 0, XYL = 0, X2Y = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + var ly = Math.log(dy), xy = dx * dy; + ++n; + Y += (dy - Y) / n; + XY += (xy - XY) / n; + X2Y += (dx * xy - X2Y) / n; + YL += (dy * ly - YL) / n; + XYL += (xy * ly - XYL) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), a = _a[0], b = _a[1]; + a = Math.exp(a); + var fn = function (xx) { return a * Math.exp(b * xx); }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + exponentialRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return exponentialRegression; + }; + exponentialRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return exponentialRegression; + }; + exponentialRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return exponentialRegression; + }; + return exponentialRegression; } - function linear () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function linear(data) { - var n = 0, - X = 0, - // sum of x - Y = 0, - // sum of y - XY = 0, - // sum of x * y - X2 = 0, - // sum of x * x - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - ++n; - X += (dx - X) / n; - Y += (dy - Y) / n; - XY += (dx * dy - XY) / n; - X2 += (dx * dx - X2) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - intercept = _ols2[0], - slope = _ols2[1], - fn = function fn(x) { - return slope * x + intercept; - }, - out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - linear.domain = function (arr) { - return arguments.length ? (domain = arr, linear) : domain; - }; - - linear.x = function (fn) { - return arguments.length ? (x = fn, linear) : x; - }; - - linear.y = function (fn) { - return arguments.length ? (y = fn, linear) : y; - }; - - return linear; + function linear() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var linearRegression = function (data) { + var n = 0, X = 0, // sum of x + Y = 0, // sum of y + XY = 0, // sum of x*y + X2 = 0, // sum of x*x + xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + ++n; + X += (dx - X) / n; + Y += (dy - Y) / n; + XY += (dx * dy - XY) / n; + X2 += (dx * dx - X2) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), intercept = _a[0], slope = _a[1]; + var fn = function (xx) { return slope * xx + intercept; }; + var out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + linearRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return linearRegression; + }; + linearRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return linearRegression; + }; + linearRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return linearRegression; + }; + return linearRegression; } - // Returns the medium value of an array of numbers. + /** + * Returns the median value of an array of numbers. + */ function median(arr) { - arr.sort(function (a, b) { - return a - b; - }); - var i = arr.length / 2; - return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; + arr.sort(function (a, b) { return a - b; }); + var i = arr.length / 2; + return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; } - var maxiters = 2, - epsilon = 1e-12; - function loess () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - bandwidth = .3; - - function loess(data) { - var _points = points(data, x, y, true), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length, - bw = Math.max(2, ~~(bandwidth * n)), - yhat = new Float64Array(n), - residuals = new Float64Array(n), - robustWeights = new Float64Array(n).fill(1); - - for (var iter = -1; ++iter <= maxiters;) { - var interval = [0, bw - 1]; - - for (var i = 0; i < n; ++i) { - var dx = xv[i], - i0 = interval[0], - i1 = interval[1], - edge = dx - xv[i0] > xv[i1] - dx ? i0 : i1; - var W = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - denom = 1 / Math.abs(xv[edge] - dx || 1); // Avoid singularity - - for (var k = i0; k <= i1; ++k) { - var xk = xv[k], - yk = yv[k], - w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k], - xkw = xk * w; - W += w; - X += xkw; - Y += yk * w; - XY += yk * xkw; - X2 += xk * xkw; - } // Linear regression fit - - - var _ols = ols(X / W, Y / W, XY / W, X2 / W), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - yhat[i] = a + b * dx; - residuals[i] = Math.abs(yv[i] - yhat[i]); - updateInterval(xv, i + 1, interval); - } - - if (iter === maxiters) { - break; - } - - var medianResidual = median(residuals); - if (Math.abs(medianResidual) < epsilon) break; - - for (var _i = 0, arg, _w; _i < n; ++_i) { - arg = residuals[_i] / (6 * medianResidual); // Default to epsilon (rather than zero) for large deviations - // Keeping weights tiny but non-zero prevents singularites - - robustWeights[_i] = arg >= 1 ? epsilon : (_w = 1 - arg * arg) * _w; - } - } - - return output(xv, yhat, ux, uy); - } - - loess.bandwidth = function (bw) { - return arguments.length ? (bandwidth = bw, loess) : bandwidth; - }; - - loess.x = function (fn) { - return arguments.length ? (x = fn, loess) : x; - }; - - loess.y = function (fn) { - return arguments.length ? (y = fn, loess) : y; - }; - - return loess; - } // Weighting kernel for local regression - + // Adapted from science.js by Jason Davies + var maxiters = 2, epsilon = 1e-12; + function loess() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, bandwidth = 0.3; + var loessRegression = function loessRegression(data) { + var _a = points(data, function (dd) { return x(dd); }, function (dd) { return y(dd); }, true), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var bw = Math.max(2, ~~(bandwidth * n)); // # of nearest neighbors + var yhat = new Float64Array(n); + var residuals = new Float64Array(n); + var robustWeights = new Float64Array(n).fill(1); + for (var iter = -1; ++iter <= maxiters;) { + var interval = [0, bw - 1]; + for (var i = 0; i < n; ++i) { + var dx = xv[i]; + var i0 = interval[0]; + var i1 = interval[1]; + var edge = (dx - xv[i0]) > (xv[i1] - dx) ? i0 : i1; + var W = 0, X = 0, Y = 0, XY = 0, X2 = 0; + var denom = 1 / Math.abs(xv[edge] - dx || 1); + for (var k = i0; k <= i1; ++k) { + var xk = xv[k]; + var yk = yv[k]; + var w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k]; + var xkw = xk * w; + W += w; + X += xkw; + Y += yk * w; + XY += yk * xkw; + X2 += xk * xkw; + } + // Linear regression fit + var _b = ols(X / W, Y / W, XY / W, X2 / W), a = _b[0], b = _b[1]; + yhat[i] = a + b * dx; + residuals[i] = Math.abs(yv[i] - yhat[i]); + updateInterval(xv, i + 1, interval); + } + if (iter === maxiters) { + break; + } + var medianResidual = median(residuals); + if (Math.abs(medianResidual) < epsilon) + break; + for (var i = 0, arg = void 0, w = void 0; i < n; ++i) { + arg = residuals[i] / (6 * medianResidual); + // Default to epsilon (rather than zero) for large deviations + // Keeping weights tiny but non-zero prevents singularites + robustWeights[i] = (arg >= 1) ? epsilon : ((w = 1 - arg * arg) * w); + } + } + return output(xv, yhat, ux, uy); + }; + loessRegression.bandwidth = function (bw) { + if (!arguments.length) + return bandwidth; + bandwidth = bw; + return loessRegression; + }; + loessRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return loessRegression; + }; + loessRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return loessRegression; + }; + return loessRegression; + } + // Weighting kernel for local regression function tricube(x) { - return (x = 1 - x * x * x) * x * x; - } // Advance sliding window interval of nearest neighbors - - + return (x = 1 - x * x * x) * x * x; + } + // Advance sliding window interval of nearest neighbors function updateInterval(xv, i, interval) { - var val = xv[i], - left = interval[0], - right = interval[1] + 1; - if (right >= xv.length) return; // Step right if distance to new right edge is <= distance to old left edge - // Step when distance is equal to ensure movement over duplicate x values - - while (i > left && xv[right] - val <= val - xv[left]) { - interval[0] = ++left; - interval[1] = right; - ++right; - } - } // Generate smoothed output points + var val = xv[i], left = interval[0], right = interval[1] + 1; + if (right >= xv.length) + return; + // Step right if distance to new right edge is <= distance to old left edge + // Step when distance is equal to ensure movement over duplicate x values + while (i > left && (xv[right] - val) <= (val - xv[left])) { + interval[0] = ++left; + interval[1] = right; + ++right; + } + } + // Generate smoothed output points // Average points with repeated x values - - function output(xv, yhat, ux, uy) { - var n = xv.length, - out = []; - var i = 0, - cnt = 0, - prev = [], - v; - - for (; i < n; ++i) { - v = xv[i] + ux; - - if (prev[0] === v) { - // Average output values via online update - prev[1] += (yhat[i] - prev[1]) / ++cnt; - } else { - // Add new output point - cnt = 0; - prev[1] += uy; - prev = [v, yhat[i]]; - out.push(prev); + var n = xv.length, out = []; + var i = 0, cnt = 0, prev = [], v; + for (; i < n; ++i) { + v = xv[i] + ux; + if (prev[0] === v) { + // Average output values via online update + prev[1] += (yhat[i] - prev[1]) / (++cnt); + } + else { + // Add new output point + cnt = 0; + prev[1] += uy; + prev = [v, yhat[i]]; + out.push(prev); + } } - } - - prev[1] += uy; - return out; - } - - function logarithmic () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - base = Math.E, - domain; - - function logarithmic(data) { - var n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity, - lb = Math.log(base); - visitPoints(data, x, y, function (dx, dy) { - var lx = Math.log(dx) / lb; - ++n; - X += (lx - X) / n; - Y += (dy - Y) / n; - XY += (lx * dy - XY) / n; - X2 += (lx * lx - X2) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - intercept = _ols2[0], - slope = _ols2[1], - fn = function fn(x) { - return slope * Math.log(x) / lb + intercept; - }, - out = interpose(xmin, xmax, fn); - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); + prev[1] += uy; return out; - } - - logarithmic.domain = function (arr) { - return arguments.length ? (domain = arr, logarithmic) : domain; - }; - - logarithmic.x = function (fn) { - return arguments.length ? (x = fn, logarithmic) : x; - }; - - logarithmic.y = function (fn) { - return arguments.length ? (y = fn, logarithmic) : y; - }; - - logarithmic.base = function (n) { - return arguments.length ? (base = n, logarithmic) : base; - }; - - return logarithmic; } - function quad () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function quadratic(data) { - var _points = points(data, x, y), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length; - - var X2 = 0, - X3 = 0, - X4 = 0, - XY = 0, - X2Y = 0, - i, - dx, - dy, - x2; - - for (i = 0; i < n;) { - dx = xv[i]; - dy = yv[i++]; - x2 = dx * dx; - X2 += (x2 - X2) / i; - X3 += (x2 * dx - X3) / i; - X4 += (x2 * x2 - X4) / i; - XY += (dx * dy - XY) / i; - X2Y += (x2 * dy - X2Y) / i; - } - - var Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - n0++; - Y += (dy - Y) / n0; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var X2X2 = X4 - X2 * X2, - d = X2 * X2X2 - X3 * X3, - a = (X2Y * X2 - XY * X3) / d, - b = (XY * X2X2 - X2Y * X3) / d, - c = -a * X2, - fn = function fn(x) { - x = x - ux; - return a * x * x + b * x + c + uy; + function logarithmic() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, base = Math.E, domain; + var logarithmicRegression = function (data) { + var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity, lb = Math.log(base); + visitPoints(data, x, y, function (dx, dy) { + var lx = Math.log(dx) / lb; + ++n; + X += (lx - X) / n; + Y += (dy - Y) / n; + XY += (lx * dy - XY) / n; + X2 += (lx * lx - X2) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), intercept = _a[0], slope = _a[1]; + var fn = function (xx) { return slope * Math.log(xx) / lb + intercept; }; + var out = interpose(xmin, xmax, fn); + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; }; - - var out = interpose(xmin, xmax, fn); - out.a = a; - out.b = b - 2 * a * ux; - out.c = c - b * ux + a * ux * ux + uy; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - quadratic.domain = function (arr) { - return arguments.length ? (domain = arr, quadratic) : domain; - }; - - quadratic.x = function (fn) { - return arguments.length ? (x = fn, quadratic) : x; - }; - - quadratic.y = function (fn) { - return arguments.length ? (y = fn, quadratic) : y; - }; - - return quadratic; + logarithmicRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return logarithmicRegression; + }; + logarithmicRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return logarithmicRegression; + }; + logarithmicRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return logarithmicRegression; + }; + logarithmicRegression.base = function (b) { + if (!arguments.length) + return base; + base = b; + return logarithmicRegression; + }; + return logarithmicRegression; } - // Source: https://github.com/Tom-Alexander/regression-js/blob/master/src/regression.js#L246 - // License: https://github.com/Tom-Alexander/regression-js/blob/master/LICENSE - // ...with ideas from vega-statistics by Jeffrey Heer - // Source: https://github.com/vega/vega/blob/f21cb8792b4e0cbe2b1a3fd44b0f5db370dbaadb/packages/vega-statistics/src/regression/poly.js - // License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE - - function polynomial () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - order = 3, - domain; - - function polynomial(data) { - // Use more efficient methods for lower orders - if (order === 1) { - var o = linear().x(x).y(y).domain(domain)(data); - o.coefficients = [o.b, o.a]; - delete o.a; - delete o.b; - return o; - } - - if (order === 2) { - var _o = quad().x(x).y(y).domain(domain)(data); - - _o.coefficients = [_o.c, _o.b, _o.a]; - delete _o.a; - delete _o.b; - delete _o.c; - return _o; - } - - var _points = points(data, x, y), - _points2 = _slicedToArray(_points, 4), - xv = _points2[0], - yv = _points2[1], - ux = _points2[2], - uy = _points2[3], - n = xv.length, - lhs = [], - rhs = [], - k = order + 1; - - var Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - ++n0; - Y += (dy - Y) / n0; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - var i, j, l, v, c; - - for (i = 0; i < k; ++i) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i) * yv[l]; - } - - lhs.push(v); - c = new Float64Array(k); - - for (j = 0; j < k; ++j) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i + j); + function quadratic() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var quadraticRegression = function quadraticRegression(data) { + var _a = points(data, function (dd) { return x(dd); }, function (dd) { return y(dd); }), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var X2 = 0, X3 = 0, X4 = 0, XY = 0, X2Y = 0, i, dx, dy, x2; + for (i = 0; i < n;) { + dx = xv[i]; + dy = yv[i++]; + x2 = dx * dx; + X2 += (x2 - X2) / i; + X3 += ((x2 * dx) - X3) / i; + X4 += ((x2 * x2) - X4) / i; + XY += ((dx * dy) - XY) / i; + X2Y += ((x2 * dy) - X2Y) / i; } - - c[j] = v; - } - - rhs.push(c); - } - - rhs.push(lhs); - - var coef = gaussianElimination(rhs), - fn = function fn(x) { - x -= ux; - var y = uy + coef[0] + coef[1] * x + coef[2] * x * x; - - for (i = 3; i < k; ++i) { - y += coef[i] * Math.pow(x, i); - } - - return y; - }, - out = interpose(xmin, xmax, fn); - - out.coefficients = uncenter(k, coef, -ux, uy); - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - return out; - } - - polynomial.domain = function (arr) { - return arguments.length ? (domain = arr, polynomial) : domain; - }; - - polynomial.x = function (fn) { - return arguments.length ? (x = fn, polynomial) : x; - }; - - polynomial.y = function (fn) { - return arguments.length ? (y = fn, polynomial) : y; - }; - - polynomial.order = function (n) { - return arguments.length ? (order = n, polynomial) : order; - }; - - return polynomial; + var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx2, dy2) { + n0++; + Y += (dy2 - Y) / n0; + if (!domain) { + if (dx2 < xmin) + xmin = dx2; + if (dx2 > xmax) + xmax = dx2; + } + }); + var X2X2 = X4 - (X2 * X2); + var d = (X2 * X2X2 - X3 * X3); + var a = (X2Y * X2 - XY * X3) / d; + var b = (XY * X2X2 - X2Y * X3) / d; + var c = -a * X2; + var fn = function (xx) { + var shifted = xx - ux; + return a * shifted * shifted + b * shifted + c + uy; + }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b - 2 * a * ux; + out.c = c - b * ux + a * ux * ux + uy; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + quadraticRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return quadraticRegression; + }; + quadraticRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return quadraticRegression; + }; + quadraticRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return quadraticRegression; + }; + return quadraticRegression; } + // Adapted from regression-js by Tom Alexander + function polynomial() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, order = 3, domain; + var polynomialRegression = function polynomialRegression(data) { + // Shortcut for lower-order polynomials: + if (order === 1) { + var o = linear().x(x).y(y).domain(domain)(data); + var result = [o[0], o[1]]; + result.coefficients = [o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + if (order === 2) { + var o = quadratic().x(x).y(y).domain(domain)(data); + var result = [o[0], o[1]]; + result.coefficients = [o.c, o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + var _a = points(data, x, y), xv = _a[0], yv = _a[1], ux = _a[2], uy = _a[3]; + var n = xv.length; + var k = order + 1; + var lhs = []; + var rhs = []; + var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + n0++; + Y += (dy - Y) / n0; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + // Build normal equations + for (var i = 0; i < k; i++) { + // LHS + var v = 0; + for (var l = 0; l < n; l++) { + v += Math.pow(xv[l], i) * yv[l]; + } + lhs.push(v); + // RHS + var c = new Float64Array(k); + for (var j = 0; j < k; j++) { + var v2 = 0; + for (var l = 0; l < n; l++) { + v2 += Math.pow(xv[l], i + j); + } + c[j] = v2; + } + rhs.push(c); + } + rhs.push(new Float64Array(lhs)); + var coef = gaussianElimination(rhs); + var fn = function (xx) { + var shifted = xx - ux; + var val = uy + coef[0]; + for (var i = 1; i < k; i++) { + val += coef[i] * Math.pow(shifted, i); + } + return val; + }; + var out = interpose(xmin, xmax, fn); + out.coefficients = uncenter(k, coef, -ux, uy); + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + return out; + }; + polynomialRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return polynomialRegression; + }; + polynomialRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return polynomialRegression; + }; + polynomialRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return polynomialRegression; + }; + polynomialRegression.order = function (n) { + if (!arguments.length) + return order; + order = n; + return polynomialRegression; + }; + return polynomialRegression; + } function uncenter(k, a, x, y) { - var z = Array(k); - var i, j, v, c; // initialize to zero - - for (i = 0; i < k; ++i) { - z[i] = 0; - } // polynomial expansion - - - for (i = k - 1; i >= 0; --i) { - v = a[i]; - c = 1; - z[i] += v; - - for (j = 1; j <= i; ++j) { - c *= (i + 1 - j) / j; // binomial coefficent - - z[i - j] += v * Math.pow(x, j) * c; + var z = new Array(k).fill(0); + for (var i = k - 1; i >= 0; --i) { + var v = a[i]; + z[i] += v; + var c = 1; + for (var j = 1; j <= i; ++j) { + c *= (i + 1 - j) / j; // binomial coefficient + z[i - j] += v * Math.pow(x, j) * c; + } } - } // bias term - - - z[0] += y; - return z; - } // Given an array for a two-dimensional matrix and the polynomial order, - // solve A * x = b using Gaussian elimination. - - + // bias term + z[0] += y; + return z; + } + // Solve A * x = b using Gaussian elimination function gaussianElimination(matrix) { - var n = matrix.length - 1, - coef = []; - var i, j, k, r, t; - - for (i = 0; i < n; ++i) { - r = i; // max row - - for (j = i + 1; j < n; ++j) { - if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { - r = j; - } - } - - for (k = i; k < n + 1; ++k) { - t = matrix[k][i]; - matrix[k][i] = matrix[k][r]; - matrix[k][r] = t; - } - - for (j = i + 1; j < n; ++j) { - for (k = n; k >= i; k--) { - matrix[k][j] -= matrix[k][i] * matrix[i][j] / matrix[i][i]; - } + var n = matrix.length - 1; + var coef = new Array(n); + for (var i = 0; i < n; i++) { + var r = i; + // find pivot row + for (var j = i + 1; j < n; j++) { + if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { + r = j; + } + } + // swap columns + for (var k = i; k < n + 1; k++) { + var t = matrix[k][i]; + matrix[k][i] = matrix[k][r]; + matrix[k][r] = t; + } + // reduce + for (var j = i + 1; j < n; j++) { + for (var k = n; k >= i; k--) { + matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i]; + } + } } - } - - for (j = n - 1; j >= 0; --j) { - t = 0; - - for (k = j + 1; k < n; ++k) { - t += matrix[k][j] * coef[k]; + for (var j = n - 1; j >= 0; j--) { + var t = 0; + for (var k = j + 1; k < n; k++) { + t += matrix[k][j] * coef[k]; + } + coef[j] = (matrix[n][j] - t) / matrix[j][j]; } - - coef[j] = (matrix[n][j] - t) / matrix[j][j]; - } - - return coef; + return coef; } - function power () { - var x = function x(d) { - return d[0]; - }, - y = function y(d) { - return d[1]; - }, - domain; - - function power(data) { - var n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - YS = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - visitPoints(data, x, y, function (dx, dy) { - var lx = Math.log(dx), - ly = Math.log(dy); - ++n; - X += (lx - X) / n; - Y += (ly - Y) / n; - XY += (lx * ly - XY) / n; - X2 += (lx * lx - X2) / n; - YS += (dy - YS) / n; - - if (!domain) { - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - var _ols = ols(X, Y, XY, X2), - _ols2 = _slicedToArray(_ols, 2), - a = _ols2[0], - b = _ols2[1]; - - a = Math.exp(a); - - var fn = function fn(x) { - return a * Math.pow(x, b); - }, - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, YS, fn); - return out; - } - - power.domain = function (arr) { - return arguments.length ? (domain = arr, power) : domain; - }; - - power.x = function (fn) { - return arguments.length ? (x = fn, power) : x; - }; - - power.y = function (fn) { - return arguments.length ? (y = fn, power) : y; - }; + function power() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain; + var powerRegression = function powerRegression(data) { + var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, YS = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity; + visitPoints(data, x, y, function (dx, dy) { + var lx = Math.log(dx), ly = Math.log(dy); + ++n; + X += (lx - X) / n; + Y += (ly - Y) / n; + XY += (lx * ly - XY) / n; + X2 += (lx * lx - X2) / n; + YS += (dy - YS) / n; + if (!domain) { + if (dx < xmin) + xmin = dx; + if (dx > xmax) + xmax = dx; + } + }); + var _a = ols(X, Y, XY, X2), a = _a[0], b = _a[1]; + a = Math.exp(a); + var fn = function (xx) { return a * Math.pow(xx, b); }; + var out = interpose(xmin, xmax, fn); + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, YS, fn); + return out; + }; + powerRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return powerRegression; + }; + powerRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return powerRegression; + }; + powerRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return powerRegression; + }; + return powerRegression; + } - return power; + function sigmoidal() { + var x = function (d) { return d[0]; }, y = function (d) { return d[1]; }, domain, maxIter = 2000, alpha = 1e-4; // learning rate + function sigmoidalRegression(data) { + var n = 0, Xmin = domain ? +domain[0] : Infinity, Xmax = domain ? +domain[1] : -Infinity, Ymin = Infinity, Ymax = -Infinity, sumY = 0; + // Gather data & track min/max for domain if not preset + visitPoints(data, x, y, function (dx, dy) { + n++; + sumY += dy; + if (!domain) { + if (dx < Xmin) + Xmin = dx; + if (dx > Xmax) + Xmax = dx; + } + if (dy < Ymin) + Ymin = dy; + if (dy > Ymax) + Ymax = dy; + }); + if (!domain && (Xmin === Infinity || Xmax === -Infinity)) { + Xmin = 0; + Xmax = 1; + } + // Initialize parameters + var A = Ymax - Ymin; // amplitude + var B = 1; // logistic slope + var C = Ymin; // baseline offset + var M = (Xmin + Xmax) / 2; // midpoint + // Predict function + function f(xx) { + return C + A / (1 + Math.exp(-B * (xx - M))); + } + var _loop_1 = function (iter) { + var dA = 0, dB = 0, dC = 0, dM = 0; + visitPoints(data, x, y, function (dx, dy) { + var yhat = f(dx); + var err = dy - yhat; + var ex = Math.exp(-B * (dx - M)); + var g = 1 / (1 + ex); // logistic + // partial derivatives + var df_dA = g; + var df_dC = 1; + var df_dB = A * g * (1 - g) * (dx - M); + // Note the negative sign for M: + var df_dM = -A * B * g * (1 - g); + var factor = -2 * err; + dA += factor * df_dA; + dB += factor * df_dB; + dC += factor * df_dC; + dM += factor * df_dM; + }); + A -= alpha * (dA / n); + B -= alpha * (dB / n); + C -= alpha * (dC / n); + M -= alpha * (dM / n); + }; + // Gradient Descent + for (var iter = 0; iter < maxIter; iter++) { + _loop_1(); + } + var predict = function (xx) { return C + A / (1 + Math.exp(-B * (xx - M))); }; + var out = interpose(Xmin, Xmax, predict); + out.A = A; + out.B = B; + out.C = C; + out.M = M; + out.predict = predict; + // R^2 + var meanY = sumY / n; + out.rSquared = determination(data, x, y, meanY, predict); + return out; + } + sigmoidalRegression.domain = function (arr) { + if (!arguments.length) + return domain; + domain = arr; + return sigmoidalRegression; + }; + sigmoidalRegression.x = function (fn) { + if (!arguments.length) + return x; + x = fn; + return sigmoidalRegression; + }; + sigmoidalRegression.y = function (fn) { + if (!arguments.length) + return y; + y = fn; + return sigmoidalRegression; + }; + return sigmoidalRegression; } exports.regressionExp = exponential; @@ -878,7 +769,8 @@ exports.regressionLog = logarithmic; exports.regressionPoly = polynomial; exports.regressionPow = power; - exports.regressionQuad = quad; + exports.regressionQuad = quadratic; + exports.regressionSigmoidal = sigmoidal; Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/dist/d3-regression.min.js b/dist/d3-regression.min.js index 1a93fd8..1227620 100644 --- a/dist/d3-regression.min.js +++ b/dist/d3-regression.min.js @@ -1 +1 @@ -!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):(n=n||self,r(n.d3={}))}(this,function(n){"use strict";function r(n,r){return t(n)||e(n,r)||u()}function t(n){if(Array.isArray(n))return n}function e(n,r){var t=[],e=!0,u=!1,o=void 0;try{for(var i,a=n[Symbol.iterator]();!(e=(i=a.next()).done)&&(t.push(i.value),!r||t.length!==r);e=!0);}catch(n){u=!0,o=n}finally{try{e||null==a.return||a.return()}finally{if(u)throw o}}return t}function u(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function o(n,r,t,e){n=n.filter(function(n,e){var u=r(n,e),o=t(n,e);return null!=u&&isFinite(u)&&null!=o&&isFinite(o)}),e&&n.sort(function(n,t){return r(n)-r(t)});for(var u,o,i,a=n.length,f=new Float64Array(a),c=new Float64Array(a),l=0,h=0,v=0;vo&&(n.splice(u+1,0,v),t=!0)}return t}(i)&&a<1e4;);return i}function h(n,r,t,e){var u=e-n*n,o=Math.abs(u)<1e-24?0:(t-n*r)/u;return[r-o*n,o]}function v(){function n(n){var o=0,f=0,c=0,v=0,s=0,g=0,d=t?+t[0]:1/0,p=t?+t[1]:-1/0;i(n,e,u,function(n,r){var e=Math.log(r),u=n*r;++o,f+=(r-f)/o,v+=(u-v)/o,g+=(n*u-g)/o,c+=(r*e-c)/o,s+=(u*e-s)/o,t||(np&&(p=n))});var M=h(v/f,c/f,s/f,g/f),y=r(M,2),b=y[0],x=y[1];b=Math.exp(b);var w=function(n){return b*Math.exp(x*n)},m=l(d,p,w);return m.a=b,m.b=x,m.predict=w,m.rSquared=a(n,e,u,f,w),m}var t,e=function(n){return n[0]},u=function(n){return n[1]};return n.domain=function(r){return arguments.length?(t=r,n):t},n.x=function(r){return arguments.length?(e=r,n):e},n.y=function(r){return arguments.length?(u=r,n):u},n}function s(){function n(n){var o=0,f=0,c=0,l=0,v=0,s=t?+t[0]:1/0,g=t?+t[1]:-1/0;i(n,e,u,function(n,r){++o,f+=(n-f)/o,c+=(r-c)/o,l+=(n*r-l)/o,v+=(n*n-v)/o,t||(ng&&(g=n))});var d=h(f,c,l,v),p=r(d,2),M=p[0],y=p[1],b=function(n){return y*n+M},x=[[s,b(s)],[g,b(g)]];return x.a=y,x.b=M,x.predict=b,x.rSquared=a(n,e,u,c,b),x}var t,e=function(n){return n[0]},u=function(n){return n[1]};return n.domain=function(r){return arguments.length?(t=r,n):t},n.x=function(r){return arguments.length?(e=r,n):e},n.y=function(r){return arguments.length?(u=r,n):u},n}function g(n){n.sort(function(n,r){return n-r});var r=n.length/2;return r%1==0?(n[r-1]+n[r])/2:n[Math.floor(r)]}function d(){function n(n){for(var i=o(n,t,e,!0),a=r(i,4),f=a[0],c=a[1],l=a[2],v=a[3],s=f.length,d=Math.max(2,~~(u*s)),b=new Float64Array(s),x=new Float64Array(s),w=new Float64Array(s).fill(1),m=-1;++m<=S;){for(var F=[0,d-1],A=0;Af[P]-E?L:P,k=0,I=0,O=0,_=0,G=0,Q=1/Math.abs(f[j]-E||1),T=L;T<=P;++T){var z=f[T],B=c[T],C=p(Math.abs(E-z)*Q)*w[T],D=z*C;k+=C,I+=D,O+=B*C,_+=B*D,G+=z*D}var H=h(I/k,O/k,_/k,G/k),J=r(H,2),K=J[0],N=J[1];b[A]=K+N*E,x[A]=Math.abs(c[A]-b[A]),M(f,A+1,F)}if(m===S)break;var R=g(x);if(Math.abs(R)=1?q:(V=1-U*U)*V}return y(f,b,l,v)}var t=function(n){return n[0]},e=function(n){return n[1]},u=.3;return n.bandwidth=function(r){return arguments.length?(u=r,n):u},n.x=function(r){return arguments.length?(t=r,n):t},n.y=function(r){return arguments.length?(e=r,n):e},n}function p(n){return(n=1-n*n*n)*n*n}function M(n,r,t){var e=n[r],u=t[0],o=t[1]+1;if(!(o>=n.length))for(;r>u&&n[o]-e<=e-n[u];)t[0]=++u,t[1]=o,++o}function y(n,r,t,e){for(var u,o=n.length,i=[],a=0,f=0,c=[];ap&&(p=n))});var y=h(c,v,s,g),b=r(y,2),x=b[0],w=b[1],m=function(n){return w*Math.log(n)/M+x},F=l(d,p,m);return F.a=w,F.b=x,F.predict=m,F.rSquared=a(n,e,u,v,m),F}var t,e=function(n){return n[0]},u=function(n){return n[1]},o=Math.E;return n.domain=function(r){return arguments.length?(t=r,n):t},n.x=function(r){return arguments.length?(e=r,n):e},n.y=function(r){return arguments.length?(u=r,n):u},n.base=function(r){return arguments.length?(o=r,n):o},n}function x(){function n(n){var f,c,h,v,s=o(n,e,u),g=r(s,4),d=g[0],p=g[1],M=g[2],y=g[3],b=d.length,x=0,w=0,m=0,F=0,A=0;for(f=0;fL&&(L=n))});var P=m-x*x,j=x*P-w*w,k=(A*x-F*w)/j,I=(F*P-A*w)/j,O=-k*x,_=function(n){return n-=M,k*n*n+I*n+O+y},G=l(E,L,_);return G.a=k,G.b=I-2*k*M,G.c=O-I*M+k*M*M+y,G.predict=_,G.rSquared=a(n,e,u,S,_),G}var t,e=function(n){return n[0]},u=function(n){return n[1]};return n.domain=function(r){return arguments.length?(t=r,n):t},n.x=function(r){return arguments.length?(e=r,n):e},n.y=function(r){return arguments.length?(u=r,n):u},n}function w(){function n(n){if(1===f){var c=s().x(e).y(u).domain(t)(n);return c.coefficients=[c.b,c.a],delete c.a,delete c.b,c}if(2===f){var h=x().x(e).y(u).domain(t)(n);return h.coefficients=[h.c,h.b,h.a],delete h.a,delete h.b,delete h.c,h}var v=o(n,e,u),g=r(v,4),d=g[0],p=g[1],M=g[2],y=g[3],b=d.length,w=[],A=[],S=f+1,q=0,E=0,L=t?+t[0]:1/0,P=t?+t[1]:-1/0;i(n,e,u,function(n,r){++E,q+=(r-q)/E,t||(nP&&(P=n))});var j,k,I,O,_;for(j=0;j=0;--u)for(i=r[u],a=1,f[u]+=i,o=1;o<=u;++o)a*=(u+1-o)/o,f[u-o]+=i*Math.pow(t,o)*a;return f[0]+=e,f}function F(n){var r,t,e,u,o,i=n.length-1,a=[];for(r=0;rMath.abs(n[r][u])&&(u=t);for(e=r;e=r;e--)n[e][t]-=n[e][r]*n[r][t]/n[r][r]}for(t=i-1;t>=0;--t){for(o=0,e=t+1;ep&&(p=n))});var M=h(f,c,v,s),y=r(M,2),b=y[0],x=y[1];b=Math.exp(b);var w=function(n){return b*Math.pow(n,x)},m=l(d,p,w);return m.a=b,m.b=x,m.predict=w,m.rSquared=a(n,e,u,g,w),m}var t,e=function(n){return n[0]},u=function(n){return n[1]};return n.domain=function(r){return arguments.length?(t=r,n):t},n.x=function(r){return arguments.length?(e=r,n):e},n.y=function(r){return arguments.length?(u=r,n):u},n}var S=2,q=1e-12;n.regressionExp=v,n.regressionLinear=s,n.regressionLoess=d,n.regressionLog=b,n.regressionPoly=w,n.regressionPow=A,n.regressionQuad=x,Object.defineProperty(n,"__esModule",{value:!0})}); \ No newline at end of file +!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):(n=n||self,r(n.d3={}))}(this,function(n){"use strict";function r(n,r,t,e){n=n.filter(function(n,e){var u=r(n,e),o=t(n,e);return null!=u&&isFinite(u)&&null!=o&&isFinite(o)}),e&&n.sort(function(n,t){return r(n)-r(t)});for(var u,o,a,i=n.length,f=new Float64Array(i),c=new Float64Array(i),v=0,h=0,l=0;li&&(n.splice(a+1,0,l),t=!0)}return t}(f)&&c<1e4;);return f}function i(n,r,t,e){var u=e-n*n,o=Math.abs(u)<1e-24?0:(t-n*r)/u;return[r-o*n,o]}function f(){var n,r=function(n){return n[1]},u=function(n){return n[0]},o=function(o){var f=0,c=0,v=0,h=0,l=0,g=0,s=n?+n[0]:1/0,d=n?+n[1]:-1/0;t(o,u,r,function(r,t){var e=Math.log(t),u=r*t;++f,c+=(t-c)/f,h+=(u-h)/f,g+=(r*u-g)/f,v+=(t*e-v)/f,l+=(u*e-l)/f,n||(rd&&(d=r))});var p=i(h/c,v/c,l/c,g/c),M=p[0],y=p[1];M=Math.exp(M);var b=function(n){return M*Math.exp(y*n)},x=a(s,d,b);return x.a=M,x.b=y,x.predict=b,x.rSquared=e(o,u,r,c,b),x};return o.domain=function(r){return arguments.length?(n=r,o):n},o.x=function(n){return arguments.length?(u=n,o):u},o.y=function(n){return arguments.length?(r=n,o):r},o}function c(){var n,r=function(n){return n[0]},u=function(n){return n[1]},o=function(o){var a=0,f=0,c=0,v=0,h=0,l=n?+n[0]:1/0,g=n?+n[1]:-1/0;t(o,r,u,function(r,t){++a,f+=(r-f)/a,c+=(t-c)/a,v+=(r*t-v)/a,h+=(r*r-h)/a,n||(rg&&(g=r))});var s=i(f,c,v,h),d=s[0],p=s[1],M=function(n){return p*n+d},y=[[l,M(l)],[g,M(g)]];return y.a=p,y.b=d,y.predict=M,y.rSquared=e(o,r,u,c,M),y};return o.domain=function(r){return arguments.length?(n=r,o):n},o.x=function(n){return arguments.length?(r=n,o):r},o.y=function(n){return arguments.length?(u=n,o):u},o}function v(n){n.sort(function(n,r){return n-r});var r=n.length/2;return r%1==0?(n[r-1]+n[r])/2:n[Math.floor(r)]}function h(){var n=function(n){return n[0]},t=function(n){return n[1]},e=.3,u=function(u){for(var o=r(u,function(r){return n(r)},function(n){return t(n)},!0),a=o[0],f=o[1],c=o[2],h=o[3],d=a.length,p=Math.max(2,~~(e*d)),M=new Float64Array(d),y=new Float64Array(d),b=new Float64Array(d).fill(1),x=-1;++x<=m;){for(var w=[0,p-1],q=0;qa[L]-F?A:L,E=0,j=0,k=0,O=0,_=0,B=1/Math.abs(a[P]-F||1),C=A;C<=L;++C){var G=a[C],I=f[C],Q=l(Math.abs(F-G)*B)*b[C],z=G*Q;E+=Q,j+=z,k+=I*Q,O+=I*z,_+=G*z}var D=i(j/E,k/E,O/E,_/E),H=D[0],J=D[1];M[q]=H+J*F,y[q]=Math.abs(f[q]-M[q]),g(a,q+1,w)}if(x===m)break;var K=v(y);if(Math.abs(K)=1?S:(Q=1-N*N)*Q}return s(a,M,c,h)};return u.bandwidth=function(n){return arguments.length?(e=n,u):e},u.x=function(r){return arguments.length?(n=r,u):n},u.y=function(n){return arguments.length?(t=n,u):t},u}function l(n){return(n=1-n*n*n)*n*n}function g(n,r,t){var e=n[r],u=t[0],o=t[1]+1;if(!(o>=n.length))for(;r>u&&n[o]-e<=e-n[u];)t[0]=++u,t[1]=o,++o}function s(n,r,t,e){for(var u,o=n.length,a=[],i=0,f=0,c=[];id&&(d=r))});var M=i(v,h,l,g),y=M[0],b=M[1],x=function(n){return b*Math.log(n)/p+y},w=a(s,d,x);return w.a=b,w.b=y,w.predict=x,w.rSquared=e(f,r,u,h,x),w};return f.domain=function(r){return arguments.length?(n=r,f):n},f.x=function(n){return arguments.length?(r=n,f):r},f.y=function(n){return arguments.length?(u=n,f):u},f.base=function(n){return arguments.length?(o=n,f):o},f}function p(){var n,u=function(n){return n[0]},o=function(n){return n[1]},i=function(i){var f,c,v,h,l=r(i,function(n){return u(n)},function(n){return o(n)}),g=l[0],s=l[1],d=l[2],p=l[3],M=g.length,y=0,b=0,x=0,w=0,m=0;for(f=0;fA&&(A=r))});var L=x-y*y,P=y*L-b*b,E=(m*y-w*b)/P,j=(w*L-m*b)/P,k=-E*y,O=function(n){var r=n-d;return E*r*r+j*r+k+p},_=a(F,A,O);return _.a=E,_.b=j-2*E*d,_.c=k-j*d+E*d*d+p,_.predict=O,_.rSquared=e(i,u,o,S,O),_};return i.domain=function(r){return arguments.length?(n=r,i):n},i.x=function(n){return arguments.length?(u=n,i):u},i.y=function(n){return arguments.length?(o=n,i):o},i}function M(){var n,u=function(n){return n[0]},o=function(n){return n[1]},i=3,f=function(f){if(1===i){var v=c().x(u).y(o).domain(n)(f),h=[v[0],v[1]];return h.coefficients=[v.b,v.a],h.predict=v.predict,h.rSquared=v.rSquared,h}if(2===i){var v=p().x(u).y(o).domain(n)(f),h=[v[0],v[1]];return h.coefficients=[v.c,v.b,v.a],h.predict=v.predict,h.rSquared=v.rSquared,h}var l=r(f,u,o),g=l[0],s=l[1],d=l[2],M=l[3],x=g.length,w=i+1,m=[],S=[],q=0,F=0,A=n?+n[0]:1/0,L=n?+n[1]:-1/0;t(f,u,o,function(r,t){F++,q+=(t-q)/F,n||(rL&&(L=r))});for(var P=0;P=0;--o){var a=r[o];u[o]+=a;for(var i=1,f=1;f<=o;++f)i*=(o+1-f)/f,u[o-f]+=a*Math.pow(t,f)*i}return u[0]+=e,u}function b(n){for(var r=n.length-1,t=new Array(r),e=0;eMath.abs(n[e][u])&&(u=o);for(var a=e;a=e;a--)n[a][o]-=n[a][e]*n[e][o]/n[e][e]}for(var o=r-1;o>=0;o--){for(var i=0,a=o+1;ad&&(d=r))});var p=i(c,v,h,l),M=p[0],y=p[1];M=Math.exp(M);var b=function(n){return M*Math.pow(n,y)},x=a(s,d,b);return x.a=M,x.b=y,x.predict=b,x.rSquared=e(o,r,u,g,b),x};return o.domain=function(r){return arguments.length?(n=r,o):n},o.x=function(n){return arguments.length?(r=n,o):r},o.y=function(n){return arguments.length?(u=n,o):u},o}function w(){function n(n){function c(n){return y+p/(1+Math.exp(-M*(n-b)))}var v=0,h=r?+r[0]:1/0,l=r?+r[1]:-1/0,g=1/0,s=-1/0,d=0;t(n,u,o,function(n,t){v++,d+=t,r||(nl&&(l=n)),ts&&(s=t)}),r||h!==1/0&&l!==-1/0||(h=0,l=1);for(var p=s-g,M=1,y=g,b=(h+l)/2,x=0;x { + (data: T[]): ExponentialOutput; + domain(): Domain; + domain(arr: Domain): this; + x(): Accessor; + x(fn: Accessor): this; + y(): Accessor; + y(fn: Accessor): this; +} +export default function exponential(): ExponentialRegression; diff --git a/dist/src/linear.d.ts b/dist/src/linear.d.ts new file mode 100644 index 0000000..7857536 --- /dev/null +++ b/dist/src/linear.d.ts @@ -0,0 +1,17 @@ +import { PredictFunction, Accessor, DataPoint, Domain } from "./types"; +export type LinearOutput = [DataPoint, DataPoint] & { + a: number; + b: number; + predict: PredictFunction; + rSquared: number; +}; +export interface LinearRegression { + (data: T[]): LinearOutput; + domain(): Domain; + domain(arr: Domain): this; + x(): Accessor; + x(fn: Accessor): this; + y(): Accessor; + y(fn: Accessor): this; +} +export default function linear(): LinearRegression; diff --git a/dist/src/loess.d.ts b/dist/src/loess.d.ts new file mode 100644 index 0000000..ec2f0e6 --- /dev/null +++ b/dist/src/loess.d.ts @@ -0,0 +1,11 @@ +import { Accessor, DataPoint } from "./types"; +export interface LoessRegression { + (data: T[]): DataPoint[]; + bandwidth(): number; + bandwidth(bw: number): this; + x(): Accessor; + x(fn: Accessor): this; + y(): Accessor; + y(fn: Accessor): this; +} +export default function loess(): LoessRegression; diff --git a/dist/src/logarithmic.d.ts b/dist/src/logarithmic.d.ts new file mode 100644 index 0000000..1420628 --- /dev/null +++ b/dist/src/logarithmic.d.ts @@ -0,0 +1,20 @@ +import { PredictFunction, DataPoint, Accessor, Domain } from "./types"; +type LogarithmicOutput = [DataPoint, DataPoint] & { + a: number; + b: number; + predict: PredictFunction; + rSquared: number; +}; +export interface LogarithmicRegression { + (data: T[]): LogarithmicOutput; + domain(): Domain; + domain(arr: Domain): this; + x(): Accessor; + x(fn: Accessor): this; + y(): Accessor; + y(fn: Accessor): this; + base(): number; + base(b: number): this; +} +export default function logarithmic(): LogarithmicRegression; +export {}; diff --git a/dist/src/polynomial.d.ts b/dist/src/polynomial.d.ts new file mode 100644 index 0000000..b32400a --- /dev/null +++ b/dist/src/polynomial.d.ts @@ -0,0 +1,18 @@ +import { PredictFunction, Accessor, DataPoint, Domain } from "./types"; +export type PolynomialOutput = [DataPoint, DataPoint] & { + coefficients: number[]; + predict: PredictFunction; + rSquared: number; +}; +export interface PolynomialRegression { + (data: T[]): PolynomialOutput; + domain(): Domain; + domain(domain?: Domain): this; + x(): Accessor; + x(x: Accessor): this; + y(): Accessor; + y(y: Accessor): this; + order(): number; + order(order: number): this; +} +export default function polynomial(): PolynomialRegression; diff --git a/dist/src/power.d.ts b/dist/src/power.d.ts new file mode 100644 index 0000000..c6b8f9a --- /dev/null +++ b/dist/src/power.d.ts @@ -0,0 +1,18 @@ +import { PredictFunction, DataPoint, Accessor, Domain } from "./types"; +export type PowerOutput = [DataPoint, DataPoint] & { + a: number; + b: number; + predict: PredictFunction; + rSquared: number; +}; +interface PowerRegression { + (data: T[]): PowerOutput; + domain(): Domain; + domain(domain?: Domain): this; + x(): Accessor; + x(x: Accessor): this; + y(): Accessor; + y(y: Accessor): this; +} +export default function power(): PowerRegression; +export {}; diff --git a/dist/src/quadratic.d.ts b/dist/src/quadratic.d.ts new file mode 100644 index 0000000..15c6567 --- /dev/null +++ b/dist/src/quadratic.d.ts @@ -0,0 +1,19 @@ +import { Accessor, DataPoint, PredictFunction, Domain } from "./types"; +export type QuadraticOutput = [DataPoint, DataPoint] & { + a: number; + b: number; + c: number; + predict: PredictFunction; + rSquared: number; +}; +interface QuadraticRegression { + (data: T[]): QuadraticOutput; + domain(): Domain; + domain(domain?: Domain): this; + x(): Accessor; + x(x: Accessor): this; + y(): Accessor; + y(y: Accessor): this; +} +export default function quadratic(): QuadraticRegression; +export {}; diff --git a/dist/src/sigmoidal.d.ts b/dist/src/sigmoidal.d.ts new file mode 100644 index 0000000..b7ffe6f --- /dev/null +++ b/dist/src/sigmoidal.d.ts @@ -0,0 +1,24 @@ +import { PredictFunction, Domain, DataPoint, Accessor } from "./types"; +/** + * Sigmoidal (logistic) regression of the form: + * f(x) = C + A / (1 + exp(-B * (x - M))) + * where A, B, C, M are parameters found via gradient descent. + */ +export type SigmoidalOutput = [DataPoint, DataPoint] & { + A: number; + B: number; + C: number; + M: number; + predict: PredictFunction; + rSquared: number; +}; +export interface SigmoidalRegression { + (data: T[]): SigmoidalOutput; + domain(): Domain; + domain(domain: Domain): this; + x(): Accessor; + x(fn: Accessor): this; + y(): Accessor; + y(fn: Accessor): this; +} +export default function sigmoidal(): SigmoidalRegression; diff --git a/dist/src/types.d.ts b/dist/src/types.d.ts new file mode 100644 index 0000000..f31848d --- /dev/null +++ b/dist/src/types.d.ts @@ -0,0 +1,4 @@ +export type DataPoint = [number, number]; +export type Accessor = (d: T, i?: number, data?: T[]) => number; +export type PredictFunction = (x: number) => number; +export type Domain = [number, number] | undefined; diff --git a/dist/src/utils/determination.d.ts b/dist/src/utils/determination.d.ts new file mode 100644 index 0000000..69bbed2 --- /dev/null +++ b/dist/src/utils/determination.d.ts @@ -0,0 +1,6 @@ +import { Accessor, PredictFunction } from "../types"; +/** + * Given a dataset, x- and y-accessors, the mean center of the y-values (uY), + * and a prediction function, return the coefficient of determination, R^2. + */ +export declare function determination(data: T[], x: Accessor, y: Accessor, uY: number, predict: PredictFunction): number; diff --git a/dist/src/utils/geometry.d.ts b/dist/src/utils/geometry.d.ts new file mode 100644 index 0000000..b6f871f --- /dev/null +++ b/dist/src/utils/geometry.d.ts @@ -0,0 +1,9 @@ +import { DataPoint } from "../types"; +/** + * Returns the angle of a line in degrees. + */ +export declare function angle(line: [DataPoint, DataPoint]): number; +/** + * Returns the midpoint of a line. + */ +export declare function midpoint(line: [DataPoint, DataPoint]): DataPoint; diff --git a/dist/src/utils/interpose.d.ts b/dist/src/utils/interpose.d.ts new file mode 100644 index 0000000..1c5dd07 --- /dev/null +++ b/dist/src/utils/interpose.d.ts @@ -0,0 +1,6 @@ +import { PredictFunction, DataPoint } from "../types"; +/** + * Given a start point (xmin), an end point (xmax), + * and a prediction function, returns a smooth line. + */ +export declare function interpose(xmin: number, xmax: number, predict: PredictFunction): [DataPoint, DataPoint]; diff --git a/dist/src/utils/median.d.ts b/dist/src/utils/median.d.ts new file mode 100644 index 0000000..0022487 --- /dev/null +++ b/dist/src/utils/median.d.ts @@ -0,0 +1,4 @@ +/** + * Returns the median value of an array of numbers. + */ +export declare function median(arr: Float64Array): number; diff --git a/dist/src/utils/ols.d.ts b/dist/src/utils/ols.d.ts new file mode 100644 index 0000000..fbca901 --- /dev/null +++ b/dist/src/utils/ols.d.ts @@ -0,0 +1,6 @@ +/** + * Ordinary Least Squares from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js + */ +export declare function ols(uX: number, uY: number, uXY: number, uX2: number): [number, number]; diff --git a/dist/src/utils/points.d.ts b/dist/src/utils/points.d.ts new file mode 100644 index 0000000..f471c45 --- /dev/null +++ b/dist/src/utils/points.d.ts @@ -0,0 +1,11 @@ +import { Accessor } from "../types"; +/** + * Adapted from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js + */ +export declare function points(data: T[], x: Accessor, y: Accessor, sort?: boolean): [Float64Array, Float64Array, number, number]; +/** + * Iterates over valid data points, invoking a callback for each. + */ +export declare function visitPoints(data: T[], x: Accessor, y: Accessor, cb: (dx: number, dy: number, index: number) => void): void; diff --git a/index.js b/index.ts similarity index 73% rename from index.js rename to index.ts index 3159d4e..d90ba6e 100644 --- a/index.js +++ b/index.ts @@ -4,4 +4,5 @@ export {default as regressionLoess} from "./src/loess"; export {default as regressionLog} from "./src/logarithmic"; export {default as regressionPoly} from "./src/polynomial"; export {default as regressionPow} from "./src/power"; -export {default as regressionQuad} from "./src/quadratic"; \ No newline at end of file +export {default as regressionQuad} from "./src/quadratic"; +export {default as regressionSigmoidal} from "./src/sigmoidal"; diff --git a/package-lock.json b/package-lock.json index cb1315d..3a163ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,44 @@ { "name": "d3-regression", "version": "1.3.10", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@babel/code-frame": { + "packages": { + "": { + "name": "d3-regression", + "version": "1.3.10", + "license": "BSD-3-Clause", + "devDependencies": { + "@babel/core": "^7.4.4", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/preset-env": "^7.4.4", + "babel": "^6.23.0", + "package-preamble": "^0.1.0", + "rollup": "^2.10.0", + "rollup-plugin-babel": "^4.4.0", + "rollup-plugin-commonjs": "^10.1.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-typescript2": "^0.35.0", + "tape": "^4.10.1", + "typescript": "^4.9.5", + "uglify-js": "^2.8.29" + } + }, + "node_modules/@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, - "requires": { + "dependencies": { "@babel/highlight": "^7.0.0" } }, - "@babel/core": { + "node_modules/@babel/core": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.4.tgz", "integrity": "sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.0.0", "@babel/generator": "^7.4.4", "@babel/helpers": "^7.4.4", @@ -34,93 +54,100 @@ "semver": "^5.4.1", "source-map": "^0.5.0" }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "node_modules/@babel/core/node_modules/@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/core/node_modules/@babel/helpers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", + "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", + "dev": true, + "dependencies": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/core/node_modules/@babel/parser": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", + "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/core/node_modules/@babel/traverse": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", + "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "node_modules/@babel/core/node_modules/@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, "dependencies": { - "@babel/generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", - "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helpers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", - "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", - "dev": true, - "requires": { - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/parser": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", - "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", - "dev": true - }, - "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/traverse": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", - "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - } - }, - "@babel/types": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", - "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/generator": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/generator": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.4.0", "jsesc": "^2.5.1", "lodash": "^4.17.11", @@ -128,79 +155,79 @@ "trim-right": "^1.0.1" } }, - "@babel/helper-annotate-as-pure": { + "node_modules/@babel/helper-annotate-as-pure": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.0.0" } }, - "@babel/helper-builder-binary-assignment-operator-visitor": { + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-explode-assignable-expression": "^7.1.0", "@babel/types": "^7.0.0" } }, - "@babel/helper-explode-assignable-expression": { + "node_modules/@babel/helper-explode-assignable-expression": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "dev": true, - "requires": { + "dependencies": { "@babel/traverse": "^7.1.0", "@babel/types": "^7.0.0" } }, - "@babel/helper-function-name": { + "node_modules/@babel/helper-function-name": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-get-function-arity": "^7.0.0", "@babel/template": "^7.1.0", "@babel/types": "^7.0.0" } }, - "@babel/helper-get-function-arity": { + "node_modules/@babel/helper-get-function-arity": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.0.0" } }, - "@babel/helper-member-expression-to-functions": { + "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.0.0" } }, - "@babel/helper-module-imports": { + "node_modules/@babel/helper-module-imports": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.0.0" } }, - "@babel/helper-module-transforms": { + "node_modules/@babel/helper-module-transforms": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz", "integrity": "sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-simple-access": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", @@ -209,36 +236,40 @@ "lodash": "^4.17.10" } }, - "@babel/helper-optimise-call-expression": { + "node_modules/@babel/helper-optimise-call-expression": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.0.0" } }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-regex": { + "node_modules/@babel/helper-regex": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "dev": true, - "requires": { + "dependencies": { "lodash": "^4.17.10" } }, - "@babel/helper-remap-async-to-generator": { + "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-annotate-as-pure": "^7.0.0", "@babel/helper-wrap-function": "^7.1.0", "@babel/template": "^7.1.0", @@ -246,298 +277,396 @@ "@babel/types": "^7.0.0" } }, - "@babel/helper-replace-supers": { + "node_modules/@babel/helper-replace-supers": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.0.tgz", "integrity": "sha512-PVwCVnWWAgnal+kJ+ZSAphzyl58XrFeSKSAJRiqg5QToTsjL+Xu1f9+RJ+d+Q0aPhPfBGaYfkox66k86thxNSg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-member-expression-to-functions": "^7.0.0", "@babel/helper-optimise-call-expression": "^7.0.0", "@babel/traverse": "^7.4.0", "@babel/types": "^7.4.0" } }, - "@babel/helper-simple-access": { + "node_modules/@babel/helper-simple-access": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "dev": true, - "requires": { + "dependencies": { "@babel/template": "^7.1.0", "@babel/types": "^7.0.0" } }, - "@babel/helper-split-export-declaration": { + "node_modules/@babel/helper-split-export-declaration": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.4.0" } }, - "@babel/helper-wrap-function": { + "node_modules/@babel/helper-wrap-function": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-function-name": "^7.1.0", "@babel/template": "^7.1.0", "@babel/traverse": "^7.1.0", "@babel/types": "^7.2.0" } }, - "@babel/highlight": { + "node_modules/@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, - "requires": { + "dependencies": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, - "@babel/parser": { + "node_modules/@babel/parser": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.2.tgz", "integrity": "sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g==", - "dev": true + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } }, - "@babel/plugin-proposal-async-generator-functions": { + "node_modules/@babel/plugin-proposal-async-generator-functions": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/helper-remap-async-to-generator": "^7.1.0", "@babel/plugin-syntax-async-generators": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-proposal-json-strings": { + "node_modules/@babel/plugin-proposal-json-strings": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-json-strings": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-proposal-object-rest-spread": { + "node_modules/@babel/plugin-proposal-object-rest-spread": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz", "integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-proposal-optional-catch-binding": { + "node_modules/@babel/plugin-proposal-optional-catch-binding": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-async-generators": { + "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-json-strings": { + "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-object-rest-spread": { + "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-optional-catch-binding": { + "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-arrow-functions": { + "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-block-scoped-functions": { + "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-computed-properties": { + "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-duplicate-keys": { + "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-exponentiation-operator": { + "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-literals": { + "node_modules/@babel/plugin-transform-literals": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-member-expression-literals": { + "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-modules-amd": { + "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-module-transforms": "^7.1.0", "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-modules-umd": { + "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-module-transforms": "^7.1.0", "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-object-super": { + "node_modules/@babel/plugin-transform-object-super": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/helper-replace-supers": "^7.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-property-literals": { + "node_modules/@babel/plugin-transform-property-literals": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-reserved-words": { + "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-shorthand-properties": { + "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-spread": { + "node_modules/@babel/plugin-transform-spread": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-sticky-regex": { + "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/helper-regex": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-typeof-symbol": { + "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/preset-env": { + "node_modules/@babel/preset-env": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.4.tgz", "integrity": "sha512-FU1H+ACWqZZqfw1x2G1tgtSSYSfxJLkpaUQL37CenULFARDo+h4xJoVHzRoHbK+85ViLciuI7ME4WTIhFRBBlw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-async-generator-functions": "^7.2.0", @@ -587,326 +716,375 @@ "js-levenshtein": "^1.1.3", "semver": "^5.5.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-define-map": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", + "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "dev": true, "dependencies": { - "@babel/generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", - "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - } - }, - "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-define-map": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", - "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.4.4", - "lodash": "^4.17.11" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", - "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.4.4", - "lodash": "^4.17.11" - } - }, - "@babel/helper-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", - "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "@babel/helper-replace-supers": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", - "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/parser": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", - "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", - "dev": true - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", - "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", - "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz", - "integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.11" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", - "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.4.4", - "@babel/helper-split-export-declaration": "^7.4.4", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", - "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", - "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", - "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", - "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.4.tgz", - "integrity": "sha512-Ki+Y9nXBlKfhD+LXaRS7v95TtTGYRAf9Y1rTDiE75zf8YQz4GDaWRXosMfJBXxnk88mGFjWdCRIeqDbon7spYA==", - "dev": true, - "requires": { - "regexp-tree": "^0.1.0" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", - "dev": true, - "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.4.tgz", - "integrity": "sha512-Zz3w+pX1SI0KMIiqshFZkwnVGUhDZzpX2vtPzfJBKQQq8WsP/Xy9DNdELWivxcKOCX/Pywge4SiEaPaLtoDT4g==", - "dev": true, - "requires": { - "regenerator-transform": "^0.13.4" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", - "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" - } - }, - "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/traverse": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", - "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - } - }, - "@babel/types": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", - "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/template": { + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-module-transforms": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", + "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", + "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", + "dev": true, + "dependencies": { + "lodash": "^4.17.11" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-replace-supers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", + "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/parser": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", + "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", + "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", + "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-classes": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", + "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.4", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-destructuring": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", + "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", + "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", + "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", + "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.4.tgz", + "integrity": "sha512-Ki+Y9nXBlKfhD+LXaRS7v95TtTGYRAf9Y1rTDiE75zf8YQz4GDaWRXosMfJBXxnk88mGFjWdCRIeqDbon7spYA==", + "dev": true, + "dependencies": { + "regexp-tree": "^0.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "dependencies": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-regenerator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.4.tgz", + "integrity": "sha512-Zz3w+pX1SI0KMIiqshFZkwnVGUhDZzpX2vtPzfJBKQQq8WsP/Xy9DNdELWivxcKOCX/Pywge4SiEaPaLtoDT4g==", + "dev": true, + "dependencies": { + "regenerator-transform": "^0.13.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", + "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/traverse": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", + "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/template": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.0.0", "@babel/parser": "^7.4.0", "@babel/types": "^7.4.0" } }, - "@babel/traverse": { + "node_modules/@babel/traverse": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.0.tgz", "integrity": "sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.0.0", "@babel/generator": "^7.4.0", "@babel/helper-function-name": "^7.1.0", @@ -918,843 +1096,1251 @@ "lodash": "^4.17.11" } }, - "@babel/types": { + "node_modules/@babel/types": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", "dev": true, - "requires": { + "dependencies": { "esutils": "^2.0.2", "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, - "@types/estree": { + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true }, - "@types/node": { + "node_modules/@types/node": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz", "integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==", "dev": true }, - "@types/resolve": { + "node_modules/@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "align-text": { + "node_modules/align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "requires": { + "dependencies": { "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "babel": { + "node_modules/babel": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel/-/babel-6.23.0.tgz", "integrity": "sha1-0NHn2APpdHZb7qMjLU4VPA77kPQ=", - "dev": true + "deprecated": "In 6.x, the babel package has been deprecated in favor of babel-cli. Check https://opencollective.com/babel to support the Babel maintainers", + "dev": true, + "bin": { + "babel": "lib/cli.js", + "babel-external-helpers": "lib/cli.js", + "babel-node": "lib/cli.js" + } }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "brace-expansion": { + "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "browserslist": { + "node_modules/browserslist": { "version": "4.16.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", "dev": true, - "requires": { + "dependencies": { "caniuse-lite": "^1.0.30001219", "colorette": "^1.2.2", "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001228", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", - "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.736", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz", - "integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig==", - "dev": true - }, - "node-releases": { - "version": "1.1.72", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", - "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", - "dev": true - } - } - }, - "builtin-modules": { + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/caniuse-lite": { + "version": "1.0.30001228", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", + "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/electron-to-chromium": { + "version": "1.3.736", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz", + "integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig==", + "dev": true + }, + "node_modules/browserslist/node_modules/node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "dev": true + }, + "node_modules/builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "camelcase": { + "node_modules/camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "center-align": { + "node_modules/center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, - "requires": { + "dependencies": { "align-text": "^0.1.3", "lazy-cache": "^1.0.3" + }, + "engines": { + "node": ">=0.10.0" } }, - "chalk": { + "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "cliui": { + "node_modules/cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, - "requires": { + "dependencies": { "center-align": "^0.1.1", "right-align": "^0.1.1", "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - } } }, - "color-convert": { + "node_modules/cliui/node_modules/wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "requires": { + "dependencies": { "color-name": "1.1.3" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "colorette": { + "node_modules/colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", "dev": true }, - "concat-map": { + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "convert-source-map": { + "node_modules/convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, - "requires": { + "dependencies": { "safe-buffer": "~5.1.1" } }, - "core-js-compat": { + "node_modules/core-js-compat": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.0.1.tgz", "integrity": "sha512-2pC3e+Ht/1/gD7Sim/sqzvRplMiRnFQVlPpDVaHtY9l7zZP7knamr3VRD6NyGfHd84MrDC0tAM9ulNxYMW0T3g==", "dev": true, - "requires": { - "browserslist": "^4.5.4", - "core-js": "3.0.1", - "core-js-pure": "3.0.1", - "semver": "^6.0.0" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30000966", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000966.tgz", - "integrity": "sha512-qqLQ/uYrpZmFhPY96VuBkMEo8NhVFBZ9y/Bh+KnvGzGJ5I8hvpIaWlF2pw5gqe4PLAL+ZjsPgMOvoXSpX21Keg==" - }, - "core-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz", - "integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.130", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.130.tgz", - "integrity": "sha512-UY2DI+gsnqGtQJqO8wXN0DnpJY+29FwJafACj0h18ZShn5besKnrRq6+lXWUbKzdxw92QQcnTqRLgNByOKXcUg==" - }, - "node-releases": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.17.tgz", - "integrity": "sha512-/SCjetyta1m7YXLgtACZGDYJdCSIBAWorDWkGCGZlydP2Ll7J48l7j/JxNYZ+xsgSPbWfdulVS/aY+GdjUsQ7Q==", - "requires": { - "semver": "^5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - } - } - }, - "semver": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", - "dev": true - } - } - }, - "core-js-pure": { + "dependencies": { + "browserslist": "^4.5.4", + "core-js": "3.0.1", + "core-js-pure": "3.0.1", + "semver": "^6.0.0" + } + }, + "node_modules/core-js-compat/node_modules/core-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz", + "integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/core-js-pure": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.0.1.tgz", "integrity": "sha512-mSxeQ6IghKW3MoyF4cz19GJ1cMm7761ON+WObSyLfTu/Jn3x7w4NwNFnrZxgl4MTSvYYepVLNuRtlB4loMwJ5g==", + "deprecated": "core-js-pure@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js-pure.", "dev": true }, - "debug": { + "node_modules/debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", "dev": true, - "requires": { + "dependencies": { "ms": "^2.1.1" } }, - "decamelize": { + "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "deep-equal": { + "node_modules/deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", "dev": true }, - "define-properties": { + "node_modules/define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, - "requires": { + "dependencies": { "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" } }, - "defined": { + "node_modules/defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, - "es-abstract": { + "node_modules/es-abstract": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, - "requires": { + "dependencies": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", "has": "^1.0.3", "is-callable": "^1.1.4", "is-regex": "^1.0.4", "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" } }, - "es-to-primitive": { + "node_modules/es-to-primitive": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, - "requires": { + "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "escalade": { + "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "escape-string-regexp": { + "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, - "estree-walker": { + "node_modules/estree-walker": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true }, - "esutils": { + "node_modules/esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "for-each": { + "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, - "requires": { + "dependencies": { "is-callable": "^1.1.3" } }, - "fs.realpath": { + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { + "node_modules/fsevents": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", "dev": true, - "optional": true + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "function-bind": { + "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "glob": { + "node_modules/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "requires": { + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" } }, - "globals": { + "node_modules/globals": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "has": { + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, - "requires": { + "dependencies": { "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" } }, - "has-flag": { + "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "has-symbols": { + "node_modules/has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + } }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, - "requires": { + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "invariant": { + "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, - "requires": { + "dependencies": { "loose-envify": "^1.0.0" } }, - "is-buffer": { + "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-callable": { + "node_modules/is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + } }, - "is-date-object": { + "node_modules/is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + } }, - "is-module": { + "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, - "is-reference": { + "node_modules/is-reference": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", "dev": true, - "requires": { + "dependencies": { "@types/estree": "0.0.39" } }, - "is-regex": { + "node_modules/is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, - "requires": { + "dependencies": { "has": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "is-symbol": { + "node_modules/is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, - "requires": { + "dependencies": { "has-symbols": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "js-levenshtein": { + "node_modules/js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "js-tokens": { + "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "jsesc": { + "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } }, - "json5": { + "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } }, - "kind-of": { + "node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "requires": { + "dependencies": { "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "lazy-cache": { + "node_modules/lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "lodash": { + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "longest": { + "node_modules/longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "loose-envify": { + "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, - "requires": { + "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "magic-string": { + "node_modules/magic-string": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", "dev": true, - "requires": { + "dependencies": { "sourcemap-codec": "^1.4.4" } }, - "minimatch": { + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "ms": { + "node_modules/ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, - "object-inspect": { + "node_modules/object-inspect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, - "object-keys": { + "node_modules/object-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "package-preamble": { + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-preamble": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/package-preamble/-/package-preamble-0.1.0.tgz", "integrity": "sha1-xDlzgbcDU0SOQlXqmkml5bQYymg=", - "dev": true + "dev": true, + "bin": { + "preamble": "bin/preamble" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "private": { + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "regenerate": { + "node_modules/regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", "dev": true }, - "regenerate-unicode-properties": { + "node_modules/regenerate-unicode-properties": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.2.tgz", "integrity": "sha512-SbA/iNrBUf6Pv2zU8Ekv1Qbhv92yxL4hiDa2siuxs4KKn4oOoMDHXjAf7+Nz9qinUQ46B1LcWEi/PhJfPWpZWQ==", "dev": true, - "requires": { + "dependencies": { "regenerate": "^1.4.0" + }, + "engines": { + "node": ">=4" } }, - "regenerator-transform": { + "node_modules/regenerator-transform": { "version": "0.13.4", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz", "integrity": "sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==", "dev": true, - "requires": { + "dependencies": { "private": "^0.1.6" } }, - "regexp-tree": { + "node_modules/regexp-tree": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.5.tgz", "integrity": "sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==", - "dev": true + "dev": true, + "bin": { + "regexp-tree": "bin/regexp-tree" + } }, - "regexpu-core": { + "node_modules/regexpu-core": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", "dev": true, - "requires": { + "dependencies": { "regenerate": "^1.4.0", "regenerate-unicode-properties": "^8.0.2", "regjsgen": "^0.5.0", "regjsparser": "^0.6.0", "unicode-match-property-ecmascript": "^1.0.4", "unicode-match-property-value-ecmascript": "^1.1.0" + }, + "engines": { + "node": ">=4" } }, - "regjsgen": { + "node_modules/regjsgen": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", "dev": true }, - "regjsparser": { + "node_modules/regjsparser": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", "dev": true, - "requires": { + "dependencies": { "jsesc": "~0.5.0" }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" } }, - "repeat-string": { + "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "resolve": { + "node_modules/resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "dev": true, - "requires": { + "dependencies": { "path-parse": "^1.0.6" } }, - "resumer": { + "node_modules/resumer": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", "dev": true, - "requires": { + "dependencies": { "through": "~2.3.4" } }, - "right-align": { + "node_modules/right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, - "requires": { + "dependencies": { "align-text": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "rollup": { + "node_modules/rollup": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.0.tgz", "integrity": "sha512-7BmpEfUN9P6esJzWIn3DmR//90mW6YwYB1t3y48LpF8ITpYtL8s1kEirMKqUu44dVH/6a/rs0EuwYVL3FuRDoA==", "dev": true, - "requires": { + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { "fsevents": "~2.1.2" } }, - "rollup-plugin-babel": { + "node_modules/rollup-plugin-babel": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-babel.", "dev": true, - "requires": { + "dependencies": { "@babel/helper-module-imports": "^7.0.0", "rollup-pluginutils": "^2.8.1" + }, + "peerDependencies": { + "@babel/core": "7 || ^7.0.0-rc.2", + "rollup": ">=0.60.0 <3" } }, - "rollup-plugin-commonjs": { + "node_modules/rollup-plugin-commonjs": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.", "dev": true, - "requires": { + "dependencies": { "estree-walker": "^0.6.1", "is-reference": "^1.1.2", "magic-string": "^0.25.2", "resolve": "^1.11.0", "rollup-pluginutils": "^2.8.1" }, + "peerDependencies": { + "rollup": ">=1.12.0" + } + }, + "node_modules/rollup-plugin-commonjs/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "rollup-plugin-node-resolve": { + "node_modules/rollup-plugin-node-resolve": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.", "dev": true, - "requires": { + "dependencies": { "@types/resolve": "0.0.8", "builtin-modules": "^3.1.0", "is-module": "^1.0.0", "resolve": "^1.11.1", "rollup-pluginutils": "^2.8.1" }, + "peerDependencies": { + "rollup": ">=1.11.0" + } + }, + "node_modules/rollup-plugin-node-resolve/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup-plugin-typescript2": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.35.0.tgz", + "integrity": "sha512-szcIO9hPUx3PhQl91u4pfNAH2EKbtrXaES+m163xQVE5O1CC0ea6YZV/5woiDDW3CR9jF2CszPrKN+AFiND0bg==", + "dev": true, + "license": "MIT", "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } + "@rollup/pluginutils": "^4.1.2", + "find-cache-dir": "^3.3.2", + "fs-extra": "^10.0.0", + "semver": "^7.3.7", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "rollup": ">=1.26.3", + "typescript": ">=2.4.0" + } + }, + "node_modules/rollup-plugin-typescript2/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "rollup-pluginutils": { + "node_modules/rollup-pluginutils": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", "dev": true, - "requires": { + "dependencies": { "estree-walker": "^0.6.1" } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "semver": { + "node_modules/semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true + "dev": true, + "bin": { + "semver": "bin/semver" + } }, - "source-map": { + "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "sourcemap-codec": { + "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", "dev": true }, - "string.prototype.trim": { + "node_modules/string.prototype.trim": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", "dev": true, - "requires": { + "dependencies": { "define-properties": "^1.1.2", "es-abstract": "^1.5.0", "function-bind": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "supports-color": { + "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "requires": { + "dependencies": { "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "tape": { + "node_modules/tape": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/tape/-/tape-4.10.1.tgz", "integrity": "sha512-G0DywYV1jQeY3axeYnXUOt6ktnxS9OPJh97FGR3nrua8lhWi1zPflLxcAHavZ7Jf3qUfY7cxcVIVFa4mY2IY1w==", "dev": true, - "requires": { + "dependencies": { "deep-equal": "~1.0.1", "defined": "~1.0.0", "for-each": "~0.3.3", @@ -1769,97 +2355,158 @@ "string.prototype.trim": "~1.1.2", "through": "~2.3.8" }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "bin": { + "tape": "bin/tape" } }, - "through": { + "node_modules/tape/node_modules/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "to-fast-properties": { + "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "trim-right": { + "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } }, - "uglify-js": { + "node_modules/uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, - "requires": { + "dependencies": { "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", "yargs": "~3.10.0" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + }, + "optionalDependencies": { + "uglify-to-browserify": "~1.0.0" } }, - "uglify-to-browserify": { + "node_modules/uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, - "unicode-canonical-property-names-ecmascript": { + "node_modules/unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "unicode-match-property-ecmascript": { + "node_modules/unicode-match-property-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, - "requires": { + "dependencies": { "unicode-canonical-property-names-ecmascript": "^1.0.4", "unicode-property-aliases-ecmascript": "^1.0.4" + }, + "engines": { + "node": ">=4" } }, - "unicode-match-property-value-ecmascript": { + "node_modules/unicode-match-property-value-ecmascript": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "unicode-property-aliases-ecmascript": { + "node_modules/unicode-property-aliases-ecmascript": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } }, - "window-size": { + "node_modules/window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "yargs": { + "node_modules/yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, - "requires": { + "dependencies": { "camelcase": "^1.0.2", "cliui": "^2.1.0", "decamelize": "^1.0.0", diff --git a/package.json b/package.json index 26fd497..babb340 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "pretest": "rm -rf dist && mkdir dist && rollup -c --banner \"$(preamble)\"", "test": "tape 'test/**/*-test.js'", "prepublishOnly": "npm run test && uglifyjs dist/d3-regression.js -c -m -o dist/d3-regression.min.js", - "postpublish": "zip -j dist/d3-regression.zip -- LICENSE README.md dist/d3-regression.js dist/d3-regression.min.js dist/d3-regression.cjs.js dist/d3-regression.esm.js" + "postpublish": "zip -j dist/d3-regression.zip -- LICENSE README.md dist/d3-regression.js dist/d3-regression.min.js dist/d3-regression.cjs.js dist/d3-regression.esm.js dist/index.d.ts dist/src/*.d.ts" }, "repository": { "type": "git", @@ -25,6 +25,7 @@ "browser": "dist/d3-regression.js", "module": "dist/d3-regression.esm.js", "main": "dist/d3-regression.cjs.js", + "types": "dist/types/index.d.ts", "license": "BSD-3-Clause", "bugs": { "url": "https://github.com/HarryStevens/d3-regression/issues" @@ -39,8 +40,9 @@ "rollup-plugin-babel": "^4.4.0", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-typescript2": "^0.35.0", "tape": "^4.10.1", + "typescript": "^4.9.5", "uglify-js": "^2.8.29" - }, - "dependencies": {} + } } diff --git a/rollup.config.js b/rollup.config.js index b192098..17a58d4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -2,11 +2,12 @@ import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import babel from "rollup-plugin-babel"; import pkg from "./package.json"; +import typescript from "rollup-plugin-typescript2"; export default [ // browser-friendly UMD build { - input: "index.js", + input: "index.ts", output: { name: "d3", file: pkg.browser, @@ -15,6 +16,16 @@ export default [ plugins: [ resolve(), commonjs(), + typescript({ + tsconfig: "./tsconfig.json", + tsconfigOverride: { + compilerOptions: { + declaration: true, + declarationDir: "./dist/types", + allowJs: true + } + } + }), babel({ exclude: ["node_modules/**"], }), @@ -22,19 +33,24 @@ export default [ }, // CommonJS (for Node) and ES module (for bundlers) build. - // (We could have three entries in the configuration array - // instead of two, but it's quicker to generate multiple - // builds from a single configuration where possible, using - // an array for the `output` option, where we can specify - // `file` and `format` for each target) { - input: "index.js", - external: [], // list dependencies here + input: "index.ts", + external: [], // list dependencies here if needed output: [ { file: pkg.main, format: "cjs" }, { file: pkg.module, format: "es" }, ], plugins: [ + typescript({ + tsconfig: "./tsconfig.json", + tsconfigOverride: { + compilerOptions: { + declaration: true, + declarationDir: "./dist/types", + allowJs: true + } + } + }), babel({ exclude: ["node_modules/**"], }), diff --git a/src/exponential.js b/src/exponential.js deleted file mode 100644 index 3b33798..0000000 --- a/src/exponential.js +++ /dev/null @@ -1,62 +0,0 @@ -import { determination } from "./utils/determination"; -import { interpose } from "./utils/interpose"; -import { ols } from "./utils/ols"; -import { visitPoints } from "./utils/points"; - -export default function() { - let x = d => d[0], - y = d => d[1], - domain; - - function exponential(data){ - let n = 0, - Y = 0, - YL = 0, - XY = 0, - XYL = 0, - X2Y = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - - visitPoints(data, x, y, (dx, dy) => { - const ly = Math.log(dy), xy = dx * dy; - ++n; - Y += (dy - Y) / n; - XY += (xy - XY) / n; - X2Y += (dx * xy - X2Y) / n; - YL += (dy * ly - YL) / n; - XYL += (xy * ly - XYL) / n; - - if (!domain){ - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - let [a, b] = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y); - a = Math.exp(a); - const fn = x => a * Math.exp(b * x), - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - - return out; - } - - exponential.domain = function(arr){ - return arguments.length ? (domain = arr, exponential) : domain; - } - - exponential.x = function(fn){ - return arguments.length ? (x = fn, exponential) : x; - } - - exponential.y = function(fn){ - return arguments.length ? (y = fn, exponential) : y; - } - - return exponential; -} \ No newline at end of file diff --git a/src/exponential.ts b/src/exponential.ts new file mode 100644 index 0000000..dc1f310 --- /dev/null +++ b/src/exponential.ts @@ -0,0 +1,92 @@ +import { determination } from "./utils/determination"; +import { interpose } from "./utils/interpose"; +import { ols } from "./utils/ols"; +import { visitPoints } from "./utils/points"; +import { PredictFunction, Domain, DataPoint, Accessor } from "./types"; + + +export type ExponentialOutput = [DataPoint, DataPoint] & { + a: number; // slope + b: number; // intercept + predict: PredictFunction + rSquared: number; +} + +export interface ExponentialRegression { + (data: T[]): ExponentialOutput; + + domain(): Domain; + domain(arr: Domain): this; + + x(): Accessor; + x(fn: Accessor): this; + + y(): Accessor; + y(fn: Accessor): this; +} + +export default function exponential(): ExponentialRegression { + let y: Accessor = (d: T) => (d as DataPoint)[1], + x: Accessor = (d: T) => (d as DataPoint)[0], + domain: Domain; + + const exponentialRegression = function (data: T[]): ExponentialOutput { + let n = 0, + Y = 0, + YL = 0, + XY = 0, + XYL = 0, + X2Y = 0, + xmin = domain ? +domain[0] : Infinity, + xmax = domain ? +domain[1] : -Infinity; + + visitPoints(data, x, y, (dx, dy) => { + const ly = Math.log(dy), + xy = dx * dy; + ++n; + Y += (dy - Y) / n; + XY += (xy - XY) / n; + X2Y += (dx * xy - X2Y) / n; + YL += (dy * ly - YL) / n; + XYL += (xy * ly - XYL) / n; + + if (!domain) { + if (dx < xmin) xmin = dx; + if (dx > xmax) xmax = dx; + } + }); + + let [a, b] = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y); + a = Math.exp(a); + + const fn = (xx: number) => a * Math.exp(b * xx); + const out = interpose(xmin, xmax, fn); + + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + + return out; + } as ExponentialRegression; + + exponentialRegression.domain = function (arr) { + if (!arguments.length) return domain; + domain = arr; + return exponentialRegression; + } as ExponentialRegression['domain']; + + exponentialRegression.x = function (fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return exponentialRegression; + } as ExponentialRegression['x']; + + exponentialRegression.y = function (fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return exponentialRegression; + } as ExponentialRegression['y']; + + return exponentialRegression; +} diff --git a/src/linear.js b/src/linear.js deleted file mode 100644 index 64eb61e..0000000 --- a/src/linear.js +++ /dev/null @@ -1,57 +0,0 @@ -import { determination } from "./utils/determination"; -import { ols } from "./utils/ols"; -import { visitPoints } from "./utils/points"; - -export default function(){ - let x = d => d[0], - y = d => d[1], - domain; - - function linear(data){ - let n = 0, - X = 0, // sum of x - Y = 0, // sum of y - XY = 0, // sum of x * y - X2 = 0, // sum of x * x - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - - visitPoints(data, x, y, (dx, dy) => { - ++n; - X += (dx - X) / n; - Y += (dy - Y) / n; - XY += (dx * dy - XY) / n; - X2 += (dx * dx - X2) / n; - - if (!domain){ - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - const [intercept, slope] = ols(X, Y, XY, X2), - fn = x => slope * x + intercept, - out = [[xmin, fn(xmin)], [xmax, fn(xmax)]]; - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - - return out; - } - - linear.domain = function(arr){ - return arguments.length ? (domain = arr, linear) : domain; - } - - linear.x = function(fn){ - return arguments.length ? (x = fn, linear) : x; - } - - linear.y = function(fn){ - return arguments.length ? (y = fn, linear) : y; - } - - return linear; -} diff --git a/src/linear.ts b/src/linear.ts new file mode 100644 index 0000000..d9c8e21 --- /dev/null +++ b/src/linear.ts @@ -0,0 +1,85 @@ +import { determination } from "./utils/determination"; +import { ols } from "./utils/ols"; +import { visitPoints } from "./utils/points"; +import { PredictFunction, Accessor, DataPoint, Domain } from "./types"; + +export type LinearOutput = [DataPoint, DataPoint] & { + a: number; // slope + b: number; // intercept + predict: PredictFunction + rSquared: number; +}; + + +export interface LinearRegression { + (data: T[]): LinearOutput; + + domain(): Domain; + domain(arr: Domain): this; + + x(): Accessor; + x(fn: Accessor): this; + + y(): Accessor; + y(fn: Accessor): this; +} + +export default function linear(): LinearRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + domain: Domain; + + const linearRegression = function (data: T[]): LinearOutput { + let n = 0, + X = 0, // sum of x + Y = 0, // sum of y + XY = 0, // sum of x*y + X2 = 0, // sum of x*x + xmin = domain ? +domain[0] : Infinity, + xmax = domain ? +domain[1] : -Infinity; + + visitPoints(data, x, y, (dx, dy) => { + ++n; + X += (dx - X) / n; + Y += (dy - Y) / n; + XY += (dx * dy - XY) / n; + X2 += (dx * dx - X2) / n; + + if (!domain) { + if (dx < xmin) xmin = dx; + if (dx > xmax) xmax = dx; + } + }); + + const [intercept, slope] = ols(X, Y, XY, X2); + const fn = (xx: number) => slope * xx + intercept; + + const out = [[xmin, fn(xmin)], [xmax, fn(xmax)]] as LinearOutput; + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + + return out; + } as LinearRegression + + linearRegression.domain = function (arr) { + if (!arguments.length) return domain; + domain = arr; + return linearRegression; + } as LinearRegression['domain']; + + linearRegression.x = function (fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return linearRegression; + } as LinearRegression['x']; + + linearRegression.y = function (fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return linearRegression; + } as LinearRegression['y']; + + return linearRegression; +} diff --git a/src/loess.js b/src/loess.js deleted file mode 100644 index 394b9bc..0000000 --- a/src/loess.js +++ /dev/null @@ -1,136 +0,0 @@ -// Adapted from science.js by Jason Davies -// License: https://github.com/jasondavies/science.js/blob/master/LICENSE -// Source: https://github.com/jasondavies/science.js/blob/master/src/stats/loess.js -// Adapted from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f21cb8792b4e0cbe2b1a3fd44b0f5db370dbaadb/packages/vega-statistics/src/regression/loess.js -import { median } from "./utils/median"; -import { ols } from "./utils/ols"; -import { points } from "./utils/points"; - -const maxiters = 2, epsilon = 1e-12; - -export default function() { - let x = d => d[0], - y = d => d[1], - bandwidth = .3; - - function loess(data) { - const [xv, yv, ux, uy] = points(data, x, y, true), - n = xv.length, - bw = Math.max(2, ~~(bandwidth * n)), // # nearest neighbors - yhat = new Float64Array(n), - residuals = new Float64Array(n), - robustWeights = new Float64Array(n).fill(1); - - for (let iter = -1; ++iter <= maxiters; ) { - const interval = [0, bw - 1]; - - for (let i = 0; i < n; ++i) { - const dx = xv[i], - i0 = interval[0], - i1 = interval[1], - edge = (dx - xv[i0]) > (xv[i1] - dx) ? i0 : i1; - - let W = 0, X = 0, Y = 0, XY = 0, X2 = 0, - denom = 1 / Math.abs(xv[edge] - dx || 1); // Avoid singularity - - for (let k = i0; k <= i1; ++k) { - const xk = xv[k], - yk = yv[k], - w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k], - xkw = xk * w; - - W += w; - X += xkw; - Y += yk * w; - XY += yk * xkw; - X2 += xk * xkw; - } - - // Linear regression fit - const [a, b] = ols(X / W, Y / W, XY / W, X2 / W); - yhat[i] = a + b * dx; - residuals[i] = Math.abs(yv[i] - yhat[i]); - - updateInterval(xv, i + 1, interval); - } - - if (iter === maxiters) { - break; - } - - const medianResidual = median(residuals); - if (Math.abs(medianResidual) < epsilon) break; - - for (let i = 0, arg, w; i < n; ++i){ - arg = residuals[i] / (6 * medianResidual); - // Default to epsilon (rather than zero) for large deviations - // Keeping weights tiny but non-zero prevents singularites - robustWeights[i] = (arg >= 1) ? epsilon : ((w = 1 - arg * arg) * w); - } - } - - return output(xv, yhat, ux, uy); - } - - loess.bandwidth = function(bw) { - return arguments.length ? (bandwidth = bw, loess) : bandwidth; - }; - - loess.x = function(fn) { - return arguments.length ? (x = fn, loess) : x; - }; - - loess.y = function(fn) { - return arguments.length ? (y = fn, loess) : y; - }; - - return loess; -} - -// Weighting kernel for local regression -function tricube(x) { - return (x = 1 - x * x * x) * x * x; -} - -// Advance sliding window interval of nearest neighbors -function updateInterval(xv, i, interval) { - let val = xv[i], - left = interval[0], - right = interval[1] + 1; - - if (right >= xv.length) return; - - // Step right if distance to new right edge is <= distance to old left edge - // Step when distance is equal to ensure movement over duplicate x values - while (i > left && (xv[right] - val) <= (val - xv[left])) { - interval[0] = ++left; - interval[1] = right; - ++right; - } -} - -// Generate smoothed output points -// Average points with repeated x values -function output(xv, yhat, ux, uy) { - const n = xv.length, out = []; - let i = 0, cnt = 0, prev = [], v; - - for (; i { + (data: T[]): DataPoint[]; + + bandwidth(): number; + bandwidth(bw: number): this; + + x(): Accessor; + x(fn: Accessor): this; + + y(): Accessor; + y(fn: Accessor): this; +} + +export default function loess(): LoessRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + bandwidth = 0.3; + + const loessRegression = function loessRegression(data: T[]): Array { + const [xv, yv, ux, uy] = points(data, (dd) => x(dd), (dd) => y(dd), true); + const n = xv.length; + const bw = Math.max(2, ~~(bandwidth * n)); // # of nearest neighbors + const yhat = new Float64Array(n); + const residuals = new Float64Array(n); + const robustWeights = new Float64Array(n).fill(1); + + for (let iter = -1; ++iter <= maxiters;) { + const interval = [0, bw - 1] as [number, number]; + + for (let i = 0; i < n; ++i) { + const dx = xv[i]; + const i0 = interval[0]; + const i1 = interval[1]; + const edge = (dx - xv[i0]) > (xv[i1] - dx) ? i0 : i1; + + let W = 0, X = 0, Y = 0, XY = 0, X2 = 0; + const denom = 1 / Math.abs(xv[edge] - dx || 1); + + for (let k = i0; k <= i1; ++k) { + const xk = xv[k]; + const yk = yv[k]; + const w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k]; + const xkw = xk * w; + W += w; + X += xkw; + Y += yk * w; + XY += yk * xkw; + X2 += xk * xkw; + } + + // Linear regression fit + const [a, b] = ols(X / W, Y / W, XY / W, X2 / W); + yhat[i] = a + b * dx; + residuals[i] = Math.abs(yv[i] - yhat[i]); + + updateInterval(xv, i + 1, interval); + } + + if (iter === maxiters) { + break; + } + + const medianResidual = median(residuals); + if (Math.abs(medianResidual) < epsilon) break; + + for (let i = 0, arg, w; i < n; ++i) { + arg = residuals[i] / (6 * medianResidual); + // Default to epsilon (rather than zero) for large deviations + // Keeping weights tiny but non-zero prevents singularites + robustWeights[i] = (arg >= 1) ? epsilon : ((w = 1 - arg * arg) * w); + } + } + + return output(xv, yhat, ux, uy); + } as LoessRegression + + loessRegression.bandwidth = function (bw?: number) { + if (!arguments.length) return bandwidth; + bandwidth = bw!; + return loessRegression; + } as LoessRegression['bandwidth']; + + loessRegression.x = function (fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return loessRegression; + } as LoessRegression['x']; + + loessRegression.y = function (fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return loessRegression; + } as LoessRegression['y']; + + return loessRegression; +} + +// Weighting kernel for local regression +function tricube(x: number): number { + return (x = 1 - x * x * x) * x * x; +} + +// Advance sliding window interval of nearest neighbors +function updateInterval(xv: Float64Array, i: number, interval: [number, number]) { + let val = xv[i], left = interval[0], right = interval[1] + 1; + if (right >= xv.length) return; + + // Step right if distance to new right edge is <= distance to old left edge + // Step when distance is equal to ensure movement over duplicate x values + while (i > left && (xv[right] - val) <= (val - xv[left])) { + interval[0] = ++left; + interval[1] = right; + ++right; + } +} + +// Generate smoothed output points +// Average points with repeated x values +function output(xv: Float64Array, yhat: Float64Array, ux: number, uy: number): Array<[number, number]> { + const n = xv.length, out = []; + + let i = 0, cnt = 0, prev: any = [], v; + + for (; i < n; ++i) { + v = xv[i] + ux; + if (prev[0] === v) { + // Average output values via online update + prev[1] += (yhat[i] - prev[1]) / (++cnt); + } else { + // Add new output point + cnt = 0; + prev[1] += uy; + prev = [v, yhat[i]]; + out.push(prev); + } + } + prev[1] += uy; + + return out; +} diff --git a/src/logarithmic.js b/src/logarithmic.js deleted file mode 100644 index 1d14d37..0000000 --- a/src/logarithmic.js +++ /dev/null @@ -1,65 +0,0 @@ -import { determination } from "./utils/determination"; -import { interpose } from "./utils/interpose"; -import { ols } from "./utils/ols"; -import { visitPoints } from "./utils/points"; - -export default function() { - let x = d => d[0], - y = d => d[1], - base = Math.E, - domain; - - function logarithmic(data){ - let n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity, - lb = Math.log(base); - - visitPoints(data, x, y, (dx, dy) => { - const lx = Math.log(dx) / lb; - ++n; - X += (lx - X) / n; - Y += (dy - Y) / n; - XY += (lx * dy - XY) / n; - X2 += (lx * lx - X2) / n; - - if (!domain){ - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - const [intercept, slope] = ols(X, Y, XY, X2), - fn = x => slope * Math.log(x) / lb + intercept, - out = interpose(xmin, xmax, fn); - - out.a = slope; - out.b = intercept; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - - return out; - } - - logarithmic.domain = function(arr){ - return arguments.length ? (domain = arr, logarithmic) : domain; - } - - logarithmic.x = function(fn){ - return arguments.length ? (x = fn, logarithmic) : x; - } - - logarithmic.y = function(fn){ - return arguments.length ? (y = fn, logarithmic) : y; - } - - logarithmic.base = function(n){ - return arguments.length ? (base = n, logarithmic) : base; - } - - return logarithmic; -} \ No newline at end of file diff --git a/src/logarithmic.ts b/src/logarithmic.ts new file mode 100644 index 0000000..f135217 --- /dev/null +++ b/src/logarithmic.ts @@ -0,0 +1,99 @@ +import { determination } from "./utils/determination"; +import { interpose } from "./utils/interpose"; +import { ols } from "./utils/ols"; +import { visitPoints } from "./utils/points"; +import { PredictFunction, DataPoint, Accessor, Domain } from "./types"; + + +type LogarithmicOutput = [DataPoint, DataPoint] & { + a: number; // slope + b: number; // intercept + predict: PredictFunction + rSquared: number; +}; + + +export interface LogarithmicRegression { + (data: T[]): LogarithmicOutput; + + domain(): Domain; + domain(arr: Domain): this; + + x(): Accessor; + x(fn: Accessor): this; + + y(): Accessor; + y(fn: Accessor): this; + + base(): number; + base(b: number): this; +} + +export default function logarithmic(): LogarithmicRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + base: number = Math.E, + domain: Domain; + + const logarithmicRegression = function (data: T[]): LogarithmicOutput { + let n = 0, + X = 0, + Y = 0, + XY = 0, + X2 = 0, + xmin = domain ? +domain[0] : Infinity, + xmax = domain ? +domain[1] : -Infinity, + lb = Math.log(base); + + visitPoints(data, x, y, (dx, dy) => { + const lx = Math.log(dx) / lb; + ++n; + X += (lx - X) / n; + Y += (dy - Y) / n; + XY += (lx * dy - XY) / n; + X2 += (lx * lx - X2) / n; + + if (!domain) { + if (dx < xmin) xmin = dx; + if (dx > xmax) xmax = dx; + } + }); + + const [intercept, slope] = ols(X, Y, XY, X2); + const fn = (xx: number) => slope * Math.log(xx) / lb + intercept; + const out = interpose(xmin, xmax, fn) as LogarithmicOutput; + + out.a = slope; + out.b = intercept; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + + return out; + } as LogarithmicRegression; + + logarithmicRegression.domain = function (arr?: [number, number]) { + if (!arguments.length) return domain; + domain = arr; + return logarithmicRegression; + } as LogarithmicRegression['domain']; + + logarithmicRegression.x = function (fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return logarithmicRegression; + } as LogarithmicRegression['x']; + + logarithmicRegression.y = function (fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return logarithmicRegression; + } as LogarithmicRegression['y']; + + logarithmicRegression.base = function (b?: number) { + if (!arguments.length) return base; + base = b!; + return logarithmicRegression; + } as LogarithmicRegression['base']; + + return logarithmicRegression; +} diff --git a/src/polynomial.js b/src/polynomial.js deleted file mode 100644 index 4b3a650..0000000 --- a/src/polynomial.js +++ /dev/null @@ -1,169 +0,0 @@ -import { determination } from "./utils/determination"; -import { interpose } from "./utils/interpose"; -import { points, visitPoints } from "./utils/points"; -import linear from "./linear"; -import quad from "./quadratic"; - -// Adapted from regression-js by Tom Alexander -// Source: https://github.com/Tom-Alexander/regression-js/blob/master/src/regression.js#L246 -// License: https://github.com/Tom-Alexander/regression-js/blob/master/LICENSE -// ...with ideas from vega-statistics by Jeffrey Heer -// Source: https://github.com/vega/vega/blob/f21cb8792b4e0cbe2b1a3fd44b0f5db370dbaadb/packages/vega-statistics/src/regression/poly.js -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -export default function(){ - let x = d => d[0], - y = d => d[1], - order = 3, - domain; - - function polynomial(data) { - // Use more efficient methods for lower orders - if (order === 1) { - const o = linear().x(x).y(y).domain(domain)(data); - o.coefficients = [o.b, o.a]; - delete o.a; delete o.b; - return o; - } - if (order === 2) { - const o = quad().x(x).y(y).domain(domain)(data); - o.coefficients = [o.c, o.b, o.a]; - delete o.a; delete o.b; delete o.c; - return o; - } - - const [xv, yv, ux, uy] = points(data, x, y), - n = xv.length, - lhs = [], - rhs = [], - k = order + 1; - - let Y = 0, n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - - visitPoints(data, x, y, (dx, dy) => { - ++n0 - Y += (dy - Y) / n0; - if (!domain){ - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - let i, j, l, v, c; - - for (i = 0; i < k; ++i) { - for (l = 0, v = 0; l < n; ++l) { - v += Math.pow(xv[l], i) * yv[l]; - } - lhs.push(v); - - c = new Float64Array(k); - for (j=0; j { - x -= ux; - let y = uy + coef[0] + coef[1] * x + coef[2] * x * x; - for (i = 3; i < k; ++i) y += coef[i] * Math.pow(x, i); - return y; - }, - out = interpose(xmin, xmax, fn); - - out.coefficients = uncenter(k, coef, -ux, uy); - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - - return out; - } - - polynomial.domain = function(arr){ - return arguments.length ? (domain = arr, polynomial) : domain; - } - - polynomial.x = function(fn){ - return arguments.length ? (x = fn, polynomial) : x; - } - - polynomial.y = function(fn){ - return arguments.length ? (y = fn, polynomial) : y; - } - - polynomial.order = function(n){ - return arguments.length ? (order = n, polynomial) : order; - } - - return polynomial; -} - -function uncenter(k, a, x, y) { - const z = Array(k); - let i, j, v, c; - - // initialize to zero - for (i = 0; i < k; ++i) z[i] = 0; - - // polynomial expansion - for (i = k - 1; i >= 0; --i) { - v = a[i]; - c = 1; - z[i] += v; - for (j = 1; j <= i; ++j) { - c *= (i + 1 - j) / j; // binomial coefficent - z[i-j] += v * Math.pow(x, j) * c; - } - } - - // bias term - z[0] += y; - - return z; -} - -// Given an array for a two-dimensional matrix and the polynomial order, -// solve A * x = b using Gaussian elimination. -function gaussianElimination(matrix) { - const n = matrix.length - 1, - coef = []; - - let i, j, k, r, t; - - for (i = 0; i < n; ++i) { - r = i; // max row - for (j = i + 1; j < n; ++j) { - if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { - r = j; - } - } - - for (k = i; k < n + 1; ++k) { - t = matrix[k][i]; - matrix[k][i] = matrix[k][r]; - matrix[k][r] = t; - } - - for (j = i + 1; j < n; ++j) { - for (k = n; k >= i; k--) { - matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i]; - } - } - } - - for (j = n - 1; j >= 0; --j) { - t = 0; - for (k = j + 1; k < n; ++k) { - t += matrix[k][j] * coef[k]; - } - coef[j] = (matrix[n][j] - t) / matrix[j][j]; - } - - return coef; -} \ No newline at end of file diff --git a/src/polynomial.ts b/src/polynomial.ts new file mode 100644 index 0000000..fb3fc6c --- /dev/null +++ b/src/polynomial.ts @@ -0,0 +1,203 @@ +// Adapted from regression-js by Tom Alexander +// Source: https://github.com/Tom-Alexander/regression-js/blob/master/src/regression.js#L246 +// License: https://github.com/Tom-Alexander/regression-js/blob/master/LICENSE +// ...with ideas from vega-statistics by Jeffrey Heer +// Source: https://github.com/vega/vega/blob/f21cb8792b4e0cbe2b1a3fd44b0f5db370dbaadb/packages/vega-statistics/src/regression/poly.js +// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + + +import { determination } from "./utils/determination"; +import { interpose } from "./utils/interpose"; +import { points, visitPoints } from "./utils/points"; +import linear from "./linear"; +import quad from "./quadratic"; +import { PredictFunction, Accessor, DataPoint, Domain } from "./types"; + +export type PolynomialOutput = [DataPoint, DataPoint] & { + coefficients: number[]; + predict: PredictFunction; + rSquared: number; +}; + + +export interface PolynomialRegression { + (data: T[]): PolynomialOutput; + + domain(): Domain; + domain(domain?: Domain): this; + + x(): Accessor; + x(x: Accessor): this; + + y(): Accessor; + y(y: Accessor): this; + + order(): number; + order(order: number): this; +} + +export default function polynomial(): PolynomialRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + order = 3, + domain: Domain; + + const polynomialRegression = function polynomialRegression(data: T[]): PolynomialOutput { + // Shortcut for lower-order polynomials: + if (order === 1) { + const o = linear().x(x).y(y).domain(domain)(data); + const result = [o[0], o[1]] as PolynomialOutput; + result.coefficients = [o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + if (order === 2) { + const o = quad().x(x).y(y).domain(domain)(data); + const result = [o[0], o[1]] as PolynomialOutput; + result.coefficients = [o.c, o.b, o.a]; + result.predict = o.predict; + result.rSquared = o.rSquared; + return result; + } + + const [xv, yv, ux, uy] = points(data, x, y); + const n = xv.length; + const k = order + 1; + const lhs: number[] = []; + const rhs: Float64Array[] = []; + + let Y = 0, + n0 = 0, + xmin = domain ? +domain[0] : Infinity, + xmax = domain ? +domain[1] : -Infinity; + + visitPoints(data, x, y, (dx, dy) => { + n0++; + Y += (dy - Y) / n0; + if (!domain) { + if (dx < xmin) xmin = dx; + if (dx > xmax) xmax = dx; + } + }); + + // Build normal equations + for (let i = 0; i < k; i++) { + // LHS + let v = 0; + for (let l = 0; l < n; l++) { + v += Math.pow(xv[l], i) * yv[l]; + } + lhs.push(v); + + // RHS + const c = new Float64Array(k); + for (let j = 0; j < k; j++) { + let v2 = 0; + for (let l = 0; l < n; l++) { + v2 += Math.pow(xv[l], i + j); + } + c[j] = v2; + } + rhs.push(c); + } + rhs.push(new Float64Array(lhs)); + + const coef = gaussianElimination(rhs); + const fn = (xx: number) => { + let shifted = xx - ux; + let val = uy + coef[0]; + for (let i = 1; i < k; i++) { + val += coef[i] * Math.pow(shifted, i); + } + return val; + }; + + const out = interpose(xmin, xmax, fn); + out.coefficients = uncenter(k, coef, -ux, uy); + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + + return out; + } as PolynomialRegression; + + polynomialRegression.domain = function (arr?: [number, number]) { + if (!arguments.length) return domain; + domain = arr; + return polynomialRegression; + } as PolynomialRegression['domain']; + + polynomialRegression.x = function (fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return polynomialRegression; + } as PolynomialRegression['x']; + + polynomialRegression.y = function (fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return polynomialRegression; + } as PolynomialRegression['y']; + + polynomialRegression.order = function (n?: number) { + if (!arguments.length) return order; + order = n!; + return polynomialRegression; + } as PolynomialRegression['order']; + + return polynomialRegression; +} + +function uncenter(k: number, a: number[], x: number, y: number): number[] { + const z = new Array(k).fill(0); + for (let i = k - 1; i >= 0; --i) { + let v = a[i]; + z[i] += v; + let c = 1; + for (let j = 1; j <= i; ++j) { + c *= (i + 1 - j) / j; // binomial coefficient + z[i - j] += v * Math.pow(x, j) * c; + } + } + // bias term + z[0] += y; + return z; +} + +// Solve A * x = b using Gaussian elimination +function gaussianElimination(matrix: Float64Array[]): number[] { + const n = matrix.length - 1; + const coef = new Array(n); + + for (let i = 0; i < n; i++) { + let r = i; + // find pivot row + for (let j = i + 1; j < n; j++) { + if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) { + r = j; + } + } + // swap columns + for (let k = i; k < n + 1; k++) { + const t = matrix[k][i]; + matrix[k][i] = matrix[k][r]; + matrix[k][r] = t; + } + // reduce + for (let j = i + 1; j < n; j++) { + for (let k = n; k >= i; k--) { + matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i]; + } + } + } + + for (let j = n - 1; j >= 0; j--) { + let t = 0; + for (let k = j + 1; k < n; k++) { + t += matrix[k][j] * coef[k]; + } + coef[j] = (matrix[n][j] - t) / matrix[j][j]; + } + + return coef; +} diff --git a/src/power.js b/src/power.js deleted file mode 100644 index 589efed..0000000 --- a/src/power.js +++ /dev/null @@ -1,63 +0,0 @@ -import { determination } from "./utils/determination"; -import { interpose } from "./utils/interpose"; -import { ols } from "./utils/ols"; -import { visitPoints } from "./utils/points"; - -export default function() { - let x = d => d[0], - y = d => d[1], - domain; - - function power(data){ - let n = 0, - X = 0, - Y = 0, - XY = 0, - X2 = 0, - YS = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - - visitPoints(data, x, y, (dx, dy) => { - const lx = Math.log(dx), - ly = Math.log(dy); - ++n; - X += (lx - X) / n; - Y += (ly - Y) / n; - XY += (lx * ly - XY) / n; - X2 += (lx * lx - X2) / n; - YS += (dy - YS) / n; - - if (!domain){ - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - let [a, b] = ols(X, Y, XY, X2); - a = Math.exp(a); - const fn = x => a * Math.pow(x, b), - out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b; - out.predict = fn; - out.rSquared = determination(data, x, y, YS, fn); - - return out; - } - - power.domain = function(arr){ - return arguments.length ? (domain = arr, power) : domain; - } - - power.x = function(fn){ - return arguments.length ? (x = fn, power) : x; - } - - power.y = function(fn){ - return arguments.length ? (y = fn, power) : y; - } - - return power; -} \ No newline at end of file diff --git a/src/power.ts b/src/power.ts new file mode 100644 index 0000000..54a140e --- /dev/null +++ b/src/power.ts @@ -0,0 +1,92 @@ +import { determination } from "./utils/determination"; +import { interpose } from "./utils/interpose"; +import { ols } from "./utils/ols"; +import { visitPoints } from "./utils/points"; +import { PredictFunction, DataPoint, Accessor, Domain } from "./types"; + +export type PowerOutput = [DataPoint, DataPoint] & { + a: number; + b: number; + predict: PredictFunction; + rSquared: number; +} + + +interface PowerRegression { + (data: T[]): PowerOutput; + + domain(): Domain; + domain(domain?: Domain): this; + + x(): Accessor; + x(x: Accessor): this; + + y(): Accessor; + y(y: Accessor): this; +} + +export default function power(): PowerRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + domain: Domain; + + const powerRegression = function powerRegression(data: T[]): PowerOutput { + let n = 0, + X = 0, + Y = 0, + XY = 0, + X2 = 0, + YS = 0, + xmin = domain ? +domain[0] : Infinity, + xmax = domain ? +domain[1] : -Infinity; + + visitPoints(data, x, y, (dx, dy) => { + const lx = Math.log(dx), + ly = Math.log(dy); + ++n; + X += (lx - X) / n; + Y += (ly - Y) / n; + XY += (lx * ly - XY) / n; + X2 += (lx * lx - X2) / n; + YS += (dy - YS) / n; + + if (!domain) { + if (dx < xmin) xmin = dx; + if (dx > xmax) xmax = dx; + } + }); + + let [a, b] = ols(X, Y, XY, X2); + a = Math.exp(a); + + const fn = (xx: number) => a * Math.pow(xx, b); + const out = interpose(xmin, xmax, fn) as PowerOutput; + + out.a = a; + out.b = b; + out.predict = fn; + out.rSquared = determination(data, x, y, YS, fn); + + return out; + } as PowerRegression; + + powerRegression.domain = function(arr?: Domain) { + if (!arguments.length) return domain; + domain = arr; + return powerRegression; + } as PowerRegression['domain']; + + powerRegression.x = function(fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return powerRegression; + } as PowerRegression['x']; + + powerRegression.y = function(fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return powerRegression; + } as PowerRegression['y']; + + return powerRegression; +} diff --git a/src/quadratic.js b/src/quadratic.js deleted file mode 100644 index 34109f1..0000000 --- a/src/quadratic.js +++ /dev/null @@ -1,80 +0,0 @@ -import { determination } from "./utils/determination"; -import { interpose } from "./utils/interpose"; -import { points, visitPoints } from "./utils/points"; - -export default function(){ - let x = d => d[0], - y = d => d[1], - domain; - - function quadratic(data){ - const [xv, yv, ux, uy] = points(data, x, y), - n = xv.length; - - let X2 = 0, - X3 = 0, - X4 = 0, - XY = 0, - X2Y = 0, - i, dx, dy, x2; - - for (i = 0; i < n;) { - dx = xv[i]; - dy = yv[i++]; - x2 = dx * dx; - X2 += (x2 - X2) / i; - X3 += (x2 * dx - X3) / i; - X4 += (x2 * x2 - X4) / i; - XY += (dx * dy - XY) / i; - X2Y += (x2 * dy - X2Y) / i; - } - - let Y = 0, - n0 = 0, - xmin = domain ? +domain[0] : Infinity, - xmax = domain ? +domain[1] : -Infinity; - - visitPoints(data, x, y, (dx, dy) => { - n0++; - Y += (dy - Y) / n0; - if (!domain){ - if (dx < xmin) xmin = dx; - if (dx > xmax) xmax = dx; - } - }); - - const X2X2 = X4 - (X2 * X2), - d = (X2 * X2X2 - X3 * X3), - a = (X2Y * X2 - XY * X3) / d, - b = (XY * X2X2 - X2Y * X3) / d, - c = -a * X2, - fn = x => { - x = x - ux; - return a * x * x + b * x + c + uy; - }; - - const out = interpose(xmin, xmax, fn); - - out.a = a; - out.b = b - 2 * a * ux; - out.c = c - b * ux + a * ux * ux + uy; - out.predict = fn; - out.rSquared = determination(data, x, y, Y, fn); - - return out; - } - - quadratic.domain = function(arr){ - return arguments.length ? (domain = arr, quadratic) : domain; - } - - quadratic.x = function(fn){ - return arguments.length ? (x = fn, quadratic) : x; - } - - quadratic.y = function(fn){ - return arguments.length ? (y = fn, quadratic) : y; - } - - return quadratic; -} \ No newline at end of file diff --git a/src/quadratic.ts b/src/quadratic.ts new file mode 100644 index 0000000..3f91ffa --- /dev/null +++ b/src/quadratic.ts @@ -0,0 +1,108 @@ +import { determination } from "./utils/determination"; +import { interpose } from "./utils/interpose"; +import { points, visitPoints } from "./utils/points"; +import { Accessor, DataPoint, PredictFunction, Domain } from "./types"; + +export type QuadraticOutput = [DataPoint, DataPoint] & { + a: number; + b: number; + c: number; + predict: PredictFunction; + rSquared: number; +} + + +interface QuadraticRegression { + (data: T[]): QuadraticOutput; + + domain(): Domain; + domain(domain?: Domain): this; + + x(): Accessor; + x(x: Accessor): this; + + y(): Accessor; + y(y: Accessor): this; +} + +export default function quadratic(): QuadraticRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + domain: Domain; + + const quadraticRegression = function quadraticRegression(data: T[]): QuadraticOutput { + const [xv, yv, ux, uy] = points(data, (dd) => x(dd), (dd) => y(dd)); + const n = xv.length; + + let X2 = 0, + X3 = 0, + X4 = 0, + XY = 0, + X2Y = 0, + i, dx, dy, x2; + + for (i = 0; i < n;) { + dx = xv[i]; + dy = yv[i++]; + x2 = dx * dx; + X2 += (x2 - X2) / i; + X3 += ((x2 * dx) - X3) / i; + X4 += ((x2 * x2) - X4) / i; + XY += ((dx * dy) - XY) / i; + X2Y += ((x2 * dy) - X2Y) / i; + } + + let Y = 0, + n0 = 0, + xmin = domain ? +domain[0] : Infinity, + xmax = domain ? +domain[1] : -Infinity; + + visitPoints(data, x, y, (dx2, dy2) => { + n0++; + Y += (dy2 - Y) / n0; + if (!domain) { + if (dx2 < xmin) xmin = dx2; + if (dx2 > xmax) xmax = dx2; + } + }); + + const X2X2 = X4 - (X2 * X2); + const d = (X2 * X2X2 - X3 * X3); + const a = (X2Y * X2 - XY * X3) / d; + const b = (XY * X2X2 - X2Y * X3) / d; + const c = -a * X2; + const fn = (xx: number) => { + const shifted = xx - ux; + return a * shifted * shifted + b * shifted + c + uy; + }; + + const out = interpose(xmin, xmax, fn) as QuadraticOutput; + out.a = a; + out.b = b - 2 * a * ux; + out.c = c - b * ux + a * ux * ux + uy; + out.predict = fn; + out.rSquared = determination(data, x, y, Y, fn); + + return out; + } as QuadraticRegression; + + quadraticRegression.domain = function (arr?: Domain) { + if (!arguments.length) return domain; + domain = arr; + return quadraticRegression; + } as QuadraticRegression['domain']; + + quadraticRegression.x = function (fn?: Accessor) { + if (!arguments.length) return x; + x = fn!; + return quadraticRegression; + } as QuadraticRegression['x']; + + quadraticRegression.y = function (fn?: Accessor) { + if (!arguments.length) return y; + y = fn!; + return quadraticRegression; + } as QuadraticRegression['y']; + + return quadraticRegression; +} diff --git a/src/sigmoidal.ts b/src/sigmoidal.ts new file mode 100644 index 0000000..a38ec50 --- /dev/null +++ b/src/sigmoidal.ts @@ -0,0 +1,133 @@ +import { determination } from "./utils/determination"; +import { interpose } from "./utils/interpose"; +import { visitPoints } from "./utils/points"; +import { PredictFunction, Domain, DataPoint, Accessor } from "./types"; + +/** + * Sigmoidal (logistic) regression of the form: + * f(x) = C + A / (1 + exp(-B * (x - M))) + * where A, B, C, M are parameters found via gradient descent. + */ +export type SigmoidalOutput = [DataPoint, DataPoint] & { + A: number; + B: number; + C: number; + M: number; + predict: PredictFunction; + rSquared: number; +}; + +export interface SigmoidalRegression { + (data: T[]): SigmoidalOutput; + domain(): Domain; + domain(domain: Domain): this; + x(): Accessor; + x(fn: Accessor): this; + y(): Accessor; + y(fn: Accessor): this; +} + +export default function sigmoidal(): SigmoidalRegression { + let x: Accessor = (d: T) => (d as DataPoint)[0], + y: Accessor = (d: T) => (d as DataPoint)[1], + domain: Domain, + maxIter = 2000, + alpha = 1e-4; // learning rate + + function sigmoidalRegression(data: T[]): SigmoidalOutput { + let n = 0, + Xmin = domain ? +domain[0] : Infinity, + Xmax = domain ? +domain[1] : -Infinity, + Ymin = Infinity, + Ymax = -Infinity, + sumY = 0; + + // Gather data & track min/max for domain if not preset + visitPoints(data, x, y, (dx, dy) => { + n++; + sumY += dy; + if (!domain) { + if (dx < Xmin) Xmin = dx; + if (dx > Xmax) Xmax = dx; + } + if (dy < Ymin) Ymin = dy; + if (dy > Ymax) Ymax = dy; + }); + + if (!domain && (Xmin === Infinity || Xmax === -Infinity)) { + Xmin = 0; + Xmax = 1; + } + + // Initialize parameters + let A = Ymax - Ymin; // amplitude + let B = 1; // logistic slope + let C = Ymin; // baseline offset + let M = (Xmin + Xmax) / 2; // midpoint + + // Predict function + function f(xx: number) { + return C + A / (1 + Math.exp(-B * (xx - M))); + } + + // Gradient Descent + for (let iter = 0; iter < maxIter; iter++) { + let dA = 0, dB = 0, dC = 0, dM = 0; + visitPoints(data, x, y, (dx, dy) => { + const yhat = f(dx); + const err = dy - yhat; + const ex = Math.exp(-B * (dx - M)); + const g = 1 / (1 + ex); // logistic + // partial derivatives + const df_dA = g; + const df_dC = 1; + const df_dB = A * g * (1 - g) * (dx - M); + // Note the negative sign for M: + const df_dM = -A * B * g * (1 - g); + + const factor = -2 * err; + dA += factor * df_dA; + dB += factor * df_dB; + dC += factor * df_dC; + dM += factor * df_dM; + }); + A -= alpha * (dA / n); + B -= alpha * (dB / n); + C -= alpha * (dC / n); + M -= alpha * (dM / n); + } + + const predict = (xx: number) => C + A / (1 + Math.exp(-B * (xx - M))); + const out = interpose(Xmin, Xmax, predict) as SigmoidalOutput; + out.A = A; + out.B = B; + out.C = C; + out.M = M; + out.predict = predict; + + // R^2 + const meanY = sumY / n; + out.rSquared = determination(data, x, y, meanY, predict); + return out; + } + + sigmoidalRegression.domain = function(arr?: Domain): any { + if (!arguments.length) return domain; + domain = arr; + return sigmoidalRegression; + }; + + sigmoidalRegression.x = function(fn?: Accessor): any { + if (!arguments.length) return x; + x = fn!; + return sigmoidalRegression; + }; + + sigmoidalRegression.y = function(fn?: Accessor): any { + if (!arguments.length) return y; + y = fn!; + return sigmoidalRegression; + }; + + return sigmoidalRegression; +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..f31848d --- /dev/null +++ b/src/types.ts @@ -0,0 +1,4 @@ +export type DataPoint = [number, number]; +export type Accessor = (d: T, i?: number, data?: T[]) => number; +export type PredictFunction = (x: number) => number; +export type Domain = [number, number] | undefined; diff --git a/src/utils/determination.js b/src/utils/determination.js deleted file mode 100644 index 117eaea..0000000 --- a/src/utils/determination.js +++ /dev/null @@ -1,18 +0,0 @@ -import { visitPoints } from "./points"; - -// Given a dataset, x- and y-accessors, the mean center of the y values, and a predict function, -// return the coefficient of determination, or R squared. -export function determination(data, x, y, uY, predict){ - let SSE = 0, - SST = 0; - - visitPoints(data, x, y, (dx, dy) => { - const sse = dy - predict(dx), - sst = dy - uY; - - SSE += sse * sse; - SST += sst * sst; - }); - - return 1 - SSE / SST; -} \ No newline at end of file diff --git a/src/utils/determination.ts b/src/utils/determination.ts new file mode 100644 index 0000000..1c23e79 --- /dev/null +++ b/src/utils/determination.ts @@ -0,0 +1,26 @@ +import { visitPoints } from "./points"; +import { Accessor, DataPoint, PredictFunction } from "../types"; + +/** + * Given a dataset, x- and y-accessors, the mean center of the y-values (uY), + * and a prediction function, return the coefficient of determination, R^2. + */ +export function determination( + data: T[], + x: Accessor, + y: Accessor, + uY: number, + predict: PredictFunction +): number { + let SSE = 0, // Sum of Squared Errors + SST = 0; // Total Sum of Squares + + visitPoints(data, x, y, (dx, dy) => { + const sse = dy - predict(dx); + const sst = dy - uY; + SSE += sse * sse; + SST += sst * sst; + }); + + return 1 - SSE / SST; +} diff --git a/src/utils/geometry.js b/src/utils/geometry.js deleted file mode 100644 index 29b9134..0000000 --- a/src/utils/geometry.js +++ /dev/null @@ -1,9 +0,0 @@ -// Returns the angle of a line in degrees. -export function angle(line){ - return Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * 180 / Math.PI; -} - -// Returns the midpoint of a line. -export function midpoint(line){ - return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2]; -} \ No newline at end of file diff --git a/src/utils/geometry.ts b/src/utils/geometry.ts new file mode 100644 index 0000000..e5b75dd --- /dev/null +++ b/src/utils/geometry.ts @@ -0,0 +1,21 @@ +import { DataPoint } from "../types"; + +/** + * Returns the angle of a line in degrees. + */ +export function angle(line: [DataPoint, DataPoint]): number { + return ( + Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * + (180 / Math.PI) + ); +} + +/** + * Returns the midpoint of a line. + */ +export function midpoint(line: [DataPoint, DataPoint]): DataPoint { + return [ + (line[0][0] + line[1][0]) / 2, + (line[0][1] + line[1][1]) / 2 + ]; +} diff --git a/src/utils/interpose.js b/src/utils/interpose.js deleted file mode 100644 index 61802c8..0000000 --- a/src/utils/interpose.js +++ /dev/null @@ -1,40 +0,0 @@ -import { angle, midpoint } from "./geometry"; - -// Given a start point, an end point, and a prediciton function, -// returns a smooth line. -export function interpose(xmin, xmax, predict){ - const l = Math.log(xmax - xmin) * Math.LOG10E + 1 | 0; - const precision = 1 * Math.pow(10, -l / 2 - 1), maxIter = 1e4; - let points = [px(xmin), px(xmax)], iter = 0; - - while (find(points) && iter < maxIter); - - return points; - - function px(x){ - return [x, predict(x)]; - } - - function find(points){ - iter++; - const n = points.length; - let found = false; - - for (let i = 0; i < n - 1; i++){ - const p0 = points[i], - p1 = points[i + 1], - m = midpoint([p0, p1]), - mp = px(m[0]), - a0 = angle([p0, m]), - a1 = angle([p0, mp]), - a = Math.abs(a0 - a1); - - if (a > precision){ - points.splice(i + 1, 0, mp); - found = true; - } - } - - return found; - } -} \ No newline at end of file diff --git a/src/utils/interpose.ts b/src/utils/interpose.ts new file mode 100644 index 0000000..41fa987 --- /dev/null +++ b/src/utils/interpose.ts @@ -0,0 +1,49 @@ +import { angle, midpoint } from "./geometry"; +import { PredictFunction, DataPoint } from "../types"; + +/** + * Given a start point (xmin), an end point (xmax), + * and a prediction function, returns a smooth line. + */ +export function interpose( + xmin: number, + xmax: number, + predict: PredictFunction +): [DataPoint, DataPoint] { + const l = (Math.log(xmax - xmin) * Math.LOG10E + 1) | 0; + const precision = Math.pow(10, -l / 2 - 1); + const maxIter = 1e4; + let points: [DataPoint, DataPoint] = [px(xmin), px(xmax)]; + let iter = 0; + + while (find(points) && iter < maxIter) ; + + return points; + + function px(x: number): DataPoint { + return [x, predict(x)]; + } + + function find(points: DataPoint[]): boolean { + iter++; + const n = points.length; + let found = false; + + for (let i = 0; i < n - 1; i++) { + const p0 = points[i]; + const p1 = points[i + 1]; + const m = midpoint([p0, p1]); + const mp = px(m[0]); + const a0 = angle([p0, m]); + const a1 = angle([p0, mp]); + const a = Math.abs(a0 - a1); + + if (a > precision) { + points.splice(i + 1, 0, mp); + found = true; + } + } + + return found; + } +} diff --git a/src/utils/median.js b/src/utils/median.ts similarity index 52% rename from src/utils/median.js rename to src/utils/median.ts index d040c87..f823d9a 100644 --- a/src/utils/median.js +++ b/src/utils/median.ts @@ -1,6 +1,8 @@ -// Returns the medium value of an array of numbers. -export function median(arr){ +/** + * Returns the median value of an array of numbers. + */ +export function median(arr: Float64Array): number { arr.sort((a, b) => a - b); var i = arr.length / 2; return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)]; -} \ No newline at end of file +} diff --git a/src/utils/ols.js b/src/utils/ols.js deleted file mode 100644 index f621548..0000000 --- a/src/utils/ols.js +++ /dev/null @@ -1,10 +0,0 @@ -// Ordinary Least Squares from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js -export function ols(uX, uY, uXY, uX2) { - const delta = uX2 - uX * uX, - slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, - intercept = uY - slope * uX; - - return [intercept, slope]; -} \ No newline at end of file diff --git a/src/utils/ols.ts b/src/utils/ols.ts new file mode 100644 index 0000000..8c43c41 --- /dev/null +++ b/src/utils/ols.ts @@ -0,0 +1,18 @@ +/** + * Ordinary Least Squares from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/ols.js + */ + +export function ols( + uX: number, + uY: number, + uXY: number, + uX2: number +): [number, number] { + const delta = uX2 - uX * uX, + slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, + intercept = uY - slope * uX; + + return [intercept, slope]; +} diff --git a/src/utils/points.js b/src/utils/points.js deleted file mode 100644 index 5e1a5c8..0000000 --- a/src/utils/points.js +++ /dev/null @@ -1,51 +0,0 @@ -// Adapted from vega-statistics by Jeffrey Heer -// License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE -// Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js -export function points(data, x, y, sort) { - data = data.filter((d, i) => { - let u = x(d, i), v = y(d, i); - return u != null && isFinite(u) && v != null && isFinite(v); - }); - - if (sort) { - data.sort((a, b) => x(a) - x(b)); - } - - const n = data.length, - X = new Float64Array(n), - Y = new Float64Array(n); - - // extract values, calculate means - let ux = 0, uy = 0, xv, yv, d; - for (let i = 0; i < n; ) { - d = data[i]; - X[i] = xv = +x(d, i, data); - Y[i] = yv = +y(d, i, data); - ++i; - ux += (xv - ux) / i; - uy += (yv - uy) / i; - } - - // mean center the data - for (let i = 0; i < n; ++i) { - X[i] -= ux; - Y[i] -= uy; - } - - return [X, Y, ux, uy]; -} - - -export function visitPoints(data, x, y, cb){ - let iterations = 0; - - for (let i = 0, n = data.length; i < n; i++) { - const d = data[i], - dx = +x(d, i, data), - dy = +y(d, i, data); - - if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { - cb(dx, dy, iterations++); - } - } -} diff --git a/src/utils/points.ts b/src/utils/points.ts new file mode 100644 index 0000000..944377e --- /dev/null +++ b/src/utils/points.ts @@ -0,0 +1,67 @@ +import { Accessor } from "../types"; + +/** + * Adapted from vega-statistics by Jeffrey Heer + * License: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/LICENSE + * Source: https://github.com/vega/vega/blob/f058b099decad9db78301405dd0d2e9d8ba3d51a/packages/vega-statistics/src/regression/points.js + */ +export function points( + data: T[], + x: Accessor, + y: Accessor, + sort?: boolean +): [Float64Array, Float64Array, number, number] { + data = data.filter((d, i) => { + let u = x(d, i), v = y(d, i); + return u != null && isFinite(u) && v != null && isFinite(v); + }); + + + if (sort) { + data.sort((a, b) => x(a) - x(b)); + } + + + const n = data.length, + X = new Float64Array(n), + Y = new Float64Array(n); + + // extract values, calculate means + let ux = 0, uy = 0, xv, yv, d; + for (let i = 0; i < n;) { + d = data[i]; + X[i] = xv = +x(d, i, data); + Y[i] = yv = +y(d, i, data); + ++i; + ux += (xv - ux) / i; + uy += (yv - uy) / i; + } + + // mean center the data + for (let i = 0; i < n; ++i) { + X[i] -= ux; + Y[i] -= uy; + } + + return [X, Y, ux, uy]; +} + +/** + * Iterates over valid data points, invoking a callback for each. + */ +export function visitPoints( + data: T[], + x: Accessor, + y: Accessor, + cb: (dx: number, dy: number, index: number) => void +): void { + let iterations = 0; + for (let i = 0; i < data.length; i++) { + const d = data[i]; + const dx = +x(d, i, data); + const dy = +y(d, i, data); + if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) { + cb(dx, dy, iterations++); + } + } +} diff --git a/test/loess-test.js b/test/loess-test.js index 0f163f3..13c965c 100644 --- a/test/loess-test.js +++ b/test/loess-test.js @@ -27,4 +27,4 @@ tape("loess(data) calculates the LOESS regression", function(test) { test.deepEqual(r, output); test.end(); -}); \ No newline at end of file +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2ac344c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES5", + "module": "ESNext", + "declaration": true, + "declarationDir": "./dist/types", + "outDir": "./dist", + "allowJs": true, + "strict": true + }, + "include": [ + "index.ts", + "src/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist", + "**/*.test.js" + ] +}