UNPKG

@macrostrat/column-components

Version:

React rendering primitives for stratigraphic columns

163 lines (162 loc) 4.38 kB
import type from "./type.js"; const { log, pow, floor, abs } = Math; function analyze(data, key = null) { const r = { min: Number.MAX_VALUE, max: Number.MAX_VALUE * -1, sum: 0, values: [], count: 0 }; if (type(data) === "object") { data = Object.values(data); } data.forEach((val) => { if (key && type(val) === "object") val = val[key]; if (val !== void 0 && val !== null && !isNaN(val)) { r.values.push(val); r.sum += val; if (val < r.min) r.min = val; if (val > r.max) r.max = val; r.count += 1; } }); r.domain = [r.min, r.max]; r.limits = (mode, num) => limits(r, mode, num); return r; } function limits(data, mode = "equal", num = 7) { if (type(data) == "array") { data = analyze(data); } const { min, max } = data; const values = data.values.sort((a, b) => a - b); if (num === 1) { return [min, max]; } const limits2 = []; if (mode.substr(0, 1) === "c") { limits2.push(min); limits2.push(max); } if (mode.substr(0, 1) === "e") { limits2.push(min); for (let i = 1; i < num; i++) { limits2.push(min + i / num * (max - min)); } limits2.push(max); } else if (mode.substr(0, 1) === "l") { if (min <= 0) { throw new Error( "Logarithmic scales are only possible for values > 0" ); } const min_log = Math.LOG10E * log(min); const max_log = Math.LOG10E * log(max); limits2.push(min); for (let i = 1; i < num; i++) { limits2.push(pow(10, min_log + i / num * (max_log - min_log))); } limits2.push(max); } else if (mode.substr(0, 1) === "q") { limits2.push(min); for (let i = 1; i < num; i++) { const p = (values.length - 1) * i / num; const pb = floor(p); if (pb === p) { limits2.push(values[pb]); } else { const pr = p - pb; limits2.push(values[pb] * (1 - pr) + values[pb + 1] * pr); } } limits2.push(max); } else if (mode.substr(0, 1) === "k") { let cluster; const n = values.length; const assignments = new Array(n); const clusterSizes = new Array(num); let repeat = true; let nb_iters = 0; let centroids = null; centroids = []; centroids.push(min); for (let i = 1; i < num; i++) { centroids.push(min + i / num * (max - min)); } centroids.push(max); while (repeat) { for (let j = 0; j < num; j++) { clusterSizes[j] = 0; } for (let i = 0; i < n; i++) { const value = values[i]; let mindist = Number.MAX_VALUE; let best; for (let j = 0; j < num; j++) { const dist = abs(centroids[j] - value); if (dist < mindist) { mindist = dist; best = j; } clusterSizes[best]++; assignments[i] = best; } } const newCentroids = new Array(num); for (let j = 0; j < num; j++) { newCentroids[j] = null; } for (let i = 0; i < n; i++) { cluster = assignments[i]; if (newCentroids[cluster] === null) { newCentroids[cluster] = values[i]; } else { newCentroids[cluster] += values[i]; } } for (let j = 0; j < num; j++) { newCentroids[j] *= 1 / clusterSizes[j]; } repeat = false; for (let j = 0; j < num; j++) { if (newCentroids[j] !== centroids[j]) { repeat = true; break; } } centroids = newCentroids; nb_iters++; if (nb_iters > 200) { repeat = false; } } const kClusters = {}; for (let j = 0; j < num; j++) { kClusters[j] = []; } for (let i = 0; i < n; i++) { cluster = assignments[i]; kClusters[cluster].push(values[i]); } let tmpKMeansBreaks = []; for (let j = 0; j < num; j++) { tmpKMeansBreaks.push(kClusters[j][0]); tmpKMeansBreaks.push(kClusters[j][kClusters[j].length - 1]); } tmpKMeansBreaks = tmpKMeansBreaks.sort((a, b) => a - b); limits2.push(tmpKMeansBreaks[0]); for (let i = 1; i < tmpKMeansBreaks.length; i += 2) { const v = tmpKMeansBreaks[i]; if (!isNaN(v) && limits2.indexOf(v) === -1) { limits2.push(v); } } } return limits2; } export { analyze, limits }; //# sourceMappingURL=analyze.js.map