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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user