mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Refactor: rename statsCalculator to fieldReducer (#16867)
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
|||||||
PanelOptionsGroup,
|
PanelOptionsGroup,
|
||||||
StatsPicker,
|
StatsPicker,
|
||||||
UnitPicker,
|
UnitPicker,
|
||||||
StatID,
|
ReducerID,
|
||||||
SelectOptionItem,
|
SelectOptionItem,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ export class SingleStatValueEditor extends PureComponent<Props> {
|
|||||||
onUnitChange = (unit: SelectOptionItem<string>) => this.props.onChange({ ...this.props.value, unit: unit.value });
|
onUnitChange = (unit: SelectOptionItem<string>) => this.props.onChange({ ...this.props.value, unit: unit.value });
|
||||||
|
|
||||||
onStatsChange = (stats: string[]) => {
|
onStatsChange = (stats: string[]) => {
|
||||||
const stat = stats[0] || StatID.mean;
|
const stat = stats[0] || ReducerID.mean;
|
||||||
this.props.onChange({ ...this.props.value, stat });
|
this.props.onChange({ ...this.props.value, stat });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ export class SingleStatValueEditor extends PureComponent<Props> {
|
|||||||
<StatsPicker
|
<StatsPicker
|
||||||
width={12}
|
width={12}
|
||||||
placeholder="Choose Stat"
|
placeholder="Choose Stat"
|
||||||
defaultStat={StatID.mean}
|
defaultStat={ReducerID.mean}
|
||||||
allowMultiple={false}
|
allowMultiple={false}
|
||||||
stats={[stat]}
|
stats={[stat]}
|
||||||
onChange={this.onStatsChange}
|
onChange={this.onStatsChange}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
SeriesData,
|
SeriesData,
|
||||||
InterpolateFunction,
|
InterpolateFunction,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import { getStatsCalculators, calculateStats } from '../../utils/statsCalculator';
|
import { getFieldReducers, reduceField } from '../../utils/fieldReducer';
|
||||||
import { getDisplayProcessor } from '../../utils/displayValue';
|
import { getDisplayProcessor } from '../../utils/displayValue';
|
||||||
export { SingleStatValueEditor } from './SingleStatValueEditor';
|
export { SingleStatValueEditor } from './SingleStatValueEditor';
|
||||||
|
|
||||||
@@ -66,10 +66,10 @@ export const getSingleStatDisplayValues = (options: GetSingleStatDisplayValueOpt
|
|||||||
|
|
||||||
// Show all fields that are not 'time'
|
// Show all fields that are not 'time'
|
||||||
if (column.type === FieldType.number) {
|
if (column.type === FieldType.number) {
|
||||||
const stats = calculateStats({
|
const stats = reduceField({
|
||||||
series,
|
series,
|
||||||
fieldIndex: i,
|
fieldIndex: i,
|
||||||
stats: [stat], // The stats to calculate
|
reducers: [stat], // The stats to calculate
|
||||||
nullValueMode: NullValueMode.Null,
|
nullValueMode: NullValueMode.Null,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ export const sharedSingleStatMigrationCheck = (panel: PanelModel<SingleStatBaseO
|
|||||||
// avg -> mean, current -> last, total -> sum
|
// avg -> mean, current -> last, total -> sum
|
||||||
const { valueOptions } = options;
|
const { valueOptions } = options;
|
||||||
if (valueOptions && valueOptions.stat) {
|
if (valueOptions && valueOptions.stat) {
|
||||||
valueOptions.stat = getStatsCalculators([valueOptions.stat]).map(s => s.id)[0];
|
valueOptions.stat = getFieldReducers([valueOptions.stat]).map(s => s.id)[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import difference from 'lodash/difference';
|
|||||||
|
|
||||||
import { Select } from '../index';
|
import { Select } from '../index';
|
||||||
|
|
||||||
import { getStatsCalculators } from '../../utils/statsCalculator';
|
import { getFieldReducers } from '../../utils/fieldReducer';
|
||||||
import { SelectOptionItem } from '../Select/Select';
|
import { SelectOptionItem } from '../Select/Select';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -34,7 +34,7 @@ export class StatsPicker extends PureComponent<Props> {
|
|||||||
checkInput = () => {
|
checkInput = () => {
|
||||||
const { stats, allowMultiple, defaultStat, onChange } = this.props;
|
const { stats, allowMultiple, defaultStat, onChange } = this.props;
|
||||||
|
|
||||||
const current = getStatsCalculators(stats);
|
const current = getFieldReducers(stats);
|
||||||
if (current.length !== stats.length) {
|
if (current.length !== stats.length) {
|
||||||
const found = current.map(v => v.id);
|
const found = current.map(v => v.id);
|
||||||
const notFound = difference(stats, found);
|
const notFound = difference(stats, found);
|
||||||
@@ -65,7 +65,7 @@ export class StatsPicker extends PureComponent<Props> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { width, stats, allowMultiple, defaultStat, placeholder } = this.props;
|
const { width, stats, allowMultiple, defaultStat, placeholder } = this.props;
|
||||||
const options = getStatsCalculators().map(s => {
|
const options = getFieldReducers().map(s => {
|
||||||
return {
|
return {
|
||||||
value: s.id,
|
value: s.id,
|
||||||
label: s.name,
|
label: s.name,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getStatsCalculators, StatID, calculateStats } from './statsCalculator';
|
import { getFieldReducers, ReducerID, reduceField } from './fieldReducer';
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
@@ -10,28 +10,28 @@ describe('Stats Calculators', () => {
|
|||||||
|
|
||||||
it('should load all standard stats', () => {
|
it('should load all standard stats', () => {
|
||||||
const names = [
|
const names = [
|
||||||
StatID.sum,
|
ReducerID.sum,
|
||||||
StatID.max,
|
ReducerID.max,
|
||||||
StatID.min,
|
ReducerID.min,
|
||||||
StatID.logmin,
|
ReducerID.logmin,
|
||||||
StatID.mean,
|
ReducerID.mean,
|
||||||
StatID.last,
|
ReducerID.last,
|
||||||
StatID.first,
|
ReducerID.first,
|
||||||
StatID.count,
|
ReducerID.count,
|
||||||
StatID.range,
|
ReducerID.range,
|
||||||
StatID.diff,
|
ReducerID.diff,
|
||||||
StatID.step,
|
ReducerID.step,
|
||||||
StatID.delta,
|
ReducerID.delta,
|
||||||
// StatID.allIsZero,
|
// ReducerID.allIsZero,
|
||||||
// StatID.allIsNull,
|
// ReducerID.allIsNull,
|
||||||
];
|
];
|
||||||
const stats = getStatsCalculators(names);
|
const stats = getFieldReducers(names);
|
||||||
expect(stats.length).toBe(names.length);
|
expect(stats.length).toBe(names.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to load unknown stats', () => {
|
it('should fail to load unknown stats', () => {
|
||||||
const names = ['not a stat', StatID.max, StatID.min, 'also not a stat'];
|
const names = ['not a stat', ReducerID.max, ReducerID.min, 'also not a stat'];
|
||||||
const stats = getStatsCalculators(names);
|
const stats = getFieldReducers(names);
|
||||||
expect(stats.length).toBe(2);
|
expect(stats.length).toBe(2);
|
||||||
|
|
||||||
const found = stats.map(v => v.id);
|
const found = stats.map(v => v.id);
|
||||||
@@ -42,10 +42,10 @@ describe('Stats Calculators', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should calculate basic stats', () => {
|
it('should calculate basic stats', () => {
|
||||||
const stats = calculateStats({
|
const stats = reduceField({
|
||||||
series: basicTable,
|
series: basicTable,
|
||||||
fieldIndex: 0,
|
fieldIndex: 0,
|
||||||
stats: ['first', 'last', 'mean'],
|
reducers: ['first', 'last', 'mean'],
|
||||||
});
|
});
|
||||||
|
|
||||||
// First
|
// First
|
||||||
@@ -59,10 +59,10 @@ describe('Stats Calculators', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should support a single stat also', () => {
|
it('should support a single stat also', () => {
|
||||||
const stats = calculateStats({
|
const stats = reduceField({
|
||||||
series: basicTable,
|
series: basicTable,
|
||||||
fieldIndex: 0,
|
fieldIndex: 0,
|
||||||
stats: ['first'],
|
reducers: ['first'],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Should do the simple version that just looks up value
|
// Should do the simple version that just looks up value
|
||||||
@@ -71,10 +71,10 @@ describe('Stats Calculators', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get non standard stats', () => {
|
it('should get non standard stats', () => {
|
||||||
const stats = calculateStats({
|
const stats = reduceField({
|
||||||
series: basicTable,
|
series: basicTable,
|
||||||
fieldIndex: 0,
|
fieldIndex: 0,
|
||||||
stats: [StatID.distinctCount, StatID.changeCount],
|
reducers: [ReducerID.distinctCount, ReducerID.changeCount],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(stats.distinctCount).toEqual(2);
|
expect(stats.distinctCount).toEqual(2);
|
||||||
@@ -82,10 +82,10 @@ describe('Stats Calculators', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should calculate step', () => {
|
it('should calculate step', () => {
|
||||||
const stats = calculateStats({
|
const stats = reduceField({
|
||||||
series: { fields: [{ name: 'A' }], rows: [[100], [200], [300], [400]] },
|
series: { fields: [{ name: 'A' }], rows: [[100], [200], [300], [400]] },
|
||||||
fieldIndex: 0,
|
fieldIndex: 0,
|
||||||
stats: [StatID.step, StatID.delta],
|
reducers: [ReducerID.step, ReducerID.delta],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(stats.step).toEqual(100);
|
expect(stats.step).toEqual(100);
|
||||||
@@ -3,7 +3,7 @@ import isNumber from 'lodash/isNumber';
|
|||||||
|
|
||||||
import { SeriesData, NullValueMode } from '../types/index';
|
import { SeriesData, NullValueMode } from '../types/index';
|
||||||
|
|
||||||
export enum StatID {
|
export enum ReducerID {
|
||||||
sum = 'sum',
|
sum = 'sum',
|
||||||
max = 'max',
|
max = 'max',
|
||||||
min = 'min',
|
min = 'min',
|
||||||
@@ -24,14 +24,14 @@ export enum StatID {
|
|||||||
allIsNull = 'allIsNull',
|
allIsNull = 'allIsNull',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FieldStats {
|
export interface FieldCalcs {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal function
|
// Internal function
|
||||||
type StatCalculator = (data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean) => FieldStats;
|
type FieldReducer = (data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean) => FieldCalcs;
|
||||||
|
|
||||||
export interface StatCalculatorInfo {
|
export interface FieldReducerInfo {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -40,16 +40,16 @@ export interface StatCalculatorInfo {
|
|||||||
// Internal details
|
// Internal details
|
||||||
emptyInputResult?: any; // typically null, but some things like 'count' & 'sum' should be zero
|
emptyInputResult?: any; // typically null, but some things like 'count' & 'sum' should be zero
|
||||||
standard: boolean; // The most common stats can all be calculated in a single pass
|
standard: boolean; // The most common stats can all be calculated in a single pass
|
||||||
calculator?: StatCalculator;
|
reduce?: FieldReducer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ids list of stat names or null to get all of them
|
* @param ids list of stat names or null to get all of them
|
||||||
*/
|
*/
|
||||||
export function getStatsCalculators(ids?: string[]): StatCalculatorInfo[] {
|
export function getFieldReducers(ids?: string[]): FieldReducerInfo[] {
|
||||||
if (ids === null || ids === undefined) {
|
if (ids === null || ids === undefined) {
|
||||||
if (!hasBuiltIndex) {
|
if (!hasBuiltIndex) {
|
||||||
getById(StatID.mean);
|
getById(ReducerID.mean);
|
||||||
}
|
}
|
||||||
return listOfStats;
|
return listOfStats;
|
||||||
}
|
}
|
||||||
@@ -60,53 +60,53 @@ export function getStatsCalculators(ids?: string[]): StatCalculatorInfo[] {
|
|||||||
list.push(stat);
|
list.push(stat);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}, new Array<StatCalculatorInfo>());
|
}, new Array<FieldReducerInfo>());
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalculateStatsOptions {
|
interface ReduceFieldOptions {
|
||||||
series: SeriesData;
|
series: SeriesData;
|
||||||
fieldIndex: number;
|
fieldIndex: number;
|
||||||
stats: string[]; // The stats to calculate
|
reducers: string[]; // The stats to calculate
|
||||||
nullValueMode?: NullValueMode;
|
nullValueMode?: NullValueMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns an object with a key for each selected stat
|
* @returns an object with a key for each selected stat
|
||||||
*/
|
*/
|
||||||
export function calculateStats(options: CalculateStatsOptions): FieldStats {
|
export function reduceField(options: ReduceFieldOptions): FieldCalcs {
|
||||||
const { series, fieldIndex, stats, nullValueMode } = options;
|
const { series, fieldIndex, reducers, nullValueMode } = options;
|
||||||
|
|
||||||
if (!stats || stats.length < 1) {
|
if (!reducers || reducers.length < 1) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const queue = getStatsCalculators(stats);
|
const queue = getFieldReducers(reducers);
|
||||||
|
|
||||||
// Return early for empty series
|
// Return early for empty series
|
||||||
// This lets the concrete implementations assume at least one row
|
// This lets the concrete implementations assume at least one row
|
||||||
if (!series.rows || series.rows.length < 1) {
|
if (!series.rows || series.rows.length < 1) {
|
||||||
const stats = {} as FieldStats;
|
const calcs = {} as FieldCalcs;
|
||||||
for (const stat of queue) {
|
for (const reducer of queue) {
|
||||||
stats[stat.id] = stat.emptyInputResult !== null ? stat.emptyInputResult : null;
|
calcs[reducer.id] = reducer.emptyInputResult !== null ? reducer.emptyInputResult : null;
|
||||||
}
|
}
|
||||||
return stats;
|
return calcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ignoreNulls = nullValueMode === NullValueMode.Ignore;
|
const ignoreNulls = nullValueMode === NullValueMode.Ignore;
|
||||||
const nullAsZero = nullValueMode === NullValueMode.AsZero;
|
const nullAsZero = nullValueMode === NullValueMode.AsZero;
|
||||||
|
|
||||||
// Avoid calculating all the standard stats if possible
|
// Avoid calculating all the standard stats if possible
|
||||||
if (queue.length === 1 && queue[0].calculator) {
|
if (queue.length === 1 && queue[0].reduce) {
|
||||||
return queue[0].calculator(series, fieldIndex, ignoreNulls, nullAsZero);
|
return queue[0].reduce(series, fieldIndex, ignoreNulls, nullAsZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now everything can use the standard stats
|
// For now everything can use the standard stats
|
||||||
let values = standardStatsStat(series, fieldIndex, ignoreNulls, nullAsZero);
|
let values = doStandardCalcs(series, fieldIndex, ignoreNulls, nullAsZero);
|
||||||
for (const calc of queue) {
|
for (const reducer of queue) {
|
||||||
if (!values.hasOwnProperty(calc.id) && calc.calculator) {
|
if (!values.hasOwnProperty(reducer.id) && reducer.reduce) {
|
||||||
values = {
|
values = {
|
||||||
...values,
|
...values,
|
||||||
...calc.calculator(series, fieldIndex, ignoreNulls, nullAsZero),
|
...reducer.reduce(series, fieldIndex, ignoreNulls, nullAsZero),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,30 +121,30 @@ export function calculateStats(options: CalculateStatsOptions): FieldStats {
|
|||||||
|
|
||||||
// private registry of all stats
|
// private registry of all stats
|
||||||
interface TableStatIndex {
|
interface TableStatIndex {
|
||||||
[id: string]: StatCalculatorInfo;
|
[id: string]: FieldReducerInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const listOfStats: StatCalculatorInfo[] = [];
|
const listOfStats: FieldReducerInfo[] = [];
|
||||||
const index: TableStatIndex = {};
|
const index: TableStatIndex = {};
|
||||||
let hasBuiltIndex = false;
|
let hasBuiltIndex = false;
|
||||||
|
|
||||||
function getById(id: string): StatCalculatorInfo | undefined {
|
function getById(id: string): FieldReducerInfo | undefined {
|
||||||
if (!hasBuiltIndex) {
|
if (!hasBuiltIndex) {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
id: StatID.last,
|
id: ReducerID.last,
|
||||||
name: 'Last',
|
name: 'Last',
|
||||||
description: 'Last Value (current)',
|
description: 'Last Value (current)',
|
||||||
standard: true,
|
standard: true,
|
||||||
alias: 'current',
|
alias: 'current',
|
||||||
calculator: calculateLast,
|
reduce: calculateLast,
|
||||||
},
|
},
|
||||||
{ id: StatID.first, name: 'First', description: 'First Value', standard: true, calculator: calculateFirst },
|
{ id: ReducerID.first, name: 'First', description: 'First Value', standard: true, reduce: calculateFirst },
|
||||||
{ id: StatID.min, name: 'Min', description: 'Minimum Value', standard: true },
|
{ id: ReducerID.min, name: 'Min', description: 'Minimum Value', standard: true },
|
||||||
{ id: StatID.max, name: 'Max', description: 'Maximum Value', standard: true },
|
{ id: ReducerID.max, name: 'Max', description: 'Maximum Value', standard: true },
|
||||||
{ id: StatID.mean, name: 'Mean', description: 'Average Value', standard: true, alias: 'avg' },
|
{ id: ReducerID.mean, name: 'Mean', description: 'Average Value', standard: true, alias: 'avg' },
|
||||||
{
|
{
|
||||||
id: StatID.sum,
|
id: ReducerID.sum,
|
||||||
name: 'Total',
|
name: 'Total',
|
||||||
description: 'The sum of all values',
|
description: 'The sum of all values',
|
||||||
emptyInputResult: 0,
|
emptyInputResult: 0,
|
||||||
@@ -152,55 +152,55 @@ function getById(id: string): StatCalculatorInfo | undefined {
|
|||||||
alias: 'total',
|
alias: 'total',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.count,
|
id: ReducerID.count,
|
||||||
name: 'Count',
|
name: 'Count',
|
||||||
description: 'Number of values in response',
|
description: 'Number of values in response',
|
||||||
emptyInputResult: 0,
|
emptyInputResult: 0,
|
||||||
standard: true,
|
standard: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.range,
|
id: ReducerID.range,
|
||||||
name: 'Range',
|
name: 'Range',
|
||||||
description: 'Difference between minimum and maximum values',
|
description: 'Difference between minimum and maximum values',
|
||||||
standard: true,
|
standard: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.delta,
|
id: ReducerID.delta,
|
||||||
name: 'Delta',
|
name: 'Delta',
|
||||||
description: 'Cumulative change in value',
|
description: 'Cumulative change in value',
|
||||||
standard: true,
|
standard: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.step,
|
id: ReducerID.step,
|
||||||
name: 'Step',
|
name: 'Step',
|
||||||
description: 'Minimum interval between values',
|
description: 'Minimum interval between values',
|
||||||
standard: true,
|
standard: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.diff,
|
id: ReducerID.diff,
|
||||||
name: 'Difference',
|
name: 'Difference',
|
||||||
description: 'Difference between first and last values',
|
description: 'Difference between first and last values',
|
||||||
standard: true,
|
standard: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.logmin,
|
id: ReducerID.logmin,
|
||||||
name: 'Min (above zero)',
|
name: 'Min (above zero)',
|
||||||
description: 'Used for log min scale',
|
description: 'Used for log min scale',
|
||||||
standard: true,
|
standard: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.changeCount,
|
id: ReducerID.changeCount,
|
||||||
name: 'Change Count',
|
name: 'Change Count',
|
||||||
description: 'Number of times the value changes',
|
description: 'Number of times the value changes',
|
||||||
standard: false,
|
standard: false,
|
||||||
calculator: calculateChangeCount,
|
reduce: calculateChangeCount,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: StatID.distinctCount,
|
id: ReducerID.distinctCount,
|
||||||
name: 'Distinct Count',
|
name: 'Distinct Count',
|
||||||
description: 'Number of distinct values',
|
description: 'Number of distinct values',
|
||||||
standard: false,
|
standard: false,
|
||||||
calculator: calculateDistinctCount,
|
reduce: calculateDistinctCount,
|
||||||
},
|
},
|
||||||
].forEach(info => {
|
].forEach(info => {
|
||||||
const { id, alias } = info;
|
const { id, alias } = info;
|
||||||
@@ -222,13 +222,8 @@ function getById(id: string): StatCalculatorInfo | undefined {
|
|||||||
return index[id];
|
return index[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
function standardStatsStat(
|
function doStandardCalcs(data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||||
data: SeriesData,
|
const calcs = {
|
||||||
fieldIndex: number,
|
|
||||||
ignoreNulls: boolean,
|
|
||||||
nullAsZero: boolean
|
|
||||||
): FieldStats {
|
|
||||||
const stats = {
|
|
||||||
sum: 0,
|
sum: 0,
|
||||||
max: -Number.MAX_VALUE,
|
max: -Number.MAX_VALUE,
|
||||||
min: Number.MAX_VALUE,
|
min: Number.MAX_VALUE,
|
||||||
@@ -247,7 +242,7 @@ function standardStatsStat(
|
|||||||
|
|
||||||
// Just used for calcutations -- not exposed as a stat
|
// Just used for calcutations -- not exposed as a stat
|
||||||
previousDeltaUp: true,
|
previousDeltaUp: true,
|
||||||
} as FieldStats;
|
} as FieldCalcs;
|
||||||
|
|
||||||
for (let i = 0; i < data.rows.length; i++) {
|
for (let i = 0; i < data.rows.length; i++) {
|
||||||
let currentValue = data.rows[i][fieldIndex];
|
let currentValue = data.rows[i][fieldIndex];
|
||||||
@@ -262,94 +257,94 @@ function standardStatsStat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentValue !== null) {
|
if (currentValue !== null) {
|
||||||
const isFirst = stats.first === null;
|
const isFirst = calcs.first === null;
|
||||||
if (isFirst) {
|
if (isFirst) {
|
||||||
stats.first = currentValue;
|
calcs.first = currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNumber(currentValue)) {
|
if (isNumber(currentValue)) {
|
||||||
stats.sum += currentValue;
|
calcs.sum += currentValue;
|
||||||
stats.allIsNull = false;
|
calcs.allIsNull = false;
|
||||||
stats.nonNullCount++;
|
calcs.nonNullCount++;
|
||||||
|
|
||||||
if (!isFirst) {
|
if (!isFirst) {
|
||||||
const step = currentValue - stats.last!;
|
const step = currentValue - calcs.last!;
|
||||||
if (stats.step > step) {
|
if (calcs.step > step) {
|
||||||
stats.step = step; // the minimum interval
|
calcs.step = step; // the minimum interval
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.last! > currentValue) {
|
if (calcs.last! > currentValue) {
|
||||||
// counter reset
|
// counter reset
|
||||||
stats.previousDeltaUp = false;
|
calcs.previousDeltaUp = false;
|
||||||
if (i === data.rows.length - 1) {
|
if (i === data.rows.length - 1) {
|
||||||
// reset on last
|
// reset on last
|
||||||
stats.delta += currentValue;
|
calcs.delta += currentValue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (stats.previousDeltaUp) {
|
if (calcs.previousDeltaUp) {
|
||||||
stats.delta += step; // normal increment
|
calcs.delta += step; // normal increment
|
||||||
} else {
|
} else {
|
||||||
stats.delta += currentValue; // account for counter reset
|
calcs.delta += currentValue; // account for counter reset
|
||||||
}
|
}
|
||||||
stats.previousDeltaUp = true;
|
calcs.previousDeltaUp = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentValue > stats.max) {
|
if (currentValue > calcs.max) {
|
||||||
stats.max = currentValue;
|
calcs.max = currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentValue < stats.min) {
|
if (currentValue < calcs.min) {
|
||||||
stats.min = currentValue;
|
calcs.min = currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentValue < stats.logmin && currentValue > 0) {
|
if (currentValue < calcs.logmin && currentValue > 0) {
|
||||||
stats.logmin = currentValue;
|
calcs.logmin = currentValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentValue !== 0) {
|
if (currentValue !== 0) {
|
||||||
stats.allIsZero = false;
|
calcs.allIsZero = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.last = currentValue;
|
calcs.last = currentValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.max === -Number.MAX_VALUE) {
|
if (calcs.max === -Number.MAX_VALUE) {
|
||||||
stats.max = null;
|
calcs.max = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.min === Number.MAX_VALUE) {
|
if (calcs.min === Number.MAX_VALUE) {
|
||||||
stats.min = null;
|
calcs.min = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.step === Number.MAX_VALUE) {
|
if (calcs.step === Number.MAX_VALUE) {
|
||||||
stats.step = null;
|
calcs.step = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.nonNullCount > 0) {
|
if (calcs.nonNullCount > 0) {
|
||||||
stats.mean = stats.sum! / stats.nonNullCount;
|
calcs.mean = calcs.sum! / calcs.nonNullCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.max !== null && stats.min !== null) {
|
if (calcs.max !== null && calcs.min !== null) {
|
||||||
stats.range = stats.max - stats.min;
|
calcs.range = calcs.max - calcs.min;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.first !== null && stats.last !== null) {
|
if (calcs.first !== null && calcs.last !== null) {
|
||||||
if (isNumber(stats.first) && isNumber(stats.last)) {
|
if (isNumber(calcs.first) && isNumber(calcs.last)) {
|
||||||
stats.diff = stats.last - stats.first;
|
calcs.diff = calcs.last - calcs.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stats;
|
return calcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateFirst(data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean): FieldStats {
|
function calculateFirst(data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||||
return { first: data.rows[0][fieldIndex] };
|
return { first: data.rows[0][fieldIndex] };
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateLast(data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean): FieldStats {
|
function calculateLast(data: SeriesData, fieldIndex: number, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||||
return { last: data.rows[data.rows.length - 1][fieldIndex] };
|
return { last: data.rows[data.rows.length - 1][fieldIndex] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +353,7 @@ function calculateChangeCount(
|
|||||||
fieldIndex: number,
|
fieldIndex: number,
|
||||||
ignoreNulls: boolean,
|
ignoreNulls: boolean,
|
||||||
nullAsZero: boolean
|
nullAsZero: boolean
|
||||||
): FieldStats {
|
): FieldCalcs {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
let first = true;
|
let first = true;
|
||||||
let last: any = null;
|
let last: any = null;
|
||||||
@@ -387,7 +382,7 @@ function calculateDistinctCount(
|
|||||||
fieldIndex: number,
|
fieldIndex: number,
|
||||||
ignoreNulls: boolean,
|
ignoreNulls: boolean,
|
||||||
nullAsZero: boolean
|
nullAsZero: boolean
|
||||||
): FieldStats {
|
): FieldCalcs {
|
||||||
const distinct = new Set<any>();
|
const distinct = new Set<any>();
|
||||||
for (let i = 0; i < data.rows.length; i++) {
|
for (let i = 0; i < data.rows.length; i++) {
|
||||||
let currentValue = data.rows[i][fieldIndex];
|
let currentValue = data.rows[i][fieldIndex];
|
||||||
@@ -5,7 +5,7 @@ export * from './namedColorsPalette';
|
|||||||
export * from './thresholds';
|
export * from './thresholds';
|
||||||
export * from './string';
|
export * from './string';
|
||||||
export * from './csv';
|
export * from './csv';
|
||||||
export * from './statsCalculator';
|
export * from './fieldReducer';
|
||||||
export * from './displayValue';
|
export * from './displayValue';
|
||||||
export * from './deprecationWarning';
|
export * from './deprecationWarning';
|
||||||
export * from './logs';
|
export * from './logs';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { VizOrientation, SelectOptionItem, StatID, SingleStatBaseOptions } from '@grafana/ui';
|
import { VizOrientation, SelectOptionItem, ReducerID, SingleStatBaseOptions } from '@grafana/ui';
|
||||||
|
|
||||||
export interface BarGaugeOptions extends SingleStatBaseOptions {
|
export interface BarGaugeOptions extends SingleStatBaseOptions {
|
||||||
minValue: number;
|
minValue: number;
|
||||||
@@ -24,7 +24,7 @@ export const defaults: BarGaugeOptions = {
|
|||||||
orientation: VizOrientation.Horizontal,
|
orientation: VizOrientation.Horizontal,
|
||||||
valueOptions: {
|
valueOptions: {
|
||||||
unit: 'none',
|
unit: 'none',
|
||||||
stat: StatID.mean,
|
stat: ReducerID.mean,
|
||||||
prefix: '',
|
prefix: '',
|
||||||
suffix: '',
|
suffix: '',
|
||||||
decimals: null,
|
decimals: null,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { VizOrientation, StatID, SingleStatBaseOptions } from '@grafana/ui';
|
import { VizOrientation, ReducerID, SingleStatBaseOptions } from '@grafana/ui';
|
||||||
|
|
||||||
export interface GaugeOptions extends SingleStatBaseOptions {
|
export interface GaugeOptions extends SingleStatBaseOptions {
|
||||||
maxValue: number;
|
maxValue: number;
|
||||||
@@ -16,7 +16,7 @@ export const defaults: GaugeOptions = {
|
|||||||
prefix: '',
|
prefix: '',
|
||||||
suffix: '',
|
suffix: '',
|
||||||
decimals: null,
|
decimals: null,
|
||||||
stat: StatID.mean,
|
stat: ReducerID.mean,
|
||||||
unit: 'none',
|
unit: 'none',
|
||||||
},
|
},
|
||||||
valueMappings: [],
|
valueMappings: [],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
GraphSeriesXY,
|
GraphSeriesXY,
|
||||||
NullValueMode,
|
NullValueMode,
|
||||||
calculateStats,
|
reduceField,
|
||||||
colors,
|
colors,
|
||||||
getFlotPairs,
|
getFlotPairs,
|
||||||
getColorFromHexRgbOrName,
|
getColorFromHexRgbOrName,
|
||||||
@@ -45,8 +45,12 @@ export const getGraphSeriesModel = (
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (points.length > 0) {
|
if (points.length > 0) {
|
||||||
const seriesStats = calculateStats({ series, stats: legendOptions.stats, fieldIndex: field.index });
|
const seriesStats = reduceField({
|
||||||
let statsDisplayValues;
|
series,
|
||||||
|
reducers: legendOptions.stats,
|
||||||
|
fieldIndex: field.index,
|
||||||
|
});
|
||||||
|
let statsDisplayValues: DisplayValue[];
|
||||||
|
|
||||||
if (legendOptions.stats) {
|
if (legendOptions.stats) {
|
||||||
statsDisplayValues = legendOptions.stats.map<DisplayValue>(stat => {
|
statsDisplayValues = legendOptions.stats.map<DisplayValue>(stat => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PieChartType, StatID, VizOrientation, SingleStatBaseOptions } from '@grafana/ui';
|
import { PieChartType, ReducerID, VizOrientation, SingleStatBaseOptions } from '@grafana/ui';
|
||||||
|
|
||||||
export interface PieChartOptions extends SingleStatBaseOptions {
|
export interface PieChartOptions extends SingleStatBaseOptions {
|
||||||
pieType: PieChartType;
|
pieType: PieChartType;
|
||||||
@@ -10,7 +10,7 @@ export const defaults: PieChartOptions = {
|
|||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
valueOptions: {
|
valueOptions: {
|
||||||
unit: 'short',
|
unit: 'short',
|
||||||
stat: StatID.last,
|
stat: ReducerID.last,
|
||||||
suffix: '',
|
suffix: '',
|
||||||
prefix: '',
|
prefix: '',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
PanelProps,
|
PanelProps,
|
||||||
getDisplayProcessor,
|
getDisplayProcessor,
|
||||||
NullValueMode,
|
NullValueMode,
|
||||||
calculateStats,
|
reduceField,
|
||||||
FieldCache,
|
FieldCache,
|
||||||
FieldType,
|
FieldType,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
@@ -57,10 +57,10 @@ export class SingleStatPanel extends PureComponent<PanelProps<SingleStatOptions>
|
|||||||
|
|
||||||
for (let i = 0; i < numberFields.length; i++) {
|
for (let i = 0; i < numberFields.length; i++) {
|
||||||
const field = numberFields[i];
|
const field = numberFields[i];
|
||||||
const stats = calculateStats({
|
const stats = reduceField({
|
||||||
series,
|
series,
|
||||||
fieldIndex: field.index,
|
fieldIndex: field.index,
|
||||||
stats: [stat], // The stats to calculate
|
reducers: [stat], // The stats to calculate
|
||||||
nullValueMode: NullValueMode.Null,
|
nullValueMode: NullValueMode.Null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { VizOrientation, StatID, SingleStatBaseOptions } from '@grafana/ui';
|
import { VizOrientation, ReducerID, SingleStatBaseOptions } from '@grafana/ui';
|
||||||
|
|
||||||
export interface SparklineOptions {
|
export interface SparklineOptions {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
@@ -33,7 +33,7 @@ export const defaults: SingleStatOptions = {
|
|||||||
prefix: '',
|
prefix: '',
|
||||||
suffix: '',
|
suffix: '',
|
||||||
decimals: null,
|
decimals: null,
|
||||||
stat: StatID.mean,
|
stat: ReducerID.mean,
|
||||||
unit: 'none',
|
unit: 'none',
|
||||||
},
|
},
|
||||||
valueMappings: [],
|
valueMappings: [],
|
||||||
|
|||||||
Reference in New Issue
Block a user