mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Feature/mathandreduce (#41608)
* Added new math functions: round, ceil, floor * Added a new reduce function: last.
This commit is contained in:
parent
5d0bc9e933
commit
9fc0aee02b
@ -128,6 +128,18 @@ Log returns the natural logarithm of of its argument which can be a number or a
|
|||||||
|
|
||||||
The inf, infn, nan, and null functions all return a single value of the name. They primarily exist for testing. Example: `null()`.
|
The inf, infn, nan, and null functions all return a single value of the name. They primarily exist for testing. Example: `null()`.
|
||||||
|
|
||||||
|
##### round
|
||||||
|
|
||||||
|
Round returns a rounded integer value. For example, `round(3.123)` or `round($A)`. (This function should probably take an argument so it can add precision to the rounded value).
|
||||||
|
|
||||||
|
##### ceil
|
||||||
|
|
||||||
|
Ceil rounds the number up to the nearest integer value. For example, `ceil(3.123)` returns 4.
|
||||||
|
|
||||||
|
##### floor
|
||||||
|
|
||||||
|
Floor rounds the number down to the nearest integer value. For example, `floor(3.123)` returns 3.
|
||||||
|
|
||||||
### Reduce
|
### Reduce
|
||||||
|
|
||||||
Reduce takes one or more time series returned from a query or an expression and turns each series into a single number. The labels of the time series are kept as labels on each outputted reduced number.
|
Reduce takes one or more time series returned from a query or an expression and turns each series into a single number. The labels of the time series are kept as labels on each outputted reduced number.
|
||||||
@ -157,6 +169,10 @@ Min and Max return the smallest or largest value in the series respectively. If
|
|||||||
|
|
||||||
Sum returns the total of all values in the series. If series is of zero length, the sum will be 0. If there are any NaN or Null values in the series, NaN is returned.
|
Sum returns the total of all values in the series. If series is of zero length, the sum will be 0. If there are any NaN or Null values in the series, NaN is returned.
|
||||||
|
|
||||||
|
#### Last
|
||||||
|
|
||||||
|
Last returns the last number in the series. If the series has no values then returns NaN.
|
||||||
|
|
||||||
### Resample
|
### Resample
|
||||||
|
|
||||||
Resample changes the time stamps in each time series to have a consistent time interval. The main use case is so you can resample time series that do not share the same timestamps so math can be performed between them. This can be done by resample each of the two series, and then in a Math operation referencing the resampled variables.
|
Resample changes the time stamps in each time series to have a consistent time interval. The main use case is so you can resample time series that do not share the same timestamps so math can be performed between them. This can be done by resample each of the two series, and then in a Math operation referencing the resampled variables.
|
||||||
|
@ -53,6 +53,21 @@ var builtins = map[string]parse.Func{
|
|||||||
VariantReturn: true,
|
VariantReturn: true,
|
||||||
F: isNumber,
|
F: isNumber,
|
||||||
},
|
},
|
||||||
|
"round": {
|
||||||
|
Args: []parse.ReturnType{parse.TypeVariantSet},
|
||||||
|
VariantReturn: true,
|
||||||
|
F: round,
|
||||||
|
},
|
||||||
|
"ceil": {
|
||||||
|
Args: []parse.ReturnType{parse.TypeVariantSet},
|
||||||
|
VariantReturn: true,
|
||||||
|
F: ceil,
|
||||||
|
},
|
||||||
|
"floor": {
|
||||||
|
Args: []parse.ReturnType{parse.TypeVariantSet},
|
||||||
|
VariantReturn: true,
|
||||||
|
F: floor,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// abs returns the absolute value for each result in NumberSet, SeriesSet, or Scalar
|
// abs returns the absolute value for each result in NumberSet, SeriesSet, or Scalar
|
||||||
@ -253,3 +268,42 @@ func perNullableFloat(e *State, val Value, floatF func(x *float64) *float64) (Va
|
|||||||
|
|
||||||
return newVal, nil
|
return newVal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// round returns the rounded value for each result in NumberSet, SeriesSet, or Scalar
|
||||||
|
func round(e *State, varSet Results) (Results, error) {
|
||||||
|
newRes := Results{}
|
||||||
|
for _, res := range varSet.Values {
|
||||||
|
newVal, err := perFloat(e, res, math.Round)
|
||||||
|
if err != nil {
|
||||||
|
return newRes, err
|
||||||
|
}
|
||||||
|
newRes.Values = append(newRes.Values, newVal)
|
||||||
|
}
|
||||||
|
return newRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ceil returns the rounded up value for each result in NumberSet, SeriesSet, or Scalar
|
||||||
|
func ceil(e *State, varSet Results) (Results, error) {
|
||||||
|
newRes := Results{}
|
||||||
|
for _, res := range varSet.Values {
|
||||||
|
newVal, err := perFloat(e, res, math.Ceil)
|
||||||
|
if err != nil {
|
||||||
|
return newRes, err
|
||||||
|
}
|
||||||
|
newRes.Values = append(newRes.Values, newVal)
|
||||||
|
}
|
||||||
|
return newRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// floor returns the rounded down value for each result in NumberSet, SeriesSet, or Scalar
|
||||||
|
func floor(e *State, varSet Results) (Results, error) {
|
||||||
|
newRes := Results{}
|
||||||
|
for _, res := range varSet.Values {
|
||||||
|
newVal, err := perFloat(e, res, math.Floor)
|
||||||
|
if err != nil {
|
||||||
|
return newRes, err
|
||||||
|
}
|
||||||
|
newRes.Values = append(newRes.Values, newVal)
|
||||||
|
}
|
||||||
|
return newRes, nil
|
||||||
|
}
|
||||||
|
@ -69,6 +69,17 @@ func Count(fv *Float64Field) *float64 {
|
|||||||
return &f
|
return &f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Last(fv *Float64Field) *float64 {
|
||||||
|
var f float64
|
||||||
|
if fv.Len() == 0 {
|
||||||
|
f = math.NaN()
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
v := fv.GetValue(fv.Len() - 1)
|
||||||
|
f = *v
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
// Reduce turns the Series into a Number based on the given reduction function
|
// Reduce turns the Series into a Number based on the given reduction function
|
||||||
func (s Series) Reduce(refID, rFunc string) (Number, error) {
|
func (s Series) Reduce(refID, rFunc string) (Number, error) {
|
||||||
var l data.Labels
|
var l data.Labels
|
||||||
@ -90,6 +101,8 @@ func (s Series) Reduce(refID, rFunc string) (Number, error) {
|
|||||||
f = Max(&floatField)
|
f = Max(&floatField)
|
||||||
case "count":
|
case "count":
|
||||||
f = Count(&floatField)
|
f = Count(&floatField)
|
||||||
|
case "last":
|
||||||
|
f = Last(&floatField)
|
||||||
default:
|
default:
|
||||||
return number, fmt.Errorf("reduction %v not implemented", rFunc)
|
return number, fmt.Errorf("reduction %v not implemented", rFunc)
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,19 @@ func TestSeriesReduce(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "last empty series",
|
||||||
|
red: "last",
|
||||||
|
varToReduce: "A",
|
||||||
|
vars: seriesEmpty,
|
||||||
|
errIs: require.NoError,
|
||||||
|
resultsIs: require.Equal,
|
||||||
|
results: Results{
|
||||||
|
[]Value{
|
||||||
|
makeNumber("", nil, NaN),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -12,7 +12,7 @@ interface Props {
|
|||||||
const mathPlaceholder =
|
const mathPlaceholder =
|
||||||
'Math operations on one more queries, you reference the query by ${refId} ie. $A, $B, $C etc\n' +
|
'Math operations on one more queries, you reference the query by ${refId} ie. $A, $B, $C etc\n' +
|
||||||
'Example: $A + $B\n' +
|
'Example: $A + $B\n' +
|
||||||
'Available functions: abs(), log(), is_number(), is_inf(), is_nan(), is_null()';
|
'Available functions: abs(), log(), is_number(), round(), ceil(), floor(), is_inf(), is_nan(), is_null(), ';
|
||||||
|
|
||||||
export const Math: FC<Props> = ({ labelWidth, onChange, query }) => {
|
export const Math: FC<Props> = ({ labelWidth, onChange, query }) => {
|
||||||
const onExpressionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
const onExpressionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
@ -21,6 +21,7 @@ export const reducerTypes: Array<SelectableValue<string>> = [
|
|||||||
{ value: ReducerID.mean, label: 'Mean', description: 'Get the average value' },
|
{ value: ReducerID.mean, label: 'Mean', description: 'Get the average value' },
|
||||||
{ value: ReducerID.sum, label: 'Sum', description: 'Get the sum of all values' },
|
{ value: ReducerID.sum, label: 'Sum', description: 'Get the sum of all values' },
|
||||||
{ value: ReducerID.count, label: 'Count', description: 'Get the number of values' },
|
{ value: ReducerID.count, label: 'Count', description: 'Get the number of values' },
|
||||||
|
{ value: ReducerID.last, label: 'Last', description: 'Get the last value' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const downsamplingTypes: Array<SelectableValue<string>> = [
|
export const downsamplingTypes: Array<SelectableValue<string>> = [
|
||||||
|
Loading…
Reference in New Issue
Block a user