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);
|
||||
});
|
||||
});
|
||||
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 () => {
|
||||
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 () => {
|
||||
const cfg = {
|
||||
id: DataTransformerID.calculateField,
|
||||
|
@ -277,7 +277,7 @@ function getTrailingWindowValues(frame: DataFrame, reducer: ReducerID, selectedF
|
||||
for (let i = 0; i < frame.length; i++) {
|
||||
if (reducer === ReducerID.mean) {
|
||||
const currentValue = selectedField.values[i];
|
||||
if (currentValue !== null) {
|
||||
if (currentValue !== null && currentValue !== undefined) {
|
||||
count++;
|
||||
sum += currentValue;
|
||||
|
||||
@ -315,7 +315,7 @@ function getCenteredWindowValues(frame: DataFrame, reducer: ReducerID, selectedF
|
||||
if (i === 0) {
|
||||
// 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++) {
|
||||
if (selectedField.values[x] !== null) {
|
||||
if (selectedField.values[x] != null) {
|
||||
sum += selectedField.values[x];
|
||||
count++;
|
||||
}
|
||||
@ -323,14 +323,14 @@ function getCenteredWindowValues(frame: DataFrame, reducer: ReducerID, selectedF
|
||||
} else {
|
||||
if (last < selectedField.values.length) {
|
||||
// Last is inside the data and should be added.
|
||||
if (selectedField.values[last] !== null) {
|
||||
if (selectedField.values[last] != null) {
|
||||
sum += selectedField.values[last];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (first > 0) {
|
||||
// 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];
|
||||
count--;
|
||||
}
|
||||
@ -363,7 +363,7 @@ function calculateVariance(vals: number[]): number {
|
||||
let nonNullCount = 0;
|
||||
for (let i = 0; i < vals.length; i++) {
|
||||
const currentValue = vals[i];
|
||||
if (currentValue !== null) {
|
||||
if (currentValue != null) {
|
||||
nonNullCount++;
|
||||
let _oldMean = runningMean;
|
||||
runningMean += (currentValue - _oldMean) / nonNullCount;
|
||||
@ -417,7 +417,7 @@ function getCumulativeCreator(options: CumulativeOptions, allFrames: DataFrame[]
|
||||
|
||||
let total = 0;
|
||||
for (let i = 0; i < frame.length; i++) {
|
||||
total += selectedField.values[i];
|
||||
total += selectedField.values[i] ?? 0;
|
||||
if (options.reducer === ReducerID.sum) {
|
||||
vals.push(total);
|
||||
} else if (options.reducer === ReducerID.mean) {
|
||||
|
Loading…
Reference in New Issue
Block a user