mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Transformations: Handle undefined values when calculating mean and total in add field from calculations (#78645)
* Transformations: Handle undefined values when calculating mean and total in add field from calculations * fix typo * change to != and add tests
This commit is contained in:
parent
703deeff0b
commit
1ab23108c4
@ -597,6 +597,32 @@ describe('calculateField transformer w/ timeseries', () => {
|
|||||||
expect(data.fields[1].values[2]).toEqual(2);
|
expect(data.fields[1].values[2]).toEqual(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('calculates cumulative total with undefined values', async () => {
|
||||||
|
const cfg = {
|
||||||
|
id: DataTransformerID.calculateField,
|
||||||
|
options: {
|
||||||
|
mode: CalculateFieldMode.CumulativeFunctions,
|
||||||
|
cumulative: {
|
||||||
|
field: 'x',
|
||||||
|
reducer: ReducerID.sum,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const series = toDataFrame({
|
||||||
|
fields: [{ name: 'x', type: FieldType.number, values: [1, undefined, 2, 3] }],
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], [series])).toEmitValuesWith((received) => {
|
||||||
|
const data = received[0][0];
|
||||||
|
|
||||||
|
expect(data.fields.length).toEqual(2);
|
||||||
|
expect(data.fields[1].values[0]).toEqual(1);
|
||||||
|
expect(data.fields[1].values[1]).toEqual(1);
|
||||||
|
expect(data.fields[1].values[2]).toEqual(3);
|
||||||
|
expect(data.fields[1].values[3]).toEqual(6);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('calculates cumulative total with nulls', async () => {
|
it('calculates cumulative total with nulls', async () => {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
@ -743,6 +769,36 @@ describe('calculateField transformer w/ timeseries', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calculates centered moving average with undefined values', async () => {
|
||||||
|
const cfg = {
|
||||||
|
id: DataTransformerID.calculateField,
|
||||||
|
options: {
|
||||||
|
mode: CalculateFieldMode.WindowFunctions,
|
||||||
|
window: {
|
||||||
|
windowAlignment: WindowAlignment.Centered,
|
||||||
|
field: 'x',
|
||||||
|
windowSize: 0.75,
|
||||||
|
windowSizeMode: WindowSizeMode.Percentage,
|
||||||
|
reducer: ReducerID.mean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const series = toDataFrame({
|
||||||
|
fields: [{ name: 'x', type: FieldType.number, values: [1, undefined, 2, 7] }],
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(transformDataFrame([cfg], [series])).toEmitValuesWith((received) => {
|
||||||
|
const data = received[0][0];
|
||||||
|
|
||||||
|
expect(data.fields.length).toEqual(2);
|
||||||
|
expect(data.fields[1].values[0]).toEqual(1);
|
||||||
|
expect(data.fields[1].values[1]).toEqual(1.5);
|
||||||
|
expect(data.fields[1].values[2]).toEqual(4.5);
|
||||||
|
expect(data.fields[1].values[3]).toEqual(4.5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('calculates centered moving average with nulls', async () => {
|
it('calculates centered moving average with nulls', async () => {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
id: DataTransformerID.calculateField,
|
id: DataTransformerID.calculateField,
|
||||||
|
@ -277,7 +277,7 @@ function getTrailingWindowValues(frame: DataFrame, reducer: ReducerID, selectedF
|
|||||||
for (let i = 0; i < frame.length; i++) {
|
for (let i = 0; i < frame.length; i++) {
|
||||||
if (reducer === ReducerID.mean) {
|
if (reducer === ReducerID.mean) {
|
||||||
const currentValue = selectedField.values[i];
|
const currentValue = selectedField.values[i];
|
||||||
if (currentValue !== null) {
|
if (currentValue !== null && currentValue !== undefined) {
|
||||||
count++;
|
count++;
|
||||||
sum += currentValue;
|
sum += currentValue;
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ function getCenteredWindowValues(frame: DataFrame, reducer: ReducerID, selectedF
|
|||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
// We're at the start and need to prime the leading part of the window
|
// We're at the start and need to prime the leading part of the window
|
||||||
for (let x = 0; x < leadingPartOfWindow + 1 && x < selectedField.values.length; x++) {
|
for (let x = 0; x < leadingPartOfWindow + 1 && x < selectedField.values.length; x++) {
|
||||||
if (selectedField.values[x] !== null) {
|
if (selectedField.values[x] != null) {
|
||||||
sum += selectedField.values[x];
|
sum += selectedField.values[x];
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -323,14 +323,14 @@ function getCenteredWindowValues(frame: DataFrame, reducer: ReducerID, selectedF
|
|||||||
} else {
|
} else {
|
||||||
if (last < selectedField.values.length) {
|
if (last < selectedField.values.length) {
|
||||||
// Last is inside the data and should be added.
|
// Last is inside the data and should be added.
|
||||||
if (selectedField.values[last] !== null) {
|
if (selectedField.values[last] != null) {
|
||||||
sum += selectedField.values[last];
|
sum += selectedField.values[last];
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (first > 0) {
|
if (first > 0) {
|
||||||
// Remove values that have fallen outside of the window, if the start of the window isn't outside of the data.
|
// Remove values that have fallen outside of the window, if the start of the window isn't outside of the data.
|
||||||
if (selectedField.values[first - 1] !== null) {
|
if (selectedField.values[first - 1] != null) {
|
||||||
sum -= selectedField.values[first - 1];
|
sum -= selectedField.values[first - 1];
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
@ -363,7 +363,7 @@ function calculateVariance(vals: number[]): number {
|
|||||||
let nonNullCount = 0;
|
let nonNullCount = 0;
|
||||||
for (let i = 0; i < vals.length; i++) {
|
for (let i = 0; i < vals.length; i++) {
|
||||||
const currentValue = vals[i];
|
const currentValue = vals[i];
|
||||||
if (currentValue !== null) {
|
if (currentValue != null) {
|
||||||
nonNullCount++;
|
nonNullCount++;
|
||||||
let _oldMean = runningMean;
|
let _oldMean = runningMean;
|
||||||
runningMean += (currentValue - _oldMean) / nonNullCount;
|
runningMean += (currentValue - _oldMean) / nonNullCount;
|
||||||
@ -417,7 +417,7 @@ function getCumulativeCreator(options: CumulativeOptions, allFrames: DataFrame[]
|
|||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
for (let i = 0; i < frame.length; i++) {
|
for (let i = 0; i < frame.length; i++) {
|
||||||
total += selectedField.values[i];
|
total += selectedField.values[i] ?? 0;
|
||||||
if (options.reducer === ReducerID.sum) {
|
if (options.reducer === ReducerID.sum) {
|
||||||
vals.push(total);
|
vals.push(total);
|
||||||
} else if (options.reducer === ReducerID.mean) {
|
} else if (options.reducer === ReducerID.mean) {
|
||||||
|
Loading…
Reference in New Issue
Block a user