StateTimeline: make sure we use result of applyNullInsertThreshold() (#50988) (#50993)

Co-authored-by: Kyle Cunningham <kyle@codeincarnate.com>
(cherry picked from commit 406509cdd3)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
Grot (@grafanabot)
2022-06-16 17:46:30 -05:00
committed by GitHub
co-authored by Leon Sorokin
parent b03353537d
commit bdd1b2a6af
3 changed files with 59 additions and 30 deletions
@@ -111,12 +111,14 @@ describe('nullInsertThreshold Transformer', () => {
const result = applyNullInsertThreshold({ const result = applyNullInsertThreshold({
frame: df, frame: df,
refFieldName: null, refFieldName: null,
refFieldPseudoMin: 1, refFieldPseudoMin: -0.5,
refFieldPseudoMax: 13, refFieldPseudoMax: 13,
}); });
expect(result.fields[0].values.toArray()).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]); expect(result.fields[0].values.toArray()).toStrictEqual([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
expect(result.fields[1].values.toArray()).toStrictEqual([ expect(result.fields[1].values.toArray()).toStrictEqual([
null,
null,
null, null,
null, null,
null, null,
@@ -132,6 +134,8 @@ describe('nullInsertThreshold Transformer', () => {
8, 8,
]); ]);
expect(result.fields[2].values.toArray()).toStrictEqual([ expect(result.fields[2].values.toArray()).toStrictEqual([
null,
null,
null, null,
null, null,
null, null,
@@ -160,7 +164,7 @@ describe('nullInsertThreshold Transformer', () => {
const result = applyNullInsertThreshold({ frame: df, refFieldName: null, refFieldPseudoMax: 13 }); const result = applyNullInsertThreshold({ frame: df, refFieldName: null, refFieldPseudoMax: 13 });
expect(result.fields[0].values.toArray()).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]); expect(result.fields[0].values.toArray()).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
expect(result.fields[1].values.toArray()).toStrictEqual([ expect(result.fields[1].values.toArray()).toStrictEqual([
4, 4,
null, null,
@@ -174,7 +178,6 @@ describe('nullInsertThreshold Transformer', () => {
8, 8,
null, null,
null, null,
null,
]); ]);
expect(result.fields[2].values.toArray()).toStrictEqual([ expect(result.fields[2].values.toArray()).toStrictEqual([
'a', 'a',
@@ -189,7 +192,6 @@ describe('nullInsertThreshold Transformer', () => {
'c', 'c',
null, null,
null, null,
null,
]); ]);
// should work for frames with 1 datapoint // should work for frames with 1 datapoint
@@ -202,15 +204,32 @@ describe('nullInsertThreshold Transformer', () => {
], ],
}); });
// Max is 2 as opposed to the above 13 otherwise // Max is 2.5 as opposed to the above 13 otherwise
// we get 12 nulls instead of the additional 1 // we get 12 nulls instead of the additional 1
const result2 = applyNullInsertThreshold({ frame: df2, refFieldName: null, refFieldPseudoMax: 2 }); const result2 = applyNullInsertThreshold({ frame: df2, refFieldName: null, refFieldPseudoMax: 2.5 });
expect(result2.fields[0].values.toArray()).toStrictEqual([1, 2]); expect(result2.fields[0].values.toArray()).toStrictEqual([1, 2]);
expect(result2.fields[1].values.toArray()).toStrictEqual([1, null]); expect(result2.fields[1].values.toArray()).toStrictEqual([1, null]);
expect(result2.fields[2].values.toArray()).toStrictEqual(['a', null]); expect(result2.fields[2].values.toArray()).toStrictEqual(['a', null]);
}); });
test('should not insert trailing null at end +interval when timeRange.to.valueOf() equals threshold', () => {
const df = new MutableDataFrame({
refId: 'A',
fields: [
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1] },
{ name: 'One', type: FieldType.number, values: [1] },
{ name: 'Two', type: FieldType.string, values: ['a'] },
],
});
const result = applyNullInsertThreshold({ frame: df, refFieldName: null, refFieldPseudoMax: 2 });
expect(result.fields[0].values.toArray()).toStrictEqual([1]);
expect(result.fields[1].values.toArray()).toStrictEqual([1]);
expect(result.fields[2].values.toArray()).toStrictEqual(['a']);
});
// TODO: make this work // TODO: make this work
test.skip('should insert nulls at +threshold (when defined) instead of +interval', () => { test.skip('should insert nulls at +threshold (when defined) instead of +interval', () => {
const df = new MutableDataFrame({ const df = new MutableDataFrame({
@@ -1,4 +1,4 @@
import { ArrayVector, DataFrame, FieldType } from '@grafana/data'; import { ArrayVector, DataFrame, FieldType, incrRoundDn } from '@grafana/data';
type InsertMode = (prev: number, next: number, threshold: number) => number; type InsertMode = (prev: number, next: number, threshold: number) => number;
@@ -76,10 +76,21 @@ export function applyNullInsertThreshold(opts: NullInsertOptions): DataFrame {
return { return {
...frame, ...frame,
length: filledFieldValues[0].length, length: filledFieldValues[0].length,
fields: frame.fields.map((field, i) => ({ fields: frame.fields.map((field, i) => {
...field, let f = {
values: new ArrayVector(filledFieldValues[i]), ...field,
})), values: new ArrayVector(filledFieldValues[i]),
};
if (i === 0) {
f.state = {
...field.state,
nullThresholdApplied: true,
};
}
return f;
}),
}; };
} }
@@ -101,24 +112,25 @@ function nullInsertThreshold(
thorough: boolean thorough: boolean
) { ) {
const len = refValues.length; const len = refValues.length;
let prevValue: number = refValues[0];
const refValuesNew: number[] = []; const refValuesNew: number[] = [];
// Continiuously add the threshold to the minimum value // Continiuously subtract the threshold from the first data
// While this is less than "prevValue" which is the lowest // point filling in insert values accordingly
// time value in the sequence add in time frames if (refFieldPseudoMin != null && refFieldPseudoMin < refValues[0]) {
if (refFieldPseudoMin != null) { // this will be 0 or 1 threshold increment left of visible range
let minValue = refFieldPseudoMin - threshold; let prevSlot = incrRoundDn(refFieldPseudoMin, threshold);
while (minValue < prevValue - threshold) { while (prevSlot < refValues[0]) {
let nextValue = minValue + threshold; // (prevSlot - threshold) is used to simulate the previous 'real' data point, as getInsertValue expects
refValuesNew.push(getInsertValue(minValue, nextValue, threshold)); refValuesNew.push(getInsertValue(prevSlot - threshold, prevSlot, threshold));
minValue = nextValue; prevSlot += threshold;
} }
} }
// Insert initial value // Insert initial value
refValuesNew.push(prevValue); refValuesNew.push(refValues[0]);
let prevValue: number = refValues[0];
// Fill nulls when a value is greater than // Fill nulls when a value is greater than
// the threshold value // the threshold value
@@ -141,8 +153,8 @@ function nullInsertThreshold(
} }
// At the end of the sequence // At the end of the sequence
if (refFieldPseudoMax != null) { if (refFieldPseudoMax != null && refFieldPseudoMax > prevValue) {
while (prevValue + threshold <= refFieldPseudoMax) { while (prevValue + threshold < refFieldPseudoMax) {
refValuesNew.push(getInsertValue(prevValue, refFieldPseudoMax, threshold)); refValuesNew.push(getInsertValue(prevValue, refFieldPseudoMax, threshold));
prevValue += threshold; prevValue += threshold;
} }
@@ -401,11 +401,9 @@ export function prepareTimelineFields(
refFieldPseudoMax: timeRange.to.valueOf(), refFieldPseudoMax: timeRange.to.valueOf(),
}); });
// Mark the field state as having a null threhold applied if (nulledFrame !== frame) {
frame.fields[0].state = { changed = true;
...frame.fields[0].state, }
nullThresholdApplied: true,
};
const fields: Field[] = []; const fields: Field[] = [];
for (let field of nullToValue(nulledFrame).fields) { for (let field of nullToValue(nulledFrame).fields) {