From 7ea31b5173ab6f1d9089bb3b50d209a5020d3bed Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Thu, 26 Jan 2023 12:02:22 +0200 Subject: [PATCH] [v9.3.x] Fix Barchart legend calcs when stacking is percent (#62176) Fix Barchart legend calcs when stacking is percent (#61449) * Fix Barchart legend calcs when stacking is percent * doc change * Refactor + tests (cherry picked from commit ab7a4e5f2809d9fa8af4d4da36e9771ab5da0276) --- .../plugins/panel/barchart/BarChartPanel.tsx | 2 +- public/app/plugins/panel/barchart/types.ts | 6 +++ .../app/plugins/panel/barchart/utils.test.ts | 47 ++++++++++++++++++- public/app/plugins/panel/barchart/utils.ts | 25 ++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/panel/barchart/BarChartPanel.tsx b/public/app/plugins/panel/barchart/BarChartPanel.tsx index bff59f36723..e2ef898e020 100644 --- a/public/app/plugins/panel/barchart/BarChartPanel.tsx +++ b/public/app/plugins/panel/barchart/BarChartPanel.tsx @@ -218,7 +218,7 @@ export const BarChartPanel: React.FunctionComponent = ({ } } - return ; + return ; }; const rawValue = (seriesIdx: number, valueIdx: number) => { diff --git a/public/app/plugins/panel/barchart/types.ts b/public/app/plugins/panel/barchart/types.ts index f694f369a19..347ae56edc0 100644 --- a/public/app/plugins/panel/barchart/types.ts +++ b/public/app/plugins/panel/barchart/types.ts @@ -10,6 +10,12 @@ export interface BarChartDisplayValues { */ viz: [DataFrame]; + /** + * The fields we can display, first field is X axis. + * Contains same data as viz, but without config modifications (e.g: unit override) + */ + legend: DataFrame; + /** Potentialy color by a field value */ colorByField?: Field; } diff --git a/public/app/plugins/panel/barchart/utils.test.ts b/public/app/plugins/panel/barchart/utils.test.ts index 8590256f7f1..ff029ba875c 100644 --- a/public/app/plugins/panel/barchart/utils.test.ts +++ b/public/app/plugins/panel/barchart/utils.test.ts @@ -19,7 +19,7 @@ import { SortOrder, } from '@grafana/schema'; -import { PanelFieldConfig } from './models.gen'; +import { PanelFieldConfig, PanelOptions } from './models.gen'; import { BarChartOptionsEX, prepareBarChartDisplayValues, preparePlotConfigBuilder } from './utils'; function mockDataFrame() { @@ -202,6 +202,19 @@ describe('BarChart utils', () => { const field = displayValues.viz[0].fields[1]; expect(field.values.toArray()).toMatchInlineSnapshot(` + Array [ + -10, + null, + 10, + null, + null, + ] + `); + + const displayLegendValuesAsc = assertIsDefined('legend' in result ? result : null).legend; + const legendField = displayLegendValuesAsc.fields[1]; + + expect(legendField.values.toArray()).toMatchInlineSnapshot(` Array [ -10, null, @@ -231,6 +244,12 @@ describe('BarChart utils', () => { expect(displayValuesAsc.fields[2].name).toBe('c'); expect(displayValuesAsc.fields[3].name).toBe('b'); + const displayLegendValuesAsc = assertIsDefined('legend' in resultAsc ? resultAsc : null).legend; + expect(displayLegendValuesAsc.fields[0].type).toBe(FieldType.string); + expect(displayLegendValuesAsc.fields[1].name).toBe('a'); + expect(displayLegendValuesAsc.fields[2].name).toBe('c'); + expect(displayLegendValuesAsc.fields[3].name).toBe('b'); + const resultDesc = prepareBarChartDisplayValues([frame], createTheme(), { legend: { sortBy: 'Min', sortDesc: true }, } as any); @@ -239,6 +258,32 @@ describe('BarChart utils', () => { expect(displayValuesDesc.fields[1].name).toBe('b'); expect(displayValuesDesc.fields[2].name).toBe('c'); expect(displayValuesDesc.fields[3].name).toBe('a'); + + const displayLegendValuesDesc = assertIsDefined('legend' in resultDesc ? resultDesc : null).legend; + expect(displayLegendValuesDesc.fields[0].type).toBe(FieldType.string); + expect(displayLegendValuesDesc.fields[1].name).toBe('b'); + expect(displayLegendValuesDesc.fields[2].name).toBe('c'); + expect(displayLegendValuesDesc.fields[3].name).toBe('a'); + }); + + it('should remove unit from legend values when stacking is percent', () => { + const frame = new MutableDataFrame({ + fields: [ + { name: 'string', type: FieldType.string, values: ['a', 'b', 'c'] }, + { name: 'a', values: [-10, 20, 10], state: { calcs: { min: -10 } } }, + { name: 'b', values: [20, 20, 20], state: { calcs: { min: 20 } } }, + { name: 'c', values: [10, 10, 10], state: { calcs: { min: 10 } } }, + ], + }); + + const resultAsc = prepareBarChartDisplayValues([frame], createTheme(), { + stacking: StackingMode.Percent, + } as PanelOptions); + const displayLegendValuesAsc = assertIsDefined('legend' in resultAsc ? resultAsc : null).legend; + + expect(displayLegendValuesAsc.fields[1].config.unit).toBeUndefined(); + expect(displayLegendValuesAsc.fields[2].config.unit).toBeUndefined(); + expect(displayLegendValuesAsc.fields[3].config.unit).toBeUndefined(); }); }); }); diff --git a/public/app/plugins/panel/barchart/utils.ts b/public/app/plugins/panel/barchart/utils.ts index 0e4d3b8b529..d25e23b4039 100644 --- a/public/app/plugins/panel/barchart/utils.ts +++ b/public/app/plugins/panel/barchart/utils.ts @@ -464,6 +464,27 @@ export function prepareBarChartDisplayValues( ); } + let legendFields: Field[] = fields; + if (options.stacking === StackingMode.Percent) { + legendFields = fields.map((field) => { + const alignedFrameField = frame.fields.find((f) => f.name === field.name)!; + + const copy = { + ...field, + config: { + ...alignedFrameField.config, + }, + values: field.values, + }; + + copy.display = getDisplayProcessor({ field: copy, theme }); + + return copy; + }); + + legendFields.unshift(firstField); + } + // String field is first fields.unshift(firstField); @@ -476,6 +497,10 @@ export function prepareBarChartDisplayValues( fields: fields, // ideally: fields.filter((f) => !Boolean(f.config.custom?.hideFrom?.viz)), }, ], + legend: { + fields: legendFields, + length: firstField.values.length, + }, }; }