From 99ae23f0be9be341ad4372fb88c2d1fb57868e35 Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Tue, 9 Aug 2022 15:50:28 +0300 Subject: [PATCH] Fix Percentile aggragtion --- .../__snapshots__/xy_chart.test.tsx.snap | 10 +++++ .../public/components/data_layers.tsx | 26 ++++++++---- .../public/components/legend_action.tsx | 6 ++- .../public/components/legend_color_picker.tsx | 5 ++- .../public/components/tooltip/tooltip.tsx | 6 ++- .../public/components/xy_chart.tsx | 4 +- .../public/helpers/data_layers.tsx | 25 ++++++----- src/plugins/vis_types/xy/public/to_ast.ts | 42 ++++++++++++------- 8 files changed, 85 insertions(+), 39 deletions(-) diff --git a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap index 1390545591f6c..e92644d7d2fb5 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap @@ -524,6 +524,7 @@ exports[`XYChart component it renders area 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -1505,6 +1506,7 @@ exports[`XYChart component it renders bar 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -2486,6 +2488,7 @@ exports[`XYChart component it renders horizontal bar 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -3467,6 +3470,7 @@ exports[`XYChart component it renders line 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -4448,6 +4452,7 @@ exports[`XYChart component it renders stacked area 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -5429,6 +5434,7 @@ exports[`XYChart component it renders stacked bar 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -6410,6 +6416,7 @@ exports[`XYChart component it renders stacked horizontal bar 1`] = ` }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -7417,6 +7424,7 @@ exports[`XYChart component split chart should render split chart if both, splitR }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -8638,6 +8646,7 @@ exports[`XYChart component split chart should render split chart if splitColumnA }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, @@ -9850,6 +9859,7 @@ exports[`XYChart component split chart should render split chart if splitRowAcce }, "legendPosition": "top", "setColor": [Function], + "singleTable": undefined, "titles": Object { "first": Object { "markSizeTitles": Object {}, diff --git a/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx b/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx index ca7acd25fd785..035faf8d22b00 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx @@ -110,10 +110,22 @@ export const DataLayers: FC = ({ : getColorAssignments(layers, titles, fieldFormats, formattedDatatables); return ( <> - {layers.flatMap((layer) => - layer.accessors.map((accessor, accessorIndex) => { - const { seriesType, columnToLabel, layerId, table } = layer; - const yColumnId = getAccessorByDimension(accessor, table.columns); + {layers.flatMap((layer) => { + const yPercentileAccessors: string[] = []; + const yAccessors: string[] = []; + layer.accessors.forEach((accessor) => { + const columnId = getAccessorByDimension(accessor, layer.table.columns); + if (columnId.includes('.')) { + yPercentileAccessors.push(columnId); + } else { + yAccessors.push(columnId); + } + }); + return ( + yPercentileAccessors.length ? [...yAccessors, yPercentileAccessors] : [...yAccessors] + ).map((accessor, accessorIndex) => { + const { seriesType, columnToLabel, layerId } = layer; + const yColumnId = Array.isArray(accessor) ? accessor[0] : accessor; const columnToLabelMap: Record = columnToLabel ? JSON.parse(columnToLabel) : {}; @@ -134,7 +146,7 @@ export const DataLayers: FC = ({ const seriesProps = getSeriesProps({ layer, titles: titles[layer.layerId], - accessor: yColumnId, + accessor, chartHasMoreThanOneBarSeries, colorAssignments, formatFactory, @@ -194,8 +206,8 @@ export const DataLayers: FC = ({ /> ); } - }) - )} + }); + })} ); }; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx index e27bb716c35c7..0d1d3b5b59256 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx @@ -24,7 +24,8 @@ export const getLegendAction = ( onFilter: (data: FilterEvent['data']) => void, fieldFormats: LayersFieldFormats, formattedDatatables: DatatablesWithFormatInfo, - titles: LayersAccessorsTitles + titles: LayersAccessorsTitles, + singleTable?: boolean ): LegendAction => React.memo(({ series: [xySeries] }) => { const series = xySeries as XYChartSeriesIdentifier; @@ -35,6 +36,7 @@ export const getLegendAction = ( ) ) ); + const allYAccessors = dataLayers.flatMap((dataLayer) => dataLayer.accessors); if (layerIndex === -1) { return null; @@ -78,7 +80,7 @@ export const getLegendAction = ( series, { splitAccessors: layer.splitAccessors, - accessorsCount: layer.accessors.length, + accessorsCount: singleTable ? allYAccessors.length : layer.accessors.length, columns: table.columns, splitAccessorsFormats: fieldFormats[layer.layerId].splitSeriesAccessors, alreadyFormattedColumns: formattedDatatables[layer.layerId].formattedColumns, diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx index fa4e02a5a9d74..3573fc65e5288 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx @@ -43,6 +43,7 @@ export interface LegendColorPickerWrapperContextType { formattedDatatables: DatatablesWithFormatInfo; titles: LayersAccessorsTitles; fieldFormats: LayersFieldFormats; + singleTable?: boolean; } export const LegendColorPickerWrapperContext = createContext< @@ -73,16 +74,18 @@ export const LegendColorPickerWrapper: LegendColorPicker = ({ titles, formattedDatatables, fieldFormats, + singleTable, } = colorPickerWrappingContext; const { layerId } = getMetaFromSeriesId(seriesIdentifier.specId); const layer = dataLayers.find((dataLayer) => dataLayer.layerId === layerId); + const allYAccessors = dataLayers.flatMap((dataLayer) => dataLayer.accessors); const seriesName = layer ? getSeriesName( seriesIdentifier as XYChartSeriesIdentifier, { splitAccessors: layer.splitAccessors ?? [], - accessorsCount: layer.accessors.length, + accessorsCount: singleTable ? allYAccessors.length : layer.accessors.length, columns: formattedDatatables[layer.layerId].table.columns, splitAccessorsFormats: fieldFormats[layer.layerId].splitSeriesAccessors, alreadyFormattedColumns: formattedDatatables[layer.layerId].formattedColumns, diff --git a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx index ca7152e485c9f..6d4ba715dae0d 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx @@ -56,7 +56,7 @@ export const Tooltip: FC = ({ const data: TooltipData[] = []; const seriesIdentifier = pickedValue.seriesIdentifier as XYChartSeriesIdentifier; - const { layerId, xAccessor, yAccessor } = getMetaFromSeriesId(seriesIdentifier.specId); + const { layerId, xAccessor, yAccessors } = getMetaFromSeriesId(seriesIdentifier.specId); const { formattedColumns, table } = formattedDatatables[layerId]; const layerTitles = titles[layerId]; const layerFormats = fieldFormats[layerId]; @@ -75,7 +75,9 @@ export const Tooltip: FC = ({ }); } - const tooltipYAccessor = yAccessor === seriesIdentifier.yAccessor ? yAccessor : null; + const tooltipYAccessor = yAccessors.includes(seriesIdentifier.yAccessor as string) + ? (seriesIdentifier.yAccessor as string) + : null; if (tooltipYAccessor) { const yFormatter = formatFactory(layerFormats.yAccessors[tooltipYAccessor]); data.push({ diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 16db7775a6d86..c94eccaeed0ba 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -737,6 +737,7 @@ export function XYChart({ formattedDatatables, titles, fieldFormats, + singleTable, }} > @@ -827,7 +828,8 @@ export function XYChart({ onClickValue, fieldFormats, formattedDatatables, - titles + titles, + singleTable ) : undefined } diff --git a/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx b/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx index bb37e1c2a56fb..8098bb0efe02b 100644 --- a/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx @@ -38,7 +38,7 @@ type SeriesSpec = LineSeriesProps & BarSeriesProps & AreaSeriesProps; type GetSeriesPropsFn = (config: { layer: CommonXYDataLayerConfig; titles?: LayerAccessorsTitles; - accessor: string; + accessor: string | string[]; chartHasMoreThanOneBarSeries?: boolean; formatFactory: FormatFactory; colorAssignments: ColorAssignments; @@ -74,7 +74,6 @@ type GetColorFn = ( seriesIdentifier: XYChartSeriesIdentifier, config: { layer: CommonXYDataLayerConfig; - accessor: string; colorAssignments: ColorAssignments; paletteService: PaletteRegistry; getSeriesNameFn: (d: XYChartSeriesIdentifier) => SeriesName; @@ -309,11 +308,11 @@ const getLineConfig: GetLineConfigFn = ({ showLines, lineWidth }) => ({ const getColor: GetColorFn = ( series, - { layer, accessor, colorAssignments, paletteService, syncColors, getSeriesNameFn }, + { layer, colorAssignments, paletteService, syncColors, getSeriesNameFn }, uiState, singleTable ) => { - const overwriteColor = getSeriesColor(layer, accessor); + const overwriteColor = getSeriesColor(layer, series.yAccessor as string); if (overwriteColor !== null) { return overwriteColor; } @@ -348,6 +347,7 @@ const getColor: GetColorFn = ( const EMPTY_ACCESSOR = '-'; const SPLIT_CHAR = ':'; +const SPLIT_Y_ACCESSORS = '|'; export const generateSeriesId = ( { layerId }: Pick, @@ -360,11 +360,11 @@ export const generateSeriesId = ( ); export const getMetaFromSeriesId = (seriesId: string) => { - const [layerId, xAccessor, yAccessor, ...splitAccessors] = seriesId.split(SPLIT_CHAR); + const [layerId, xAccessor, yAccessors, ...splitAccessors] = seriesId.split(SPLIT_CHAR); return { layerId, xAccessor: xAccessor === EMPTY_ACCESSOR ? undefined : xAccessor, - yAccessor, + yAccessors: yAccessors.split(SPLIT_Y_ACCESSORS), splitAccessor: splitAccessors[0] === EMPTY_ACCESSOR ? undefined : splitAccessors, }; }; @@ -411,7 +411,9 @@ export const getSeriesProps: GetSeriesPropsFn = ({ (isStacked || !splitColumnIds.length) && (isStacked || !isBarChart || !chartHasMoreThanOneBarSeries); - const formatter = table?.columns.find((column) => column.id === accessor)?.meta?.params; + const formatter = table?.columns.find( + (column) => column.id === (Array.isArray(accessor) ? accessor[0] : accessor) + )?.meta?.params; const markSizeColumnId = markSizeAccessor ? getAccessorByDimension(markSizeAccessor, table.columns) @@ -433,7 +435,9 @@ export const getSeriesProps: GetSeriesPropsFn = ({ !(xColumnId && row[xColumnId] === undefined) && !( splitColumnIds.some((splitColumnId) => row[splitColumnId] === undefined) && - row[accessor] === undefined + (Array.isArray(accessor) + ? accessor.some((a) => row[a] === undefined) + : row[accessor] === undefined) ) ); @@ -471,11 +475,11 @@ export const getSeriesProps: GetSeriesPropsFn = ({ id: generateSeriesId( layer, splitColumnIds.length ? splitColumnIds : [EMPTY_ACCESSOR], - accessor, + Array.isArray(accessor) ? accessor.join(SPLIT_Y_ACCESSORS) : accessor, xColumnId ), xAccessor: xColumnId || 'unifiedX', - yAccessors: [accessor], + yAccessors: Array.isArray(accessor) ? accessor : [accessor], markSizeAccessor: markSizeColumnId, markFormat: (value) => markFormatter.convert(value), data: rows, @@ -489,7 +493,6 @@ export const getSeriesProps: GetSeriesPropsFn = ({ series, { layer, - accessor, colorAssignments, paletteService, getSeriesNameFn, diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 7f8212eef7625..05806c4549b7c 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -423,23 +423,35 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params }); } + const series = finalSeriesParams.reduce>((acc, param) => { + if (param.show && yAccessors[param.data.id]) { + if (param.valueAxis && acc[param.valueAxis]) { + acc[param.valueAxis].yAccessors.push(...yAccessors[param.data.id]); + } else { + acc[param.valueAxis] = { + ...param, + yAccessors: [...yAccessors[param.data.id]], + }; + } + } + return acc; + }, {}); + const visTypeXy = buildExpressionFunction('layeredXyVis', { layers: [ - ...finalSeriesParams - .filter((seriesParam) => seriesParam.show && yAccessors[seriesParam.data.id]) - .map((seriesParam) => - prepareLayers( - seriesParam, - isHistogram, - vis.params.valueAxes, - yAccessors[seriesParam.data.id], - dimensions.x, - dimensions.series, - dimensions.z ? dimensions.z[0] : undefined, - vis.params.palette, - xScale - ) - ), + ...Object.keys(series).map((key) => + prepareLayers( + series[key], + isHistogram, + vis.params.valueAxes, + series[key].yAccessors, + dimensions.x, + dimensions.series, + dimensions.z ? dimensions.z[0] : undefined, + vis.params.palette, + xScale + ) + ), ...(vis.params.thresholdLine.show ? [prepareReferenceLine(vis.params.thresholdLine, vis.params.valueAxes[0].id)] : []),