diff --git a/packages/grafana-data/src/transformations/transformers/calculateField.test.ts b/packages/grafana-data/src/transformations/transformers/calculateField.test.ts index 31518b76b54..a820514c95e 100644 --- a/packages/grafana-data/src/transformations/transformers/calculateField.test.ts +++ b/packages/grafana-data/src/transformations/transformers/calculateField.test.ts @@ -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, diff --git a/packages/grafana-data/src/transformations/transformers/calculateField.ts b/packages/grafana-data/src/transformations/transformers/calculateField.ts index d8a9ca0dff0..e50dc3b268b 100644 --- a/packages/grafana-data/src/transformations/transformers/calculateField.ts +++ b/packages/grafana-data/src/transformations/transformers/calculateField.ts @@ -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) {