mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
FieldReducers: Fix median (#98184)
Co-authored-by: Kristina Durivage <kristina.durivage@grafana.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
@@ -254,6 +254,29 @@ describe('Stats Calculators', () => {
|
||||
expect(reduce(someNulls, ReducerID.count)).toEqual(4);
|
||||
});
|
||||
|
||||
it('median should ignoreNulls by default', () => {
|
||||
const someNulls = createField('y', [3, null, 2, 1, 4]);
|
||||
expect(reduce(someNulls, ReducerID.median)).toEqual(2.5);
|
||||
});
|
||||
|
||||
it('median should use fieldConfig nullValueMode.Ignore and not count nulls', () => {
|
||||
const someNulls = createField('y', [3, null, 2, 1, 4]);
|
||||
someNulls.config.nullValueMode = NullValueMode.Ignore;
|
||||
expect(reduce(someNulls, ReducerID.median)).toEqual(2.5);
|
||||
});
|
||||
|
||||
it('median should use fieldConfig nullValueMode.Null and count nulls', () => {
|
||||
const someNulls = createField('y', [3, null, 2, 1, 4]);
|
||||
someNulls.config.nullValueMode = NullValueMode.Null;
|
||||
expect(reduce(someNulls, ReducerID.median)).toEqual(2);
|
||||
});
|
||||
|
||||
it('median should use fieldConfig nullValueMode.AsZero and count nulls as zero', () => {
|
||||
const someNulls = createField('y', [3, null, 2, 1, 4]);
|
||||
someNulls.config.nullValueMode = NullValueMode.AsZero;
|
||||
expect(reduce(someNulls, ReducerID.median)).toEqual(2);
|
||||
});
|
||||
|
||||
it('can reduce to percentiles', () => {
|
||||
// This `Array.from` will build an array of elements from 1 to 99
|
||||
const percentiles = [...Array.from({ length: 99 }, (_, i) => i + 1)];
|
||||
|
||||
@@ -283,7 +283,8 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
|
||||
id: ReducerID.median,
|
||||
name: 'Median',
|
||||
description: 'Median Value',
|
||||
standard: true,
|
||||
standard: false,
|
||||
reduce: calculateMedian,
|
||||
aliasIds: ['median'],
|
||||
preservesUnits: true,
|
||||
},
|
||||
@@ -584,6 +585,7 @@ export function doStandardCalcs(field: Field, ignoreNulls: boolean, nullAsZero:
|
||||
if (isNumber(calcs.firstNotNull) && isNumber(calcs.diff)) {
|
||||
calcs.diffperc = (calcs.diff / calcs.firstNotNull) * 100;
|
||||
}
|
||||
|
||||
return calcs;
|
||||
}
|
||||
|
||||
@@ -703,3 +705,32 @@ function calculatePercentile(field: Field, percentile: number, ignoreNulls: bool
|
||||
const index = Math.round((sorted.length - 1) * percentile);
|
||||
return sorted[index];
|
||||
}
|
||||
|
||||
function calculateMedian(field: Field<number>, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||
const numbers: number[] = [];
|
||||
|
||||
for (let i = 0; i < field.values.length; i++) {
|
||||
let currentValue = field.values[i];
|
||||
|
||||
if (currentValue == null) {
|
||||
if (ignoreNulls) {
|
||||
continue;
|
||||
}
|
||||
if (nullAsZero) {
|
||||
currentValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
numbers.push(currentValue);
|
||||
}
|
||||
|
||||
numbers.sort((a, b) => a - b);
|
||||
|
||||
const mid = Math.floor(numbers.length / 2);
|
||||
|
||||
if (numbers.length % 2 === 0) {
|
||||
return { median: (numbers[mid - 1] + numbers[mid]) / 2 };
|
||||
} else {
|
||||
return { median: numbers[mid] };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user