[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 ab7a4e5f28)
This commit is contained in:
Victor Marin
2023-01-26 10:02:22 +00:00
committed by GitHub
parent 613940a0c8
commit 7ea31b5173
4 changed files with 78 additions and 2 deletions
@@ -218,7 +218,7 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({
}
}
return <PlotLegend data={info.viz} config={config} maxHeight="35%" maxWidth="60%" {...options.legend} />;
return <PlotLegend data={[info.legend]} config={config} maxHeight="35%" maxWidth="60%" {...options.legend} />;
};
const rawValue = (seriesIdx: number, valueIdx: number) => {
@@ -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;
}
@@ -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();
});
});
});
@@ -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,
},
};
}