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

Co-authored-by: Kyle Cunningham <kyle@codeincarnate.com>
This commit is contained in:
Leon Sorokin
2022-06-16 17:28:41 -05:00
committed by GitHub
parent 1b51cd2043
commit 406509cdd3
3 changed files with 59 additions and 30 deletions

View File

@@ -111,12 +111,14 @@ describe('nullInsertThreshold Transformer', () => {
const result = applyNullInsertThreshold({
frame: df,
refFieldName: null,
refFieldPseudoMin: 1,
refFieldPseudoMin: -0.5,
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([
null,
null,
null,
null,
null,
@@ -132,6 +134,8 @@ describe('nullInsertThreshold Transformer', () => {
8,
]);
expect(result.fields[2].values.toArray()).toStrictEqual([
null,
null,
null,
null,
null,
@@ -160,7 +164,7 @@ describe('nullInsertThreshold Transformer', () => {
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([
4,
null,
@@ -174,7 +178,6 @@ describe('nullInsertThreshold Transformer', () => {
8,
null,
null,
null,
]);
expect(result.fields[2].values.toArray()).toStrictEqual([
'a',
@@ -189,7 +192,6 @@ describe('nullInsertThreshold Transformer', () => {
'c',
null,
null,
null,
]);
// 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
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[1].values.toArray()).toStrictEqual([1, 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
test.skip('should insert nulls at +threshold (when defined) instead of +interval', () => {
const df = new MutableDataFrame({

View File

@@ -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;
@@ -76,10 +76,21 @@ export function applyNullInsertThreshold(opts: NullInsertOptions): DataFrame {
return {
...frame,
length: filledFieldValues[0].length,
fields: frame.fields.map((field, i) => ({
...field,
values: new ArrayVector(filledFieldValues[i]),
})),
fields: frame.fields.map((field, i) => {
let f = {
...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
) {
const len = refValues.length;
let prevValue: number = refValues[0];
const refValuesNew: number[] = [];
// Continiuously add the threshold to the minimum value
// While this is less than "prevValue" which is the lowest
// time value in the sequence add in time frames
if (refFieldPseudoMin != null) {
let minValue = refFieldPseudoMin - threshold;
// Continiuously subtract the threshold from the first data
// point filling in insert values accordingly
if (refFieldPseudoMin != null && refFieldPseudoMin < refValues[0]) {
// this will be 0 or 1 threshold increment left of visible range
let prevSlot = incrRoundDn(refFieldPseudoMin, threshold);
while (minValue < prevValue - threshold) {
let nextValue = minValue + threshold;
refValuesNew.push(getInsertValue(minValue, nextValue, threshold));
minValue = nextValue;
while (prevSlot < refValues[0]) {
// (prevSlot - threshold) is used to simulate the previous 'real' data point, as getInsertValue expects
refValuesNew.push(getInsertValue(prevSlot - threshold, prevSlot, threshold));
prevSlot += threshold;
}
}
// Insert initial value
refValuesNew.push(prevValue);
refValuesNew.push(refValues[0]);
let prevValue: number = refValues[0];
// Fill nulls when a value is greater than
// the threshold value
@@ -141,8 +153,8 @@ function nullInsertThreshold(
}
// At the end of the sequence
if (refFieldPseudoMax != null) {
while (prevValue + threshold <= refFieldPseudoMax) {
if (refFieldPseudoMax != null && refFieldPseudoMax > prevValue) {
while (prevValue + threshold < refFieldPseudoMax) {
refValuesNew.push(getInsertValue(prevValue, refFieldPseudoMax, threshold));
prevValue += threshold;
}

View File

@@ -401,11 +401,9 @@ export function prepareTimelineFields(
refFieldPseudoMax: timeRange.to.valueOf(),
});
// Mark the field state as having a null threhold applied
frame.fields[0].state = {
...frame.fields[0].state,
nullThresholdApplied: true,
};
if (nulledFrame !== frame) {
changed = true;
}
const fields: Field[] = [];
for (let field of nullToValue(nulledFrame).fields) {