@visactor/vmind
Version:
<div align="center"> <a href="https://github.com/VisActor#gh-light-mode-only" target="_blank"> <img alt="VisActor Logo" width="200" src="https://github.com/VisActor/.github/blob/main/profile/logo_500_200_light.svg"/> </a> <a href="https://githu
68 lines (58 loc) • 3.09 kB
JavaScript
import { isArray } from "@visactor/vutils";
import { InsightType } from "../../type";
import { ChartType, DataType } from "../../../../types";
import { getIntersection } from "../../../../utils/common";
import { getAbnormalByIQR, getAbnormalByZScores } from "./statistics";
import { LOF } from "./lof";
import { isPercenSeries } from "../../utils";
function getDistanceList(dataList, isTimeSeries) {
const res = [], n = dataList.length;
let index = 0;
if (isTimeSeries) for (let i = 0; i < n - 1; i++) res.push({
index: index++,
indexPair: [ i, i + 1 ],
value: Math.abs(dataList[i].value - dataList[i + 1].value)
}); else for (let i = 0; i < n - 1; i++) for (let j = i + 1; j < n; j++) {
const distance = Math.abs(dataList[i].value - dataList[j].value);
res.push({
index: index++,
indexPair: [ i, j ],
value: distance
});
}
return res;
}
const difference = (context, options) => {
const result = [], {zScore: zScore = 3, lofThreshold: lofThreshold = 3} = options || {}, {seriesDataMap: seriesDataMap, cell: cell, fieldInfo: fieldInfo, spec: spec} = context, {y: celly, x: cellx} = cell, yField = isArray(celly) ? celly.flat() : [ celly ], xField = isArray(cellx) ? cellx[0] : cellx, isTimeSeries = [ DataType.TIME, DataType.DATE ].includes(fieldInfo.find((info => info.fieldName === xField)).type);
return Object.keys(seriesDataMap).forEach((group => {
const dataset = seriesDataMap[group];
yField.forEach((field => {
const dataList = dataset.map(((d, index) => ({
index: index,
value: d.dataItem[field]
})));
if (isPercenSeries(spec, field)) return;
const distanceList = getDistanceList(dataList, isTimeSeries), zScoreResult = distanceList.length >= 30 ? getAbnormalByZScores(distanceList, zScore) : null, iqrResult = distanceList.length >= 10 ? getAbnormalByIQR(distanceList) : [], staticResult = zScoreResult ? getIntersection(zScoreResult, iqrResult) : iqrResult, lofResult = LOF(distanceList.map((v => v.value)), lofThreshold).map((v => v.index));
(getIntersection(staticResult, lofResult) || []).forEach((index => {
const distanceItem = distanceList[index], lofInsight = {
type: InsightType.PairOutlier,
data: distanceItem.indexPair.map((v => dataset[dataList[v].index])),
fieldId: field,
value: distanceItem.value,
significant: 1,
seriesName: group
};
result.push(lofInsight);
}));
}));
})), result;
};
export const DifferenceAlg = {
name: "difference",
forceChartType: [ ChartType.DualAxisChart, ChartType.LineChart, ChartType.BarChart, ChartType.AreaChart, ChartType.WaterFallChart ],
insightType: InsightType.PairOutlier,
algorithmFunction: difference,
supportPercent: !1,
supportStack: !1
};
//# sourceMappingURL=difference.js.map