Transformations: Show row index as percent in 'Add field from calculation' (#74322)

* show row index as percentage in add field from calc transform

* prettier

* add test + modify docs

* show quantile and add percentage unit default. add explanatory tooltip and docs

* fix test

* set unit percent only on quantile mode

* Change naming to percentile

* Rename to As Percentile

* docs mods
This commit is contained in:
Victor Marin
2023-09-25 18:34:42 +03:00
committed by GitHub
parent d15661c726
commit 13db9066a3
4 changed files with 73 additions and 3 deletions
@@ -109,10 +109,11 @@ Use this transformation to add a new field calculated from two other fields. Eac
- **Mode -** Select a mode:
- **Reduce row -** Apply selected calculation on each row of selected fields independently.
- **Binary option -** Apply basic math operation(sum, multiply, etc) on values in a single row from two selected fields.
- **Index -** Will insert a field with the row index.
- **Row index -** Insert a field with the row index.
- **Field name -** Select the names of fields you want to use in the calculation for the new field.
- **Calculation -** If you select **Reduce row** mode, then the **Calculation** field appears. Click in the field to see a list of calculation choices you can use to create the new field. For information about available calculations, refer to [Calculation types][].
- **Operation -** If you select **Binary option** mode, then the **Operation** fields appear. These fields allow you to do basic math operations on values in a single row from two selected fields. You can also use numerical values for binary operations.
- **As percentile -** If you select **Row index** mode, then the **As percentile** switch appears. This switch allows you to transform the row index as a percentage of the total number of rows.
- **Alias -** (Optional) Enter the name of your new field. If you leave this blank, then the field will be named to match the calculation.
- **Replace all fields -** (Optional) Select this option if you want to hide all other fields and display only your calculated field in the visualization.
@@ -238,6 +238,34 @@ describe('calculateField transformer w/ timeseries', () => {
});
});
it('can add percentage index field', async () => {
const cfg = {
id: DataTransformerID.calculateField,
options: {
mode: CalculateFieldMode.Index,
replaceFields: true,
index: {
asPercentile: true,
},
},
};
const series = toDataFrame({
fields: [
{ name: 'TheTime', type: FieldType.time, values: [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000] },
{ name: 'Field', type: FieldType.number, values: [2, 200, 3, 6, 3, 7, 9, 9] },
],
});
await expect(transformDataFrame([cfg], [series])).toEmitValuesWith((received) => {
const data = received[0][0];
expect(data.fields.length).toEqual(1);
expect(data.fields[0].values[2]).toEqual(0.25);
expect(data.fields[0].values[4]).toEqual(0.5);
expect(data.fields[0].values[6]).toEqual(0.75);
});
});
it('uses template variable substituion', async () => {
const cfg = {
id: DataTransformerID.calculateField,
@@ -31,6 +31,10 @@ export interface BinaryOptions {
right: string;
}
export interface IndexOptions {
asPercentile: boolean;
}
const defaultReduceOptions: ReduceOptions = {
reducer: ReducerID.sum,
};
@@ -49,6 +53,7 @@ export interface CalculateFieldTransformerOptions {
// Only one should be filled
reduce?: ReduceOptions;
binary?: BinaryOptions;
index?: IndexOptions;
// Remove other fields
replaceFields?: boolean;
@@ -98,11 +103,19 @@ export const calculateFieldTransformer: DataTransformerInfo<CalculateFieldTransf
creator = getBinaryCreator(defaults(binaryOptions, defaultBinaryOptions), data);
} else if (mode === CalculateFieldMode.Index) {
return data.map((frame) => {
const indexArr = [...Array(frame.length).keys()];
if (options.index?.asPercentile) {
for (let i = 0; i < indexArr.length; i++) {
indexArr[i] = indexArr[i] / indexArr.length;
}
}
const f = {
name: options.alias ?? 'Row',
type: FieldType.number,
values: [...Array(frame.length).keys()],
config: {},
values: indexArr,
config: options.index?.asPercentile ? { unit: 'percentunit' } : {},
};
return {
...frame,
@@ -23,6 +23,7 @@ import {
CalculateFieldMode,
CalculateFieldTransformerOptions,
getNameFromOptions,
IndexOptions,
ReduceOptions,
} from '@grafana/data/src/transformations/transformers/calculateField';
import { FilterPill, HorizontalGroup, Input, LegacyForms, Select, StatsPicker } from '@grafana/ui';
@@ -142,6 +143,16 @@ export class CalculateFieldTransformerEditor extends React.PureComponent<
});
};
onToggleRowIndexAsPercentile = () => {
const { options } = this.props;
this.props.onChange({
...options,
index: {
asPercentile: !options.index?.asPercentile ?? false,
},
});
};
onModeChanged = (value: SelectableValue<CalculateFieldMode>) => {
const { options, onChange } = this.props;
const mode = value.value ?? CalculateFieldMode.BinaryOperation;
@@ -197,6 +208,22 @@ export class CalculateFieldTransformerEditor extends React.PureComponent<
this.updateReduceOptions({ ...reduce, reducer });
};
renderRowIndex(options?: IndexOptions) {
return (
<>
<div className="gf-form-inline">
<LegacyForms.Switch
label="As percentile"
tooltip="Transform the row index as a percentile."
labelClass="width-8"
checked={!!options?.asPercentile}
onChange={this.onToggleRowIndexAsPercentile}
/>
</div>
</>
);
}
renderReduceRow(options?: ReduceOptions) {
const { names, selected } = this.state;
options = defaults(options, { reducer: ReducerID.sum });
@@ -353,6 +380,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent<
</div>
{mode === CalculateFieldMode.BinaryOperation && this.renderBinaryOperation(options.binary)}
{mode === CalculateFieldMode.ReduceRow && this.renderReduceRow(options.reduce)}
{mode === CalculateFieldMode.Index && this.renderRowIndex(options.index)}
<div className="gf-form-inline">
<div className="gf-form">
<div className="gf-form-label width-8">Alias</div>