Skip to content

Commit 8ff8278

Browse files
committed
[FIX] charts: non-invertible matrix returns NaN as predicted data
Task Description When trying to make a trending line, almost all model use matrix computation to get the predicted data, with some matrix multiplications and inversions. When the matrixes aren't invertible the user get a traceback, which is not fine. This PR aims to fix these issues by returning an array of NaN when there is an error in the computation of the predicted dataset. Related Task Task: 4328743
1 parent 064a7cf commit 8ff8278

File tree

2 files changed

+48
-30
lines changed

2 files changed

+48
-30
lines changed

src/helpers/figures/charts/chart_common.ts

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -535,41 +535,45 @@ export function interpolateData(
535535
const labelRange = labelMax - labelMin;
536536
const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
537537
const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
538-
switch (config.type) {
539-
case "polynomial": {
540-
const order = config.order ?? 2;
541-
if (order === 1) {
542-
return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
538+
try {
539+
switch (config.type) {
540+
case "polynomial": {
541+
const order = config.order ?? 2;
542+
if (order === 1) {
543+
return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
544+
}
545+
const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
546+
return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
543547
}
544-
const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
545-
return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
546-
}
547-
case "exponential": {
548-
const positiveLogValues: number[] = [];
549-
const filteredLabels: number[] = [];
550-
for (let i = 0; i < values.length; i++) {
551-
if (values[i] > 0) {
552-
positiveLogValues.push(Math.log(values[i]));
553-
filteredLabels.push(normalizedLabels[i]);
548+
case "exponential": {
549+
const positiveLogValues: number[] = [];
550+
const filteredLabels: number[] = [];
551+
for (let i = 0; i < values.length; i++) {
552+
if (values[i] > 0) {
553+
positiveLogValues.push(Math.log(values[i]));
554+
filteredLabels.push(normalizedLabels[i]);
555+
}
554556
}
557+
if (!filteredLabels.length) {
558+
return Array.from({ length: newLabels.length }, () => NaN);
559+
}
560+
return expM(
561+
predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true)
562+
)[0];
555563
}
556-
if (!filteredLabels.length) {
557-
return [];
564+
case "logarithmic": {
565+
return predictLinearValues(
566+
[values],
567+
logM([normalizedLabels]),
568+
logM([normalizedNewLabels]),
569+
true
570+
)[0];
558571
}
559-
return expM(
560-
predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true)
561-
)[0];
562-
}
563-
case "logarithmic": {
564-
return predictLinearValues(
565-
[values],
566-
logM([normalizedLabels]),
567-
logM([normalizedNewLabels]),
568-
true
569-
)[0];
572+
default:
573+
return [];
570574
}
571-
default:
572-
return [];
575+
} catch (e) {
576+
return Array.from({ length: newLabels.length }, () => NaN);
573577
}
574578
}
575579

tests/figures/chart/chart_plugin.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3188,6 +3188,20 @@ describe("trending line", () => {
31883188
}
31893189
});
31903190

3191+
test("non-invertible matrix doesn't throw error", () => {
3192+
// prettier-ignore
3193+
setGrid(model, {
3194+
A1: "label",
3195+
A2: "0",
3196+
A3: "1",
3197+
});
3198+
updateChart(model, "1", {
3199+
dataSets: [{ dataRange: "A1:A3", trend: { display: true, type: "polynomial", order: 2 } }],
3200+
});
3201+
const runtime = model.getters.getChartRuntime("1") as LineChartRuntime;
3202+
expect(runtime.chartJsConfig.data.datasets[1].data.every((x) => isNaN(Number(x)))).toBeTruthy();
3203+
});
3204+
31913205
test("trend line works with real date values as labels", () => {
31923206
setGrid(model, {
31933207
B1: "1",

0 commit comments

Comments
 (0)