From 9dfab8abcfbd7c00e928531c2e30f98a0004618d Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 12 Aug 2021 16:36:22 +0300 Subject: [PATCH 01/43] Added comments for places I wished to refactor. --- .../public/expression_functions/xy_vis_fn.ts | 11 +++++++++++ .../public/utils/render_all_series.tsx | 4 ++++ .../vis_type_xy/public/vis_component.tsx | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts index 35f3b2d7c627d..6f41c9aa0b441 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts @@ -251,6 +251,16 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ }, fillOpacity: args.fillOpacity, fittingFunction: args.fittingFunction, + // @TODO: This part of `VisParams` has special details of esaggs query, but it seems to me, + // as a chart, it should know nothing from such information in the purpose of the reusability + // with other functions. + // For example, if we would like to use `essql`, `esdocs`, or even `demodata` functions, + // this chart vis would not fully support rendering of that data with flexibility. + // + // I propose to create a layer, some function, as `pointseries`, which would receive the data + // from some data source, process its output, prepare for rendering `xy_vis` and pass the result to current fn. + // And as a result, we would have always good, stable, customizable interface, without connection to the special data + // from the query result. dimensions: { x: args.xDimension, y: args.yDimension, @@ -260,6 +270,7 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ splitRow: args.splitRowDimension, splitColumn: args.splitColumnDimension, }, + // ------------------------------------------------------------------------------------------------------------------ } as VisParams; if (handlers?.inspectorAdapters?.tables) { diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx index d186617fef2ae..8b57b712e988b 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx @@ -82,6 +82,8 @@ export const renderAllSeries = ( interpolate, type, }) => { + // @TODO: should move this special logic, related to aggs to the separate `fn`, out of `xy_vis` rendering logic + // it is not related to the visualization, those are details of querying/filtering data, not rendering. const yAspects = aspects.y.filter(({ aggId, aggType, accessor }) => { if ( aggType === METRIC_TYPES.PERCENTILES || @@ -93,6 +95,8 @@ export const renderAllSeries = ( return aggId === paramId && accessor !== null; } }); + // ------------------------------------------------------------------------------------------------------------ + if (!show || !yAspects.length) { return null; } diff --git a/src/plugins/vis_type_xy/public/vis_component.tsx b/src/plugins/vis_type_xy/public/vis_component.tsx index 2dffabb2ba0b9..71b44661532a1 100644 --- a/src/plugins/vis_type_xy/public/vis_component.tsx +++ b/src/plugins/vis_type_xy/public/vis_component.tsx @@ -71,7 +71,7 @@ export type VisComponentType = typeof VisComponent; const VisComponent = (props: VisComponentProps) => { const [showLegend, setShowLegend] = useState(() => { - // TODO: Check when this bwc can safely be removed + // @TODO: Check when this bwc can safely be removed const bwcLegendStateDefault = props.visParams.addLegend == null ? true : props.visParams.addLegend; return props.uiState?.get('vis.legendOpen', bwcLegendStateDefault) as boolean; @@ -210,17 +210,31 @@ const VisComponent = (props: VisComponentProps) => { const config = getConfig(visData, visParams); const timeZone = getTimeZone(); + + // @TODO: I think, { min, max, interval? } need to come to props to avoid relations with aggregations const xDomain = config.xAxis.scale.type === ScaleType.Ordinal ? undefined : getXDomain(config.aspects.x.params); + // ------------------------------------------------------------------------------------------------------- + + // @TODO: move this logic to the `pointseries` function or kind of that to separate + // view from logic of processing the result of fetching. + // This will enable the possibility to reuse `xy_vis` as a rendering function. const hasBars = visParams.seriesParams.some( ({ type, data: { id: paramId } }) => type === ChartType.Histogram && config.aspects.y.find(({ aggId }) => aggId === paramId) !== undefined ); + // ------------------------------------------------------------------------------------------------------- + + // @TODO: move this logic from `xy_vis` function and renderer to a separate function, which would proceed + // the result of `esaggs` and pass ready visualization params to `xy_vis` function and renderer as a following step. + // Possibly, it makes sence to move this logic to `pointseries` function. const adjustedXDomain = config.xAxis.scale.type === ScaleType.Ordinal ? undefined : getAdjustedDomain(visData.rows, config.aspects.x, timeZone, xDomain, hasBars); + // ------------------------------------------------------------------------------------------------------- + const legendPosition = useMemo(() => config.legend.position ?? Position.Right, [ config.legend.position, ]); @@ -280,6 +294,8 @@ const VisComponent = (props: VisComponentProps) => { palettesRegistry, ] ); + + // @TODO: move this logic, related to aggregation types, to the other processing function, out of `xy_vis`. const xAccessor = getXAccessor(config.aspects.x); const splitSeriesAccessors = useMemo( @@ -295,6 +311,7 @@ const VisComponent = (props: VisComponentProps) => { const splitChartRowAccessor = config.aspects.splitRow ? getComplexAccessor(COMPLEX_SPLIT_ACCESSOR, true)(config.aspects.splitRow) : undefined; + // ------------------------------------------------------------------------------------------------------- const renderSeries = useMemo( () => From 8a6b5022bc0ddb1af4a3c2f223b86ed7152d4aab Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 23 Aug 2021 14:56:33 +0300 Subject: [PATCH 02/43] Fixed comments. --- .../vis_types/xy/public/expression_functions/xy_vis_fn.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index 074f39284d5ed..382a490fe1973 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -274,11 +274,6 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ // with other functions. // For example, if we would like to use `essql`, `esdocs`, or even `demodata` functions, // this chart vis would not fully support rendering of that data with flexibility. - // - // I propose to create a layer, some function, as `pointseries`, which would receive the data - // from some data source, process its output, prepare for rendering `xy_vis` and pass the result to current fn. - // And as a result, we would have always good, stable, customizable interface, without connection to the special data - // from the query result. dimensions: { x: args.xDimension, y: args.yDimension, From f74fc2862c0a66039b1664b5d3ac3addb5c3e72c Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Wed, 1 Sep 2021 15:32:11 +0300 Subject: [PATCH 03/43] Removed logic, related to BUCKET_TYPES. --- src/plugins/vis_types/xy/kibana.json | 2 +- .../xy/public/components/detailed_tooltip.tsx | 19 ++++++++---- .../vis_types/xy/public/config/get_axis.ts | 13 ++++---- .../vis_types/xy/public/config/get_config.ts | 30 ++++++++++--------- src/plugins/vis_types/xy/public/plugin.ts | 6 ++-- src/plugins/vis_types/xy/public/services.ts | 7 +++-- .../xy/public/utils/accessors.test.ts | 2 +- .../vis_types/xy/public/utils/accessors.tsx | 24 ++++++++------- .../xy/public/utils/render_all_series.tsx | 22 ++++---------- .../vis_types/xy/public/vis_component.tsx | 5 ++-- 10 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/plugins/vis_types/xy/kibana.json b/src/plugins/vis_types/xy/kibana.json index c25f035fb6d4b..b23011799a54c 100644 --- a/src/plugins/vis_types/xy/kibana.json +++ b/src/plugins/vis_types/xy/kibana.json @@ -3,7 +3,7 @@ "version": "kibana", "ui": true, "server": true, - "requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection"], + "requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection", "fieldFormats"], "requiredBundles": ["kibanaUtils", "visDefaultEditor"], "extraPublicDirs": ["common/index"], "owner": { diff --git a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx index fb6b4bb41d9ba..f8f12b939424f 100644 --- a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx +++ b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx @@ -19,7 +19,7 @@ import { import { Aspects } from '../types'; import './_detailed_tooltip.scss'; -import { COMPLEX_SPLIT_ACCESSOR, isRangeAggType } from '../utils/accessors'; +import { COMPLEX_SPLIT_ACCESSOR, isSimpleField } from '../utils/accessors'; interface TooltipData { label: string; @@ -34,10 +34,13 @@ export const getTooltipData = ( const data: TooltipData[] = []; if (header) { - const xFormatter = isRangeAggType(aspects.x.aggType) ? null : aspects.x.formatter; data.push({ label: aspects.x.title, - value: xFormatter ? xFormatter(header.value) : `${header.value}`, + // already formatted while execiting accessor on such a complex field as `*_range` + value: + isSimpleField(aspects.x.format) && aspects.x.formatter + ? aspects.x.formatter(header.value) + : `${header.value}`, }); } @@ -47,14 +50,20 @@ export const getTooltipData = ( if (yAccessor) { data.push({ label: yAccessor.title, - value: yAccessor.formatter ? yAccessor.formatter(value.value) : `${value.value}`, + value: + isSimpleField(yAccessor.format) && yAccessor.formatter + ? yAccessor.formatter(value.value) + : `${value.value}`, }); } if (aspects.z && !isNil(value.markValue)) { data.push({ label: aspects.z.title, - value: aspects.z.formatter ? aspects.z.formatter(value.markValue) : `${value.markValue}`, + value: + isSimpleField(aspects.z.format) && aspects.z.formatter + ? aspects.z.formatter(value.markValue) + : `${value.markValue}`, }); } diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index 4750724ca3d42..135ffbab4533a 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -6,13 +6,9 @@ * Side Public License, v 1. */ -import { identity, isNil } from 'lodash'; - +import { isNil } from 'lodash'; import { AxisSpec, TickFormatter, YDomainRange, ScaleType as ECScaleType } from '@elastic/charts'; - import { LabelRotation } from '../../../../charts/public'; -import { BUCKET_TYPES } from '../../../../data/public'; - import { Aspect, CategoryAxis, @@ -27,6 +23,7 @@ import { YScaleType, SeriesParam, } from '../types'; +import { isSimpleField } from '../utils/accessors'; export function getAxis( { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, @@ -50,9 +47,8 @@ export function getAxis( : { show: valueAxis === axis.id, }; - // Date range formatter applied on xAccessor - const tickFormatter = - aggType === BUCKET_TYPES.DATE_RANGE || aggType === BUCKET_TYPES.RANGE ? identity : formatter; + + const tickFormatter = (v: any) => (isSimpleField(format) ? formatter?.(v) ?? v : v); const ticks: TickOptions = { formatter: tickFormatter, labelFormatter: getLabelFormatter(labels.truncate, tickFormatter), @@ -61,6 +57,7 @@ export function getAxis( showOverlappingLabels: !labels.filter, showDuplicates: !labels.filter, }; + const scale = getScale(axisScale, params, format, isCategoryAxis); const title = axisTitle.text || fallbackTitle; const fallbackRotation = diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index 13c9a6c275f8e..5a299ac12558f 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -9,12 +9,12 @@ import { ScaleContinuousType } from '@elastic/charts'; import { Datatable } from '../../../../expressions/public'; -import { BUCKET_TYPES } from '../../../../data/public'; -import { DateHistogramParams } from '../../../../visualizations/public'; - +import { KBN_FIELD_TYPES } from '../../../../data/public'; import { Aspect, AxisConfig, + AxisMode, + ChartMode, SeriesParam, VisConfig, VisParams, @@ -42,23 +42,25 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { fillOpacity, } = params; const aspects = getAspects(table.columns, params.dimensions); + const yAxes = params.valueAxes.map((a) => + // uses first y aspect in array for formatting axis + getAxis(a, params.grid, aspects.y[0], params.seriesParams) + ); + + const enableHistogramMode = shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); + + const timeChartFieldTypes: string[] = [KBN_FIELD_TYPES.DATE, KBN_FIELD_TYPES.DATE_RANGE]; + const isTimeChart = timeChartFieldTypes.includes(aspects.x.format?.id ?? ''); + const xAxis = getAxis( params.categoryAxes[0], params.grid, aspects.x, params.seriesParams, - params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM + aspects.x.format?.id === KBN_FIELD_TYPES.DATE ); + const tooltip = getTooltip(aspects, params); - const yAxes = params.valueAxes.map((a) => - // uses first y aspect in array for formatting axis - getAxis(a, params.grid, aspects.y[0], params.seriesParams) - ); - const enableHistogramMode = - (params.dimensions.x?.aggType === BUCKET_TYPES.DATE_HISTOGRAM || - params.dimensions.x?.aggType === BUCKET_TYPES.HISTOGRAM) && - shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); - const isTimeChart = (aspects.x.params as DateHistogramParams).date ?? false; return { // NOTE: downscale ratio to match current vislib implementation @@ -114,6 +116,6 @@ const shouldEnableHistogramMode = ( return bars.every(({ valueAxis: groupId, mode }) => { const yAxisScale = yAxes.find(({ groupId: axisGroupId }) => axisGroupId === groupId)?.scale; - return mode === 'stacked' || yAxisScale?.mode === 'percentage'; + return mode === ChartMode.Stacked || yAxisScale?.mode === AxisMode.Percentage; }); }; diff --git a/src/plugins/vis_types/xy/public/plugin.ts b/src/plugins/vis_types/xy/public/plugin.ts index 57736444f49fe..6245fc37d8d28 100644 --- a/src/plugins/vis_types/xy/public/plugin.ts +++ b/src/plugins/vis_types/xy/public/plugin.ts @@ -7,6 +7,7 @@ */ import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { FieldFormatsStart } from '../../../field_formats/public'; import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; import { VisualizationsSetup, VisualizationsStart } from '../../../visualizations/public'; import { ChartsPluginSetup, ChartsPluginStart } from '../../../charts/public'; @@ -48,6 +49,7 @@ export interface VisTypeXyPluginStartDependencies { visualizations: VisualizationsStart; data: DataPublicPluginStart; charts: ChartsPluginStart; + fieldFormats: FieldFormatsStart; } type VisTypeXyCoreSetup = CoreSetup; @@ -88,8 +90,8 @@ export class VisTypeXyPlugin return {}; } - public start(core: CoreStart, { data, charts }: VisTypeXyPluginStartDependencies) { - setFormatService(data.fieldFormats); + public start(core: CoreStart, { data, charts, fieldFormats }: VisTypeXyPluginStartDependencies) { + setFormatService(fieldFormats); setDataActions(data.actions); setDocLinks(core.docLinks); setActiveCursor(charts.activeCursor); diff --git a/src/plugins/vis_types/xy/public/services.ts b/src/plugins/vis_types/xy/public/services.ts index 7f1f7e8728151..ed3957ae872ab 100644 --- a/src/plugins/vis_types/xy/public/services.ts +++ b/src/plugins/vis_types/xy/public/services.ts @@ -11,6 +11,7 @@ import { CoreSetup, DocLinksStart } from '../../../../core/public'; import { createGetterSetter } from '../../../kibana_utils/public'; import { DataPublicPluginStart } from '../../../data/public'; import { ChartsPluginSetup, ChartsPluginStart } from '../../../charts/public'; +import { FieldFormatsStart } from '../../../field_formats/public'; export const [getUISettings, setUISettings] = createGetterSetter( 'xy core.uiSettings' @@ -20,9 +21,9 @@ export const [getDataActions, setDataActions] = createGetterSetter< DataPublicPluginStart['actions'] >('xy data.actions'); -export const [getFormatService, setFormatService] = createGetterSetter< - DataPublicPluginStart['fieldFormats'] ->('xy data.fieldFormats'); +export const [getFormatService, setFormatService] = createGetterSetter( + 'xy data.fieldFormats' +); export const [getThemeService, setThemeService] = createGetterSetter( 'xy charts.theme' diff --git a/src/plugins/vis_types/xy/public/utils/accessors.test.ts b/src/plugins/vis_types/xy/public/utils/accessors.test.ts index 61d175fa8ff7d..8a85eca083fc3 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.test.ts +++ b/src/plugins/vis_types/xy/public/utils/accessors.test.ts @@ -59,7 +59,7 @@ describe('XY chart datum accessors', () => { aggType: BUCKET_TYPES.TERMS, ...aspectBase, }; - const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR, true)(aspect); + const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); expect(typeof accessor).toBe('function'); expect((accessor as AccessorFn)({ 'col-0-2': 'some value' })).toBe('some value'); diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index 0356e921a9d5c..28abb69883d79 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -7,7 +7,7 @@ */ import { AccessorFn, Accessor } from '@elastic/charts'; -import { BUCKET_TYPES } from '../../../../data/public'; +import { KBN_FIELD_TYPES } from '../../../../data/public'; import { FakeParams } from '../../../../visualizations/public'; import { Aspect } from '../types'; @@ -27,35 +27,37 @@ const getFieldName = (fieldName: string, index?: number) => { return `${fieldName}${indexStr}`; }; -export const isRangeAggType = (type: string | null) => - type === BUCKET_TYPES.DATE_RANGE || type === BUCKET_TYPES.RANGE || type === BUCKET_TYPES.IP_RANGE; +export const isSimpleField = (format: Aspect['format']) => { + const simpleFormats: string[] = [ + KBN_FIELD_TYPES.STRING, + KBN_FIELD_TYPES.NUMBER, + KBN_FIELD_TYPES.DATE, + KBN_FIELD_TYPES.BOOLEAN, + ]; + return simpleFormats.includes(format?.id ?? ''); +}; /** * Returns accessor function for complex accessor types * @param aspect * @param isComplex - forces to be functional/complex accessor */ -export const getComplexAccessor = (fieldName: string, isComplex: boolean = false) => ( +export const getComplexAccessor = (fieldName: string) => ( aspect: Aspect, index?: number ): Accessor | AccessorFn | undefined => { if (!aspect.accessor) { return; } - - if (!((isComplex || isRangeAggType(aspect.aggType)) && aspect.formatter)) { - return aspect.accessor; - } - const formatter = aspect.formatter; const accessor = aspect.accessor; + const fn: AccessorFn = (d) => { const v = d[accessor]; if (v === undefined) { return; } - const f = formatter(v); - return f; + return isSimpleField(aspect.format) ? v : formatter?.(v) ?? v; }; fn.fieldName = getFieldName(fieldName, index); diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx index f956dc561129c..d359fd737b4ad 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -82,25 +82,16 @@ export const renderAllSeries = ( interpolate, type, }) => { - // @TODO: should move this special logic, related to aggs to the separate `fn`, out of `xy_vis` rendering logic - // it is not related to the visualization, those are details of querying/filtering data, not rendering. - const yAspects = aspects.y.filter(({ aggId, aggType, accessor }) => { - if ( - aggType === METRIC_TYPES.PERCENTILES || - aggType === METRIC_TYPES.PERCENTILE_RANKS || - aggType === METRIC_TYPES.STD_DEV - ) { - return aggId?.includes(paramId) && accessor !== null; - } else { - return aggId === paramId && accessor !== null; - } - }); - // ------------------------------------------------------------------------------------------------------------ + const yAspects = aspects.y.filter( + ({ aggId, accessor }) => + ((Array.isArray(aggId) && aggId?.includes(paramId)) || aggId === paramId) && + accessor !== null + ); if (!show || !yAspects.length) { return null; } - const yAccessors = yAspects.map((aspect) => aspect.accessor) as string[]; + const yAccessors: string[] = yAspects.map((aspect) => aspect.accessor ?? ''); const id = `${type}-${yAccessors[0]}`; const yAxisScale = yAxes.find(({ groupId: axisGroupId }) => axisGroupId === groupId)?.scale; @@ -148,7 +139,6 @@ export const renderAllSeries = ( case ChartType.Area: case ChartType.Line: const markSizeAccessor = showCircles ? aspects.z?.accessor ?? undefined : undefined; - return ( { [config.aspects.series] ); const splitChartColumnAccessor = config.aspects.splitColumn - ? getComplexAccessor(COMPLEX_SPLIT_ACCESSOR, true)(config.aspects.splitColumn) + ? getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(config.aspects.splitColumn) : undefined; const splitChartRowAccessor = config.aspects.splitRow - ? getComplexAccessor(COMPLEX_SPLIT_ACCESSOR, true)(config.aspects.splitRow) + ? getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(config.aspects.splitRow) : undefined; // ------------------------------------------------------------------------------------------------------- @@ -348,6 +348,7 @@ const VisComponent = (props: VisComponentProps) => { ), [getSeriesName, legendPosition, props.uiState, setColor, visParams.palette.name] ); + return (
Date: Wed, 1 Sep 2021 17:39:12 +0300 Subject: [PATCH 04/43] removed aggType connected code. --- src/plugins/vis_types/xy/public/config/get_axis.ts | 4 ++-- src/plugins/vis_types/xy/public/to_ast.ts | 12 +++++++++++- src/plugins/vis_types/xy/public/types/param.ts | 2 +- .../vis_types/xy/public/utils/render_all_series.tsx | 12 ++++-------- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index 135ffbab4533a..d73494d5acd50 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -28,7 +28,7 @@ import { isSimpleField } from '../utils/accessors'; export function getAxis( { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, { categoryLines, valueAxis }: Grid, - { params, format, formatter, title: fallbackTitle = '', aggType }: Aspect, + { params, format, formatter, title: fallbackTitle = '' }: Aspect, seriesParams: SeriesParam[], isDateHistogram = false ): AxisConfig { @@ -73,7 +73,7 @@ export function getAxis( scale, style: getAxisStyle(ticks, title, fallbackRotation), domain: getAxisDomain(scale, isCategoryAxis), - integersOnly: aggType === 'count', + integersOnly: params?.integersOnly ?? false, }; } diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 5fc130a08ed27..7c4deb9a0540e 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -28,6 +28,7 @@ import { ValueAxis, Scale, TimeMarker, + AxisMode, } from './types'; import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_functions/xy_vis_fn'; import { XyVisType } from '../common'; @@ -184,10 +185,19 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params const usedValueAxis = (vis.params.valueAxes || []).find( (valueAxis: any) => valueAxis.id === seriesParam.valueAxis ); - if (usedValueAxis?.scale.mode === 'percentage') { + if (usedValueAxis?.scale.mode === AxisMode.Percentage) { yDimension.format = { id: 'percent' }; } } + // if aggType is 'Count', need to display only integers at y-axis + // prevent from displaying floats on small charts with small step + if (yDimension.aggType === 'count') { + if (!yDimension.params) { + yDimension.params = {}; + } + + yDimension.params.integersOnly = true; + } }); const visTypeXy = buildExpressionFunction(visName, { diff --git a/src/plugins/vis_types/xy/public/types/param.ts b/src/plugins/vis_types/xy/public/types/param.ts index 81eeca55108ca..c7566ec481bbc 100644 --- a/src/plugins/vis_types/xy/public/types/param.ts +++ b/src/plugins/vis_types/xy/public/types/param.ts @@ -103,7 +103,7 @@ export interface TimeMarker { export type Dimension = Omit & { params: DateHistogramParams | HistogramParams | FakeParams | {}; -}; +} & { params: { integersOnly?: boolean } }; export interface Dimensions { x: Dimension | null; diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx index d359fd737b4ad..68c0a1bf6b37e 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -7,7 +7,6 @@ */ import React from 'react'; - import { AreaSeries, CurveType, @@ -20,18 +19,15 @@ import { ColorVariant, LabelOverflowConstraint, } from '@elastic/charts'; - import { DatatableRow } from '../../../../expressions/public'; -import { METRIC_TYPES } from '../../../../data/public'; - import { ChartType } from '../../common'; -import { SeriesParam, VisConfig } from '../types'; +import { AxisMode, ChartMode, InterpolationMode, SeriesParam, VisConfig } from '../types'; /** * Matches vislib curve to elastic charts * @param type curve type */ -const getCurveType = (type?: 'linear' | 'cardinal' | 'step-after'): CurveType => { +const getCurveType = (type?: InterpolationMode): CurveType => { switch (type) { case 'cardinal': return CurveType.CURVE_MONOTONE_X; @@ -95,8 +91,8 @@ export const renderAllSeries = ( const id = `${type}-${yAccessors[0]}`; const yAxisScale = yAxes.find(({ groupId: axisGroupId }) => axisGroupId === groupId)?.scale; - const isStacked = mode === 'stacked' || yAxisScale?.mode === 'percentage'; - const stackMode = yAxisScale?.mode === 'normal' ? undefined : yAxisScale?.mode; + const isStacked = mode === ChartMode.Stacked || yAxisScale?.mode === AxisMode.Percentage; + const stackMode = yAxisScale?.mode === AxisMode.Normal ? undefined : yAxisScale?.mode; // needed to seperate stacked and non-stacked bars into unique pseudo groups const pseudoGroupId = isStacked ? `__pseudo_stacked_group-${groupId}__` : groupId; // set domain of stacked groups to use actual groupId not pseudo groupdId From df2e3db687eb7e359700684dead762a1fc46a17a Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 12:12:23 +0300 Subject: [PATCH 05/43] Added `id` to `xy_dimension` to avoid direct comparison with aggId --- .../xy/public/expression_functions/xy_vis_fn.ts | 12 ++++++++---- src/plugins/vis_types/xy/public/to_ast.ts | 1 + .../common/expression_functions/xy_dimension.ts | 11 ++++++++++- src/plugins/visualizations/public/vis_schemas.ts | 2 ++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index 382a490fe1973..266dc07c1bc10 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -255,10 +255,14 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ categoryLines: args.gridCategoryLines, valueAxis: args.gridValueAxis, }, - seriesParams: args.seriesParams.map((seriesParam) => ({ - ...seriesParam, - type: seriesParam.seriesParamType, - })), + seriesParams: args.seriesParams.map((seriesParam) => { + const matchedSeries = args.yDimension.filter((y) => y.id === seriesParam.data.id); + return { + ...seriesParam, + show: matchedSeries.length > 0, + type: seriesParam.seriesParamType, + }; + }), radiusRatio: args.radiusRatio, times: args.times, isVislibVis: args.isVislibVis, diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 7c4deb9a0540e..4dc96adbc9f08 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -127,6 +127,7 @@ const prepareXYDimension = (data: Dimension) => { aggType: data.aggType, label: data.label, visDimension: prepareVisDimension(data), + id: data.id, }); return buildExpression([xyDimension]); diff --git a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts index 82538fea8605a..0d6bb2ee5e962 100644 --- a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts +++ b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts @@ -42,6 +42,7 @@ interface Arguments { params: string; aggType: string; label: string; + id?: number | string; } export type ExpressionValueXYDimension = ExpressionValueBoxed< @@ -52,7 +53,8 @@ export type ExpressionValueXYDimension = ExpressionValueBoxed< params: DateHistogramParams | HistogramParams | FakeParams | {}; accessor: number | DatatableColumn; format: SerializedFieldFormat; - } + id?: number | string; + } & { params: { integersOnly?: boolean } } >; export const xyDimension = (): ExpressionFunctionDefinition< @@ -93,6 +95,12 @@ export const xyDimension = (): ExpressionFunctionDefinition< defaultMessage: 'Params', }), }, + id: { + types: ['string', 'number'], + help: i18n.translate('visualizations.function.xyDimension.id.help', { + defaultMessage: 'ID', // @TODO: add description + }), + }, }, fn: (context, args) => { return { @@ -102,6 +110,7 @@ export const xyDimension = (): ExpressionFunctionDefinition< params: JSON.parse(args.params!), accessor: args.visDimension.accessor as number, format: args.visDimension.format, + id: args.id, }; }, }); diff --git a/src/plugins/visualizations/public/vis_schemas.ts b/src/plugins/visualizations/public/vis_schemas.ts index 115e13ece45ff..ac421416ceead 100644 --- a/src/plugins/visualizations/public/vis_schemas.ts +++ b/src/plugins/visualizations/public/vis_schemas.ts @@ -24,6 +24,7 @@ export interface SchemaConfig { format: SerializedFieldFormat; params: SchemaConfigParams; aggType: string; + id?: number | string; } export interface Schemas { @@ -86,6 +87,7 @@ export const getVisSchemas = ( params, label, aggType: agg.type.name, + id: agg.id, }; }; From 6093e969f218fdeac61c38d139f69eac2b1c9ddd Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 12:26:40 +0300 Subject: [PATCH 06/43] Removed all checks of seriesParams at chart. --- src/plugins/vis_types/xy/public/config/get_aspects.ts | 3 ++- src/plugins/vis_types/xy/public/config/get_config.ts | 6 +----- src/plugins/vis_types/xy/public/types/config.ts | 1 + .../vis_types/xy/public/utils/render_all_series.tsx | 8 +++----- src/plugins/vis_types/xy/public/vis_component.tsx | 6 +----- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/plugins/vis_types/xy/public/config/get_aspects.ts b/src/plugins/vis_types/xy/public/config/get_aspects.ts index 666a913e48402..b9374f4c9cc12 100644 --- a/src/plugins/vis_types/xy/public/config/get_aspects.ts +++ b/src/plugins/vis_types/xy/public/config/get_aspects.ts @@ -76,7 +76,7 @@ function getAspectsFromDimension( const getAspect = ( { id: accessor, name: title }: DatatableColumn, - { accessor: column, format, params, aggType }: Dimension + { accessor: column, format, params, aggType, id }: Dimension ): Aspect => ({ accessor, column, @@ -86,4 +86,5 @@ const getAspect = ( aggId: getAggId(accessor), formatter: (value: any) => getFormatService().deserialize(format).convert(value), params, + id, }); diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index 5a299ac12558f..db68ed2b39373 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -96,11 +96,7 @@ const shouldEnableHistogramMode = ( yAspects: Aspect[], yAxes: Array> ): boolean => { - const bars = seriesParams.filter(({ type, data: { id: paramId } }) => { - return ( - type === ChartType.Histogram && yAspects.find(({ aggId }) => aggId === paramId) !== undefined - ); - }); + const bars = seriesParams.filter(({ type }) => type === ChartType.Histogram); const groupIds = [ ...bars.reduce>((acc, { valueAxis: groupId, mode }) => { diff --git a/src/plugins/vis_types/xy/public/types/config.ts b/src/plugins/vis_types/xy/public/types/config.ts index e52b47366bc85..2df34daa82bc0 100644 --- a/src/plugins/vis_types/xy/public/types/config.ts +++ b/src/plugins/vis_types/xy/public/types/config.ts @@ -36,6 +36,7 @@ export interface Aspect { format?: Dimension['format']; formatter?: TickFormatter; params: Dimension['params']; + id?: Dimension['id']; } export interface Aspects { diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx index 68c0a1bf6b37e..d64004a42b146 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -78,11 +78,9 @@ export const renderAllSeries = ( interpolate, type, }) => { - const yAspects = aspects.y.filter( - ({ aggId, accessor }) => - ((Array.isArray(aggId) && aggId?.includes(paramId)) || aggId === paramId) && - accessor !== null - ); + const yAspects = aspects.y.filter(({ accessor, id }) => { + return id === paramId && accessor !== null; + }); if (!show || !yAspects.length) { return null; diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index e1a649652d819..dd66856f7e338 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -219,11 +219,7 @@ const VisComponent = (props: VisComponentProps) => { // @TODO: move this logic to the `pointseries` function or kind of that to separate // view from logic of processing the result of fetching. // This will enable the possibility to reuse `xy_vis` as a rendering function. - const hasBars = visParams.seriesParams.some( - ({ type, data: { id: paramId } }) => - type === ChartType.Histogram && - config.aspects.y.find(({ aggId }) => aggId === paramId) !== undefined - ); + const hasBars = visParams.seriesParams.some(({ type }) => type === ChartType.Histogram); // ------------------------------------------------------------------------------------------------------- // @TODO: move this logic from `xy_vis` function and renderer to a separate function, which would proceed From 80eb59f0747b93dd1d821fb242dd36450b654c76 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 12:37:07 +0300 Subject: [PATCH 07/43] removed aggId and aggType from chart --- src/plugins/vis_types/xy/public/config/get_aspects.ts | 7 +------ .../vis_types/xy/public/expression_functions/xy_vis_fn.ts | 3 ++- src/plugins/vis_types/xy/public/to_ast.ts | 1 - src/plugins/vis_types/xy/public/types/config.ts | 2 -- src/plugins/visualizations/public/vis_schemas.ts | 3 +-- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/plugins/vis_types/xy/public/config/get_aspects.ts b/src/plugins/vis_types/xy/public/config/get_aspects.ts index b9374f4c9cc12..e5ad75d5bcccf 100644 --- a/src/plugins/vis_types/xy/public/config/get_aspects.ts +++ b/src/plugins/vis_types/xy/public/config/get_aspects.ts @@ -14,13 +14,10 @@ import { DatatableColumn } from '../../../../expressions/public'; import { Aspect, Dimension, Aspects, Dimensions } from '../types'; import { getFormatService } from '../services'; -import { getAggId } from './get_agg_id'; export function getEmptyAspect(): Aspect { return { accessor: null, - aggId: null, - aggType: null, title: i18n.translate('visTypeXy.aggResponse.allDocsTitle', { defaultMessage: 'All docs', }), @@ -76,14 +73,12 @@ function getAspectsFromDimension( const getAspect = ( { id: accessor, name: title }: DatatableColumn, - { accessor: column, format, params, aggType, id }: Dimension + { accessor: column, format, params, id }: Dimension ): Aspect => ({ accessor, column, title, format, - aggType, - aggId: getAggId(accessor), formatter: (value: any) => getFormatService().deserialize(format).convert(value), params, id, diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index 266dc07c1bc10..4806ee5ea937b 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -288,7 +288,8 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ splitColumn: args.splitColumnDimension, }, // ------------------------------------------------------------------------------------------------------------------ - } as VisParams; + } as VisParams; /* @TODO: rewrite this `as VisParams` to real `VisParams` via changing accessor + to vis_dimension accessor (accepting string, not only number) */ if (handlers?.inspectorAdapters?.tables) { const argsTable: Dimension[] = [ diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 4dc96adbc9f08..dbead38442f58 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -124,7 +124,6 @@ const prepareVisDimension = (data: Dimension) => { const prepareXYDimension = (data: Dimension) => { const xyDimension = buildExpressionFunction('xydimension', { params: JSON.stringify(data.params), - aggType: data.aggType, label: data.label, visDimension: prepareVisDimension(data), id: data.id, diff --git a/src/plugins/vis_types/xy/public/types/config.ts b/src/plugins/vis_types/xy/public/types/config.ts index 2df34daa82bc0..6120ef08dfbc4 100644 --- a/src/plugins/vis_types/xy/public/types/config.ts +++ b/src/plugins/vis_types/xy/public/types/config.ts @@ -29,8 +29,6 @@ export interface Column { export interface Aspect { accessor: Column['id']; - aggType: string | null; - aggId: string | null; column?: Dimension['accessor']; title: Column['name']; format?: Dimension['format']; diff --git a/src/plugins/visualizations/public/vis_schemas.ts b/src/plugins/visualizations/public/vis_schemas.ts index ac421416ceead..4d72902148534 100644 --- a/src/plugins/visualizations/public/vis_schemas.ts +++ b/src/plugins/visualizations/public/vis_schemas.ts @@ -23,7 +23,7 @@ export interface SchemaConfig { label: string; format: SerializedFieldFormat; params: SchemaConfigParams; - aggType: string; + aggType?: string; id?: number | string; } @@ -86,7 +86,6 @@ export const getVisSchemas = ( format: formatAgg.toSerializedFieldFormat(), params, label, - aggType: agg.type.name, id: agg.id, }; }; From 807a8eb86c48feefad23e4c0f535763f561fb7c1 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 12:59:21 +0300 Subject: [PATCH 08/43] removed all aggId/aggTypes from tests/mocks. --- .../components/detailed_tooltip.mock.ts | 24 ++++-------- .../xy/public/sample_vis.test.mocks.ts | 3 -- .../xy/public/utils/accessors.test.ts | 10 +---- .../xy/public/utils/get_all_series.test.ts | 9 ++--- .../public/utils/get_series_name_fn.test.ts | 15 +++---- .../utils/render_all_series.test.mocks.ts | 39 +++++++------------ 6 files changed, 31 insertions(+), 69 deletions(-) diff --git a/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts b/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts index 25310ea1ee7ff..b366074d5f085 100644 --- a/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts +++ b/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts @@ -17,8 +17,7 @@ export const aspects = { pattern: 'YYYY-MM-DD HH:mm', }, }, - aggType: 'date_histogram', - aggId: '3', + id: '3', params: { date: true, intervalESUnit: 'h', @@ -35,8 +34,7 @@ export const aspects = { format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ], @@ -53,8 +51,7 @@ export const aspectsWithSplitColumn = { pattern: 'YYYY-MM-DD HH:mm', }, }, - aggType: 'date_histogram', - aggId: '3', + id: '3', params: { date: true, intervalESUnit: 'h', @@ -71,8 +68,7 @@ export const aspectsWithSplitColumn = { format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ], @@ -88,8 +84,7 @@ export const aspectsWithSplitColumn = { missingBucketLabel: 'Missing', }, }, - aggType: 'terms', - aggId: '4', + id: '4', params: {}, }, }; @@ -105,8 +100,7 @@ export const aspectsWithSplitRow = { pattern: 'YYYY-MM-DD HH:mm', }, }, - aggType: 'date_histogram', - aggId: '3', + id: '3', params: { date: true, intervalESUnit: 'h', @@ -123,8 +117,7 @@ export const aspectsWithSplitRow = { format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ], @@ -140,8 +133,7 @@ export const aspectsWithSplitRow = { missingBucketLabel: 'Missing', }, }, - aggType: 'terms', - aggId: '4', + id: '4', params: {}, }, }; diff --git a/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts index 7fff29edfab51..307da89b0a7e6 100644 --- a/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts @@ -289,7 +289,6 @@ export const sampleAreaVis = { }, }, label: 'order_date per 12 hours', - aggType: 'date_histogram', }, y: [ { @@ -306,7 +305,6 @@ export const sampleAreaVis = { }, params: {}, label: 'Sum of total_quantity', - aggType: 'sum', }, ], series: [ @@ -322,7 +320,6 @@ export const sampleAreaVis = { }, params: {}, label: 'category.keyword: Descending', - aggType: 'terms', }, ], }, diff --git a/src/plugins/vis_types/xy/public/utils/accessors.test.ts b/src/plugins/vis_types/xy/public/utils/accessors.test.ts index 8a85eca083fc3..b2747b8d9bb02 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.test.ts +++ b/src/plugins/vis_types/xy/public/utils/accessors.test.ts @@ -7,21 +7,19 @@ */ import { COMPLEX_SPLIT_ACCESSOR, getComplexAccessor } from './accessors'; -import { BUCKET_TYPES } from '../../../../data/common'; import { AccessorFn, Datum } from '@elastic/charts'; describe('XY chart datum accessors', () => { const aspectBase = { accessor: 'col-0-2', formatter: (value: Datum) => value, - aggId: '', + id: '', title: '', params: {}, }; it('should return complex accessor for IP range aggregation', () => { const aspect = { - aggType: BUCKET_TYPES.IP_RANGE, ...aspectBase, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); @@ -39,7 +37,6 @@ describe('XY chart datum accessors', () => { it('should return complex accessor for date range aggregation', () => { const aspect = { - aggType: BUCKET_TYPES.DATE_RANGE, ...aspectBase, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); @@ -56,7 +53,6 @@ describe('XY chart datum accessors', () => { it('should return complex accessor when isComplex option set to true', () => { const aspect = { - aggType: BUCKET_TYPES.TERMS, ...aspectBase, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); @@ -67,7 +63,6 @@ describe('XY chart datum accessors', () => { it('should return simple string accessor for not range (date histogram) aggregation', () => { const aspect = { - aggType: BUCKET_TYPES.DATE_HISTOGRAM, ...aspectBase, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); @@ -78,7 +73,6 @@ describe('XY chart datum accessors', () => { it('should return simple string accessor when aspect has no formatter', () => { const aspect = { - aggType: BUCKET_TYPES.RANGE, ...aspectBase, formatter: undefined, }; @@ -90,7 +84,7 @@ describe('XY chart datum accessors', () => { it('should return undefined when aspect has no accessor', () => { const aspect = { - aggType: BUCKET_TYPES.RANGE, + ...aspectBase, accessor: null, }; diff --git a/src/plugins/vis_types/xy/public/utils/get_all_series.test.ts b/src/plugins/vis_types/xy/public/utils/get_all_series.test.ts index 6c6b78dfd73f7..0d8a04f674be4 100644 --- a/src/plugins/vis_types/xy/public/utils/get_all_series.test.ts +++ b/src/plugins/vis_types/xy/public/utils/get_all_series.test.ts @@ -78,8 +78,7 @@ const yAspects = [ format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ]; @@ -92,8 +91,7 @@ const myltipleYAspects = [ format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, { @@ -106,8 +104,7 @@ const myltipleYAspects = [ pattern: '$0,0.[00]', }, }, - aggType: 'avg', - aggId: '4', + id: '4', params: {}, }, ]; diff --git a/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts b/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts index 8853e6075e269..32f5360415e06 100644 --- a/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts +++ b/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts @@ -23,8 +23,7 @@ const aspects = { missingBucketLabel: 'Missing', }, }, - aggType: 'terms', - aggId: '3', + id: '3', params: {}, }, ], @@ -38,8 +37,7 @@ const aspects = { pattern: 'YYYY-MM-DD', }, }, - aggType: 'date_histogram', - aggId: '2', + id: '2', params: { date: true, intervalESUnit: 'd', @@ -56,8 +54,7 @@ const aspects = { format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ], @@ -112,8 +109,7 @@ describe('getSeriesNameFn', () => { format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ], @@ -133,8 +129,7 @@ describe('getSeriesNameFn', () => { format: { id: 'number', }, - aggType: 'count', - aggId: '1', + id: '1', params: {}, }, ], diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts index 5fe1b03dd8b93..d3898dbf82b0d 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts @@ -31,8 +31,7 @@ export const getVisConfig = (): VisConfig => { pattern: 'HH:mm', }, }, - aggType: 'date_histogram', - aggId: '2', + id: '2', params: { date: true, intervalESUnit: 'm', @@ -49,8 +48,7 @@ export const getVisConfig = (): VisConfig => { format: { id: 'number', }, - aggType: 'avg', - aggId: '3', + id: '3', params: {}, }, ], @@ -154,8 +152,7 @@ export const getVisConfigMutipleYaxis = (): VisConfig => { pattern: 'HH:mm', }, }, - aggType: 'date_histogram', - aggId: '2', + id: '2', params: { date: true, intervalESUnit: 'm', @@ -172,8 +169,7 @@ export const getVisConfigMutipleYaxis = (): VisConfig => { format: { id: 'number', }, - aggType: 'avg', - aggId: '3', + id: '3', params: {}, }, { @@ -183,8 +179,7 @@ export const getVisConfigMutipleYaxis = (): VisConfig => { format: { id: 'number', }, - aggType: 'avg', - aggId: '33', + id: '33', params: {}, }, ], @@ -288,8 +283,7 @@ export const getVisConfigPercentiles = (): VisConfig => { pattern: 'HH:mm', }, }, - aggType: 'date_histogram', - aggId: '2', + id: '2', params: { date: true, intervalESUnit: 'm', @@ -306,8 +300,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.1', + id: '3.1', params: {}, }, { @@ -317,8 +310,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.5', + id: '3.5', params: {}, }, { @@ -328,8 +320,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.25', + id: '3.25', params: {}, }, { @@ -339,8 +330,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.50', + id: '3.50', params: {}, }, { @@ -350,8 +340,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.75', + id: '3.75', params: {}, }, { @@ -361,8 +350,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.95', + id: '3.95', params: {}, }, { @@ -372,8 +360,7 @@ export const getVisConfigPercentiles = (): VisConfig => { format: { id: 'number', }, - aggType: 'percentiles', - aggId: '3.99', + id: '3.99', params: {}, }, ], From c8038412dd7c892160167395033b526e6e2b8212 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 13:15:06 +0300 Subject: [PATCH 09/43] Fixed comment. --- src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx index f8f12b939424f..aeb18c1555cdf 100644 --- a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx +++ b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx @@ -36,7 +36,7 @@ export const getTooltipData = ( if (header) { data.push({ label: aspects.x.title, - // already formatted while execiting accessor on such a complex field as `*_range` + // already formatted while executing accessor on such a complex field type as `*_range` value: isSimpleField(aspects.x.format) && aspects.x.formatter ? aspects.x.formatter(header.value) From ce5c1d4ad5dc954f6a8ecb1997759db82f11ec62 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 15:03:32 +0300 Subject: [PATCH 10/43] moved `get_agg_id.ts` util to the vislib --- .../vislib/public/vislib/helpers/point_series/_add_to_siri.ts | 4 +--- .../public/vislib/helpers/point_series}/get_agg_id.ts | 0 src/plugins/vis_types/xy/public/config/index.ts | 1 - src/plugins/vis_types/xy/public/index.ts | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) rename src/plugins/vis_types/{xy/public/config => vislib/public/vislib/helpers/point_series}/get_agg_id.ts (100%) diff --git a/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts index c334a83f3dd6a..1e74ef34705b0 100644 --- a/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts +++ b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/_add_to_siri.ts @@ -5,10 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -import { getAggId } from '../../../../../xy/public'; import type { Dimension } from '../../../../../xy/public'; - +import { getAggId } from './get_agg_id'; import { Point } from './_get_point'; export interface Serie { diff --git a/src/plugins/vis_types/xy/public/config/get_agg_id.ts b/src/plugins/vis_types/vislib/public/vislib/helpers/point_series/get_agg_id.ts similarity index 100% rename from src/plugins/vis_types/xy/public/config/get_agg_id.ts rename to src/plugins/vis_types/vislib/public/vislib/helpers/point_series/get_agg_id.ts diff --git a/src/plugins/vis_types/xy/public/config/index.ts b/src/plugins/vis_types/xy/public/config/index.ts index b00d6aea3d356..348be38924df5 100644 --- a/src/plugins/vis_types/xy/public/config/index.ts +++ b/src/plugins/vis_types/xy/public/config/index.ts @@ -7,4 +7,3 @@ */ export { getConfig } from './get_config'; -export { getAggId } from './get_agg_id'; diff --git a/src/plugins/vis_types/xy/public/index.ts b/src/plugins/vis_types/xy/public/index.ts index 0953183fa1093..e7f9275d9712b 100644 --- a/src/plugins/vis_types/xy/public/index.ts +++ b/src/plugins/vis_types/xy/public/index.ts @@ -31,7 +31,6 @@ export { TruncateLabelsOption } from './editor/components/common/truncate_labels export { getPositions } from './editor/positions'; export { getScaleTypes } from './editor/scale_types'; export { xyVisTypes } from './vis_types'; -export { getAggId } from './config/get_agg_id'; // Export common types export * from '../common'; From 8276a668c6940dffa48c648d6f3aa6b20c3bf7be Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 15:06:26 +0300 Subject: [PATCH 11/43] clearified the code, related to isSimpleField logic. --- .../xy/public/components/detailed_tooltip.tsx | 17 ++++------------- .../vis_types/xy/public/utils/accessors.tsx | 12 ++++++++++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx index aeb18c1555cdf..e74c0254bcccb 100644 --- a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx +++ b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx @@ -17,9 +17,9 @@ import { } from '@elastic/charts'; import { Aspects } from '../types'; +import { applyFormatterIfSimpleField, COMPLEX_SPLIT_ACCESSOR } from '../utils/accessors'; import './_detailed_tooltip.scss'; -import { COMPLEX_SPLIT_ACCESSOR, isSimpleField } from '../utils/accessors'; interface TooltipData { label: string; @@ -37,10 +37,7 @@ export const getTooltipData = ( data.push({ label: aspects.x.title, // already formatted while executing accessor on such a complex field type as `*_range` - value: - isSimpleField(aspects.x.format) && aspects.x.formatter - ? aspects.x.formatter(header.value) - : `${header.value}`, + value: `${applyFormatterIfSimpleField(aspects.x, header.value)}`, }); } @@ -50,20 +47,14 @@ export const getTooltipData = ( if (yAccessor) { data.push({ label: yAccessor.title, - value: - isSimpleField(yAccessor.format) && yAccessor.formatter - ? yAccessor.formatter(value.value) - : `${value.value}`, + value: `${applyFormatterIfSimpleField(yAccessor, value.value)}`, }); } if (aspects.z && !isNil(value.markValue)) { data.push({ label: aspects.z.title, - value: - isSimpleField(aspects.z.format) && aspects.z.formatter - ? aspects.z.formatter(value.markValue) - : `${value.markValue}`, + value: `${applyFormatterIfSimpleField(aspects.z, value.markValue)}`, }); } diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index 28abb69883d79..c17d2b7fbb163 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -37,6 +37,15 @@ export const isSimpleField = (format: Aspect['format']) => { return simpleFormats.includes(format?.id ?? ''); }; +const applyFormatter = (aspect: Aspect, value: unknown, shouldApply: boolean = false) => + shouldApply ? aspect.formatter?.(value) ?? value : value; + +export const applyFormatterIfSimpleField = (aspect: Aspect, value: unknown) => + applyFormatter(aspect, value, isSimpleField(aspect.format)); + +export const applyFormatterIfComplexField = (aspect: Aspect, value: unknown) => + applyFormatter(aspect, value, !isSimpleField(aspect.format)); + /** * Returns accessor function for complex accessor types * @param aspect @@ -49,7 +58,6 @@ export const getComplexAccessor = (fieldName: string) => ( if (!aspect.accessor) { return; } - const formatter = aspect.formatter; const accessor = aspect.accessor; const fn: AccessorFn = (d) => { @@ -57,7 +65,7 @@ export const getComplexAccessor = (fieldName: string) => ( if (v === undefined) { return; } - return isSimpleField(aspect.format) ? v : formatter?.(v) ?? v; + return applyFormatterIfComplexField(aspect, v); }; fn.fieldName = getFieldName(fieldName, index); From ef3dcef88ed16f759800b64eb288d2b0ebe4e5fc Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 15:14:49 +0300 Subject: [PATCH 12/43] added comment. --- src/plugins/vis_types/xy/public/utils/accessors.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index c17d2b7fbb163..49bc15d1075ae 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -43,6 +43,7 @@ const applyFormatter = (aspect: Aspect, value: unknown, shouldApply: boolean = f export const applyFormatterIfSimpleField = (aspect: Aspect, value: unknown) => applyFormatter(aspect, value, isSimpleField(aspect.format)); +// complex field is a field, which has some specific structure, as `range`, for example, not pure value export const applyFormatterIfComplexField = (aspect: Aspect, value: unknown) => applyFormatter(aspect, value, !isSimpleField(aspect.format)); @@ -65,6 +66,11 @@ export const getComplexAccessor = (fieldName: string) => ( if (v === undefined) { return; } + // Because of the specific logic of chart, it cannot compare complex values to display, + // thats why it is necessary to apply formatters before its comparison while rendering. + // What about simple values, formatting them at this step is breaking the logic of intervals (xDomain). + // If the value will be formatted on this step, it will be rendered without any respect to the passed bounds + // and the chart will render not all the range, but only the part of range, which contains data. return applyFormatterIfComplexField(aspect, v); }; From 9909715d3dd588f7ab36195ac98b04286a0927f5 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 16:50:21 +0300 Subject: [PATCH 13/43] Fixed error at percentile agg. --- .../vis_types/xy/public/expression_functions/xy_vis_fn.ts | 7 ++++++- src/plugins/vis_types/xy/public/utils/accessors.tsx | 4 ++++ .../vis_types/xy/public/utils/render_all_series.tsx | 5 ++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index 4806ee5ea937b..adcb6a88e715c 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -16,6 +16,7 @@ import type { import { prepareLogTable, Dimension } from '../../../../visualizations/public'; import type { ChartType } from '../../common'; import type { VisParams, XYVisConfig } from '../types'; +import { isPercentileIdEqualToSeriesId } from '../utils/accessors'; export const visName = 'xy_vis'; export interface RenderValue { @@ -256,7 +257,11 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ valueAxis: args.gridValueAxis, }, seriesParams: args.seriesParams.map((seriesParam) => { - const matchedSeries = args.yDimension.filter((y) => y.id === seriesParam.data.id); + const matchedSeries = args.yDimension.filter( + (y) => + y.id === seriesParam.data.id || + isPercentileIdEqualToSeriesId(y.id ?? '', seriesParam.data.id) + ); return { ...seriesParam, show: matchedSeries.length > 0, diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index 49bc15d1075ae..86ce46e242302 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -93,3 +93,7 @@ export const getSplitSeriesAccessorFnMap = ( return m; }; + +// For percentile aggregation id is comming in the form `%d.%d`, where first `%d` is `id` and the second - `percents` +export const isPercentileIdEqualToSeriesId = (columnId: number | string, seriesColumnId: string) => + columnId.toString().split('.')[0] === seriesColumnId; diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx index d64004a42b146..6c0b537093d22 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -78,13 +78,12 @@ export const renderAllSeries = ( interpolate, type, }) => { - const yAspects = aspects.y.filter(({ accessor, id }) => { - return id === paramId && accessor !== null; - }); + const yAspects = aspects.y.filter(({ accessor }) => accessor !== null); if (!show || !yAspects.length) { return null; } + const yAccessors: string[] = yAspects.map((aspect) => aspect.accessor ?? ''); const id = `${type}-${yAccessors[0]}`; From 4b3496552b3da70dffa92a65461306cfea020b87 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 17:26:03 +0300 Subject: [PATCH 14/43] Fixed render_all_series failure of tests. --- .../xy/public/expression_functions/xy_vis_fn.ts | 8 +++----- src/plugins/vis_types/xy/public/utils/accessors.tsx | 11 +++++++++++ .../vis_types/xy/public/utils/render_all_series.tsx | 5 ++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index adcb6a88e715c..eaa662d39125e 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -16,7 +16,7 @@ import type { import { prepareLogTable, Dimension } from '../../../../visualizations/public'; import type { ChartType } from '../../common'; import type { VisParams, XYVisConfig } from '../types'; -import { isPercentileIdEqualToSeriesId } from '../utils/accessors'; +import { isValidSeriesForDimension } from '../utils/accessors'; export const visName = 'xy_vis'; export interface RenderValue { @@ -257,10 +257,8 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ valueAxis: args.gridValueAxis, }, seriesParams: args.seriesParams.map((seriesParam) => { - const matchedSeries = args.yDimension.filter( - (y) => - y.id === seriesParam.data.id || - isPercentileIdEqualToSeriesId(y.id ?? '', seriesParam.data.id) + const matchedSeries = args.yDimension.filter(({ id, accessor }) => + isValidSeriesForDimension(seriesParam.data.id)({ id, accessor }) ); return { ...seriesParam, diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index 86ce46e242302..4846f601f18e0 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -7,6 +7,7 @@ */ import { AccessorFn, Accessor } from '@elastic/charts'; +import { DatatableColumn } from '../../../../expressions'; import { KBN_FIELD_TYPES } from '../../../../data/public'; import { FakeParams } from '../../../../visualizations/public'; import { Aspect } from '../types'; @@ -97,3 +98,13 @@ export const getSplitSeriesAccessorFnMap = ( // For percentile aggregation id is comming in the form `%d.%d`, where first `%d` is `id` and the second - `percents` export const isPercentileIdEqualToSeriesId = (columnId: number | string, seriesColumnId: string) => columnId.toString().split('.')[0] === seriesColumnId; + +export const isValidSeriesForDimension = (seriesColumnId: string) => ({ + id, + accessor, +}: { + id?: string | number; + accessor?: string | number | DatatableColumn | null; +}) => + (id === seriesColumnId || isPercentileIdEqualToSeriesId(id ?? '', seriesColumnId)) && + accessor !== null; diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx index 6c0b537093d22..535500746fb8d 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -22,6 +22,7 @@ import { import { DatatableRow } from '../../../../expressions/public'; import { ChartType } from '../../common'; import { AxisMode, ChartMode, InterpolationMode, SeriesParam, VisConfig } from '../types'; +import { isValidSeriesForDimension } from './accessors'; /** * Matches vislib curve to elastic charts @@ -78,7 +79,9 @@ export const renderAllSeries = ( interpolate, type, }) => { - const yAspects = aspects.y.filter(({ accessor }) => accessor !== null); + const yAspects = aspects.y.filter(({ id, accessor }) => + isValidSeriesForDimension(paramId)({ id, accessor }) + ); if (!show || !yAspects.length) { return null; From 7dd186a3fd482199f1bd2977186c44d1259336f9 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 2 Sep 2021 17:50:28 +0300 Subject: [PATCH 15/43] Added tests for new behavior. --- .../xy/public/utils/accessors.test.ts | 82 +++++++++++-------- .../vis_types/xy/public/utils/accessors.tsx | 2 +- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/plugins/vis_types/xy/public/utils/accessors.test.ts b/src/plugins/vis_types/xy/public/utils/accessors.test.ts index b2747b8d9bb02..309dd8508f174 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.test.ts +++ b/src/plugins/vis_types/xy/public/utils/accessors.test.ts @@ -8,88 +8,100 @@ import { COMPLEX_SPLIT_ACCESSOR, getComplexAccessor } from './accessors'; import { AccessorFn, Datum } from '@elastic/charts'; +import { KBN_FIELD_TYPES } from '@kbn/field-types'; describe('XY chart datum accessors', () => { + const formatter = (val: Datum) => JSON.stringify(val); const aspectBase = { accessor: 'col-0-2', - formatter: (value: Datum) => value, + formatter, id: '', title: '', params: {}, }; - it('should return complex accessor for IP range aggregation', () => { + const shouldNotApplyFormatterForNotComplexField = (type: string) => { const aspect = { ...aspectBase, + format: { id: type }, + }; + const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); + const val = 'data'; + const datum = { 'col-0-2': val }; + expect(accessor?.(datum)).toBe(val); + }; + + it('should format IP range aggregation', () => { + const aspect = { + ...aspectBase, + format: { id: 'range' }, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); const datum = { 'col-0-2': { type: 'range', from: '0.0.0.0', to: '127.255.255.255' }, }; - expect(typeof accessor).toBe('function'); - expect((accessor as AccessorFn)(datum)).toStrictEqual({ - type: 'range', - from: '0.0.0.0', - to: '127.255.255.255', - }); + expect((accessor as AccessorFn)(datum)).toStrictEqual( + formatter({ + type: 'range', + from: '0.0.0.0', + to: '127.255.255.255', + }) + ); }); - it('should return complex accessor for date range aggregation', () => { + it('should format date range aggregation', () => { const aspect = { ...aspectBase, + format: { id: 'date_range' }, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); const datum = { 'col-0-2': { from: '1613941200000', to: '1614685113537' }, }; - expect(typeof accessor).toBe('function'); - expect((accessor as AccessorFn)(datum)).toStrictEqual({ - from: '1613941200000', - to: '1614685113537', - }); + expect((accessor as AccessorFn)(datum)).toStrictEqual( + formatter({ + from: '1613941200000', + to: '1614685113537', + }) + ); }); - it('should return complex accessor when isComplex option set to true', () => { - const aspect = { - ...aspectBase, - }; - const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); + it(`should not apply formatter for not complex field: ${KBN_FIELD_TYPES.STRING}`, () => + shouldNotApplyFormatterForNotComplexField(KBN_FIELD_TYPES.STRING)); - expect(typeof accessor).toBe('function'); - expect((accessor as AccessorFn)({ 'col-0-2': 'some value' })).toBe('some value'); - }); + it(`should not apply formatter for not complex field: ${KBN_FIELD_TYPES.NUMBER}`, () => + shouldNotApplyFormatterForNotComplexField(KBN_FIELD_TYPES.NUMBER)); - it('should return simple string accessor for not range (date histogram) aggregation', () => { - const aspect = { - ...aspectBase, - }; - const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); + it(`should not apply formatter for not complex field: ${KBN_FIELD_TYPES.DATE}`, () => + shouldNotApplyFormatterForNotComplexField(KBN_FIELD_TYPES.DATE)); - expect(typeof accessor).toBe('string'); - expect(accessor).toBe('col-0-2'); - }); + it(`should not apply formatter for not complex field: ${KBN_FIELD_TYPES.BOOLEAN}`, () => + shouldNotApplyFormatterForNotComplexField(KBN_FIELD_TYPES.BOOLEAN)); - it('should return simple string accessor when aspect has no formatter', () => { + it('should return simple string when aspect has no formatter', () => { const aspect = { ...aspectBase, formatter: undefined, }; const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); - expect(typeof accessor).toBe('string'); - expect(accessor).toBe('col-0-2'); + const val = 'data'; + const datum = { 'col-0-2': val }; + + expect(accessor?.(datum)).toBe(val); }); it('should return undefined when aspect has no accessor', () => { const aspect = { - ...aspectBase, accessor: null, }; + const datum = { 'col-0-2': 'data' }; + const accessor = getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(aspect); - expect(accessor).toBeUndefined(); + expect(accessor?.(datum)).toBeUndefined(); }); }); diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index 4846f601f18e0..ed61e3fde33aa 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -56,7 +56,7 @@ export const applyFormatterIfComplexField = (aspect: Aspect, value: unknown) => export const getComplexAccessor = (fieldName: string) => ( aspect: Aspect, index?: number -): Accessor | AccessorFn | undefined => { +): AccessorFn | undefined => { if (!aspect.accessor) { return; } From a325fe41ca6a780cc9485e5dd998ed1967a0342f Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 3 Sep 2021 12:42:44 +0300 Subject: [PATCH 16/43] changed the way of handling `enableHistogramMode`. --- .../xy/public/components/detailed_tooltip.tsx | 8 ++++++-- src/plugins/vis_types/xy/public/config/get_axis.ts | 11 +++++++---- src/plugins/vis_types/xy/public/config/get_config.ts | 9 ++++++--- .../xy/public/expression_functions/xy_vis_fn.ts | 7 +++++++ src/plugins/vis_types/xy/public/to_ast.ts | 9 +++++++-- src/plugins/vis_types/xy/public/types/param.ts | 2 ++ src/plugins/vis_types/xy/public/utils/accessors.tsx | 2 +- 7 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx index e74c0254bcccb..2292ac213d08f 100644 --- a/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx +++ b/src/plugins/vis_types/xy/public/components/detailed_tooltip.tsx @@ -17,7 +17,11 @@ import { } from '@elastic/charts'; import { Aspects } from '../types'; -import { applyFormatterIfSimpleField, COMPLEX_SPLIT_ACCESSOR } from '../utils/accessors'; +import { + applyFormatterIfSimpleField, + applyFormatter, + COMPLEX_SPLIT_ACCESSOR, +} from '../utils/accessors'; import './_detailed_tooltip.scss'; @@ -47,7 +51,7 @@ export const getTooltipData = ( if (yAccessor) { data.push({ label: yAccessor.title, - value: `${applyFormatterIfSimpleField(yAccessor, value.value)}`, + value: `${applyFormatter(yAccessor, value.value)}`, }); } diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index d73494d5acd50..e32ba302756c4 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -23,14 +23,15 @@ import { YScaleType, SeriesParam, } from '../types'; -import { isSimpleField } from '../utils/accessors'; +import { applyFormatter, isSimpleField } from '../utils/accessors'; export function getAxis( { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, { categoryLines, valueAxis }: Grid, - { params, format, formatter, title: fallbackTitle = '' }: Aspect, + { params, format, formatter, title: fallbackTitle = '', accessor }: Aspect, seriesParams: SeriesParam[], - isDateHistogram = false + isDateHistogram = false, + shouldApplyFormatter = false ): AxisConfig { const isCategoryAxis = type === AxisType.Category; // Hide unassigned axis, not supported in elastic charts @@ -48,7 +49,9 @@ export function getAxis( show: valueAxis === axis.id, }; - const tickFormatter = (v: any) => (isSimpleField(format) ? formatter?.(v) ?? v : v); + const tickFormatter = (v: any) => + isSimpleField(format) || shouldApplyFormatter ? formatter?.(v) ?? v : v; + const ticks: TickOptions = { formatter: tickFormatter, labelFormatter: getLabelFormatter(labels.truncate, tickFormatter), diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index db68ed2b39373..16f267d500a30 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -43,11 +43,14 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { } = params; const aspects = getAspects(table.columns, params.dimensions); const yAxes = params.valueAxes.map((a) => - // uses first y aspect in array for formatting axis - getAxis(a, params.grid, aspects.y[0], params.seriesParams) + // shouldApplyFormatter = true, because no formatter was applied to this axis values before + // and will be not applied in the future + getAxis(a, params.grid, aspects.y[0], params.seriesParams, false, true) ); - const enableHistogramMode = shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); + const enableHistogramMode = + (params.enableHistogramMode ?? false) && + shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); const timeChartFieldTypes: string[] = [KBN_FIELD_TYPES.DATE, KBN_FIELD_TYPES.DATE_RANGE]; const isTimeChart = timeChartFieldTypes.includes(aspects.x.format?.id ?? ''); diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index eaa662d39125e..7072fd522c868 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -154,6 +154,12 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ 'Flag to indicate old vislib visualizations. Used for backwards compatibility including colors', }), }, + enableHistogramMode: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.enableHistogramMode.help', { + defaultMessage: 'Flag to enable histogram mode', + }), + }, detailedTooltip: { types: ['boolean'], help: i18n.translate('visTypeXy.function.args.detailedTooltip.help', { @@ -276,6 +282,7 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ }, fillOpacity: args.fillOpacity, fittingFunction: args.fittingFunction, + enableHistogramMode: args.enableHistogramMode, // @TODO: This part of `VisParams` has special details of esaggs query, but it seems to me, // as a chart, it should know nothing from such information in the purpose of the reusability // with other functions. diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index dbead38442f58..16d9cd18b1738 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -146,8 +146,12 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params const responseAggs = vis.data.aggs?.getResponseAggs().filter(({ enabled }) => enabled) ?? []; - if (dimensions.x) { - const xAgg = responseAggs[dimensions.x.accessor] as any; + const xAgg = dimensions.x ? (responseAggs[dimensions.x?.accessor] as any) : null; + const enableHistogramMode = [BUCKET_TYPES.HISTOGRAM, BUCKET_TYPES.DATE_HISTOGRAM].includes( + xAgg?.type?.name + ); + + if (dimensions.x && xAgg) { if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { (dimensions.x.params as DateHistogramParams).date = true; const { esUnit, esValue } = xAgg.buckets.getInterval(); @@ -231,6 +235,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params seriesDimension: dimensions.series?.map(prepareXYDimension), splitRowDimension: dimensions.splitRow?.map(prepareXYDimension), splitColumnDimension: dimensions.splitColumn?.map(prepareXYDimension), + enableHistogramMode, }); const ast = buildExpression([getEsaggsFn(vis), visTypeXy]); diff --git a/src/plugins/vis_types/xy/public/types/param.ts b/src/plugins/vis_types/xy/public/types/param.ts index c7566ec481bbc..06464afc2aec9 100644 --- a/src/plugins/vis_types/xy/public/types/param.ts +++ b/src/plugins/vis_types/xy/public/types/param.ts @@ -145,6 +145,7 @@ export interface VisParams { palette: PaletteOutput; fillOpacity?: number; fittingFunction?: Exclude; + enableHistogramMode?: boolean; } export interface XYVisConfig { @@ -167,6 +168,7 @@ export interface XYVisConfig { thresholdLine: ExpressionValueThresholdLine; radiusRatio: number; times: ExpressionValueTimeMarker[]; // For compatibility with vislib + enableHistogramMode?: boolean; /** * flag to indicate old vislib visualizations * used for backwards compatibility including colors diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index ed61e3fde33aa..ed7009cbdbe33 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -38,7 +38,7 @@ export const isSimpleField = (format: Aspect['format']) => { return simpleFormats.includes(format?.id ?? ''); }; -const applyFormatter = (aspect: Aspect, value: unknown, shouldApply: boolean = false) => +export const applyFormatter = (aspect: Aspect, value: unknown, shouldApply: boolean = true) => shouldApply ? aspect.formatter?.(value) ?? value : value; export const applyFormatterIfSimpleField = (aspect: Aspect, value: unknown) => From 6a70424058c38fb500f26ba91e9b27c3c16a949a Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 3 Sep 2021 12:58:53 +0300 Subject: [PATCH 17/43] updated snapshots. --- .../vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap | 2 +- .../vislib/public/__snapshots__/to_ast_pie.test.ts.snap | 2 +- .../vis_types/xy/public/__snapshots__/to_ast.test.ts.snap | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap index 233940d97d38a..a4778929ce26b 100644 --- a/src/plugins/vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_types/vislib/public/__snapshots__/to_ast.test.ts.snap @@ -8,7 +8,7 @@ Object { "area", ], "visConfig": Array [ - "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"circlesRadius\\":5,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"truncateLegend\\":true,\\"maxLegendLines\\":1,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"circlesRadius\\":5,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"truncateLegend\\":true,\\"maxLegendLines\\":1,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{},\\"id\\":\\"2\\"},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{},\\"id\\":\\"1\\"}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{},\\"id\\":\\"3\\"}]}}", ], }, "getArgument": [Function], diff --git a/src/plugins/vis_types/vislib/public/__snapshots__/to_ast_pie.test.ts.snap b/src/plugins/vis_types/vislib/public/__snapshots__/to_ast_pie.test.ts.snap index b8dc4b31747c4..72f74418ff6fb 100644 --- a/src/plugins/vis_types/vislib/public/__snapshots__/to_ast_pie.test.ts.snap +++ b/src/plugins/vis_types/vislib/public/__snapshots__/to_ast_pie.test.ts.snap @@ -5,7 +5,7 @@ Object { "addArgument": [Function], "arguments": Object { "visConfig": Array [ - "{\\"type\\":\\"pie\\",\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"right\\",\\"isDonut\\":true,\\"labels\\":{\\"show\\":true,\\"values\\":true,\\"last_level\\":true,\\"truncate\\":100},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\"},\\"params\\":{}},\\"buckets\\":[{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "{\\"type\\":\\"pie\\",\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"right\\",\\"isDonut\\":true,\\"labels\\":{\\"show\\":true,\\"values\\":true,\\"last_level\\":true,\\"truncate\\":100},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\"},\\"params\\":{},\\"id\\":\\"1\\"},\\"buckets\\":[{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{},\\"id\\":\\"2\\"}]}}", ], }, "getArgument": [Function], diff --git a/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap index 7ee1b0d2b2053..0282c6204e41d 100644 --- a/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap @@ -21,6 +21,9 @@ Object { "chartType": Array [ "area", ], + "enableHistogramMode": Array [ + false, + ], "gridCategoryLines": Array [ false, ], From 4fe713ee52ca7cff1657677abf30ab1204d5731c Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 3 Sep 2021 14:15:40 +0300 Subject: [PATCH 18/43] remove not used lib. --- src/plugins/vis_types/xy/public/config/get_axis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index e32ba302756c4..887bc2bce1363 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -23,7 +23,7 @@ import { YScaleType, SeriesParam, } from '../types'; -import { applyFormatter, isSimpleField } from '../utils/accessors'; +import { isSimpleField } from '../utils/accessors'; export function getAxis( { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, From 9803617d64fbb43fac6ad9374a964bed91416c13 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 6 Sep 2021 17:59:20 +0300 Subject: [PATCH 19/43] added XDomain function. --- src/plugins/vis_types/xy/common/index.ts | 2 + .../vis_types/xy/common/utils/index.ts | 9 + .../vis_types/xy/common/utils/intervals.ts | 57 ++++++ .../xy/public/expression_functions/index.ts | 1 + .../public/expression_functions/x_domain.ts | 187 ++++++++++++++++++ .../public/expression_functions/xy_vis_fn.ts | 7 + src/plugins/vis_types/xy/public/plugin.ts | 1 + src/plugins/vis_types/xy/public/to_ast.ts | 45 +++-- .../vis_types/xy/public/types/constants.ts | 6 + .../types/expression_functions/index.ts | 9 + .../types/expression_functions/x_domain.ts | 65 ++++++ .../vis_types/xy/public/types/index.ts | 1 + .../vis_types/xy/public/types/param.ts | 3 + .../vis_types/xy/public/vis_component.tsx | 29 +-- 14 files changed, 387 insertions(+), 35 deletions(-) create mode 100644 src/plugins/vis_types/xy/common/utils/index.ts create mode 100644 src/plugins/vis_types/xy/common/utils/intervals.ts create mode 100644 src/plugins/vis_types/xy/public/expression_functions/x_domain.ts create mode 100644 src/plugins/vis_types/xy/public/types/expression_functions/index.ts create mode 100644 src/plugins/vis_types/xy/public/types/expression_functions/x_domain.ts diff --git a/src/plugins/vis_types/xy/common/index.ts b/src/plugins/vis_types/xy/common/index.ts index a80946f7c62fa..7b4a2ea066cc0 100644 --- a/src/plugins/vis_types/xy/common/index.ts +++ b/src/plugins/vis_types/xy/common/index.ts @@ -21,3 +21,5 @@ export enum ChartType { export type XyVisType = ChartType | 'horizontal_bar'; export const LEGACY_CHARTS_LIBRARY = 'visualization:visualize:legacyChartsLibrary'; + +export { getAdjustedInterval } from './utils'; diff --git a/src/plugins/vis_types/xy/common/utils/index.ts b/src/plugins/vis_types/xy/common/utils/index.ts new file mode 100644 index 0000000000000..9001d26ebc1d7 --- /dev/null +++ b/src/plugins/vis_types/xy/common/utils/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { getAdjustedInterval } from './intervals'; diff --git a/src/plugins/vis_types/xy/common/utils/intervals.ts b/src/plugins/vis_types/xy/common/utils/intervals.ts new file mode 100644 index 0000000000000..3360147eccd74 --- /dev/null +++ b/src/plugins/vis_types/xy/common/utils/intervals.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import moment, { unitOfTime } from 'moment'; + +const findIntervalFromDuration = ( + dateValue: number, + esValue: number, + esUnit: unitOfTime.Base, + timeZone: string +) => { + const date = moment.tz(dateValue, timeZone); + const startOfDate = moment.tz(date, timeZone).startOf(esUnit); + const endOfDate = moment.tz(date, timeZone).startOf(esUnit).add(esValue, esUnit); + return endOfDate.valueOf() - startOfDate.valueOf(); +}; + +const getIntervalInMs = ( + value: number, + esValue: number, + esUnit: unitOfTime.Base, + timeZone: string +): number => { + switch (esUnit) { + case 's': + return 1000 * esValue; + case 'ms': + return 1 * esValue; + default: + return findIntervalFromDuration(value, esValue, esUnit, timeZone); + } +}; + +export const getAdjustedInterval = ( + values: number[], + esValue: number, + esUnit: unitOfTime.Base, + timeZone: string +): number => { + const newInterval = values.reduce((minInterval, currentXvalue, index) => { + let currentDiff = minInterval; + + if (index > 0) { + currentDiff = Math.abs(values[index - 1] - currentXvalue); + } + + const singleUnitInterval = getIntervalInMs(currentXvalue, esValue, esUnit, timeZone); + return Math.min(minInterval, singleUnitInterval, currentDiff); + }, Number.MAX_SAFE_INTEGER); + + return newInterval > 0 ? newInterval : moment.duration(esValue, esUnit).asMilliseconds(); +}; diff --git a/src/plugins/vis_types/xy/public/expression_functions/index.ts b/src/plugins/vis_types/xy/public/expression_functions/index.ts index 32c50e3adff1e..96f327c396dee 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/index.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/index.ts @@ -15,3 +15,4 @@ export { seriesParam, ExpressionValueSeriesParam } from './series_param'; export { thresholdLine, ExpressionValueThresholdLine } from './threshold_line'; export { label, ExpressionValueLabel } from './label'; export { visScale, ExpressionValueScale } from './vis_scale'; +export { xDomain } from './x_domain'; diff --git a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts new file mode 100644 index 0000000000000..2f7a6374440a5 --- /dev/null +++ b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts @@ -0,0 +1,187 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { uniq } from 'lodash'; +import { unitOfTime } from 'moment'; +import { ExpressionValueVisDimension } from '../../../../visualizations/common'; +import type { ExpressionFunctionDefinition, Datatable } from '../../../../expressions/public'; +import { getAdjustedInterval } from '../../common'; +import { XDomainArguments, ExpressionValueXDomain } from '../types'; + +export const getAdjustedDomain = ( + data: Datatable['rows'], + column: ExpressionValueVisDimension, + domain: { + intervalValue: number; + intervalUnit: string; + min: number; + max: number; + minInterval: number; + }, + timezone?: string, + considerInterval?: boolean +) => { + const accessor = typeof column.accessor === 'number' ? column.accessor : column.accessor.id; + const values = uniq(data.map((d) => d[accessor]).sort()); + + const [first] = values; + const last = values[values.length - 1]; + const domainMin = Math.min(first, domain.min); + const domainMaxValue = Math.max(domain.max - domain.minInterval, last); + const domainMax = considerInterval ? domainMaxValue + domain.minInterval : domainMaxValue; + const minInterval = getAdjustedInterval( + values, + domain.intervalValue, + domain.intervalUnit as unitOfTime.Base, + timezone ?? '' + ); + + return { + min: domainMin, + max: domainMax, + minInterval, + }; +}; + +export const xDomain = (): ExpressionFunctionDefinition< + 'x_domain', + Datatable | null, + XDomainArguments, + ExpressionValueXDomain +> => ({ + name: 'x_domain', + help: i18n.translate('visTypeXy.function.valueaxis.help', { + defaultMessage: 'Generates value axis object', + }), + type: 'x_domain', + args: { + minInterval: { + types: ['number'], + help: i18n.translate('visTypeXy.function.xDomain.minInterval.help', { + defaultMessage: 'Min interval', + }), + }, + + intervalUnit: { + types: ['string'], + help: i18n.translate('visTypeXy.function.xDomain.intervalUnit.help', { + defaultMessage: 'intervalUnit', + }), + }, + + intervalValue: { + types: ['number'], + help: i18n.translate('visTypeXy.function.xDomain.intervalValue.help', { + defaultMessage: 'intervalValue', + }), + }, + + column: { + types: ['vis_dimension'], + help: i18n.translate('visTypeXy.function.column.intervalValue.help', { + defaultMessage: 'column', + }), + }, + + timezone: { + types: ['string'], + help: i18n.translate('visTypeXy.function.xDomain.timezone.help', { + defaultMessage: 'timezone', + }), + }, + + considerInterval: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.xDomain.considerInterval.help', { + defaultMessage: 'considerInterval', + }), + }, + + min: { + types: ['number'], + help: i18n.translate('visTypeXy.function.xDomain.min.help', { + defaultMessage: 'min', + }), + }, + + max: { + types: ['number'], + help: i18n.translate('visTypeXy.function.xDomain.max.help', { + defaultMessage: 'max', + }), + }, + + logBase: { + types: ['string'], + help: i18n.translate('visTypeXy.function.xDomain.logBase.help', { + defaultMessage: 'logBase', + }), + }, + + coordinates: { + types: ['string', 'number'], + help: i18n.translate('visTypeXy.function.xDomain.coordinates.help', { + defaultMessage: 'coordinates', + }), + multi: true, + }, + }, + fn: (context, args) => { + const { + min, + max, + minInterval, + logBase, + coordinates, + column, + intervalUnit, + intervalValue, + timezone, + considerInterval, + } = args; + + const domain = { min, max, minInterval, logBase, coordinates }; + const shouldReturnPlainDomain = !( + context?.rows && + column && + intervalUnit && + timezone && + (intervalValue ?? false) && + (min ?? false) && + (max ?? false) + ); + + if (shouldReturnPlainDomain) { + return { + type: 'x_domain', + ...domain, + }; + } + + const adjusted = getAdjustedDomain( + context?.rows, + column, + { + min: min as number, + max: max as number, + minInterval: minInterval as number, + intervalValue: intervalValue as number, + intervalUnit, + }, + timezone, + considerInterval + ); + + return { + type: 'x_domain', + ...domain, + adjusted, + }; + }, +}); diff --git a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts index 7072fd522c868..02c86b349fc0c 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/xy_vis_fn.ts @@ -239,6 +239,12 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ }), multi: true, }, + xDomain: { + types: ['x_domain'], + help: i18n.translate('visTypeXy.function.args.xDomain.help', { + defaultMessage: 'x_domains', + }), + }, }, fn(context, args, handlers) { const visType = args.chartType; @@ -297,6 +303,7 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ splitRow: args.splitRowDimension, splitColumn: args.splitColumnDimension, }, + xDomain: args.xDomain, // ------------------------------------------------------------------------------------------------------------------ } as VisParams; /* @TODO: rewrite this `as VisParams` to real `VisParams` via changing accessor to vis_dimension accessor (accepting string, not only number) */ diff --git a/src/plugins/vis_types/xy/public/plugin.ts b/src/plugins/vis_types/xy/public/plugin.ts index 6245fc37d8d28..d0a312860e070 100644 --- a/src/plugins/vis_types/xy/public/plugin.ts +++ b/src/plugins/vis_types/xy/public/plugin.ts @@ -81,6 +81,7 @@ export class VisTypeXyPlugin expressions.registerFunction(expressionFunctions.thresholdLine); expressions.registerFunction(expressionFunctions.label); expressions.registerFunction(expressionFunctions.visScale); + expressions.registerFunction(expressionFunctions.xDomain); visTypesDefinitions.forEach(visualizations.createBaseVisualization); } diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 16d9cd18b1738..442266e258d7f 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -12,7 +12,6 @@ import { VisToExpressionAst, getVisSchemas, DateHistogramParams, - HistogramParams, } from '../../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { BUCKET_TYPES } from '../../../data/public'; @@ -29,9 +28,10 @@ import { Scale, TimeMarker, AxisMode, + XDomainArguments, } from './types'; import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_functions/xy_vis_fn'; -import { XyVisType } from '../common'; +import { ChartType, XyVisType } from '../common'; import { getEsaggsFn } from './to_ast_esaggs'; import { TimeRangeBounds } from '../../../data/common'; @@ -132,6 +132,17 @@ const prepareXYDimension = (data: Dimension) => { return buildExpression([xyDimension]); }; +const prepareXDomain = (data: XDomainArguments) => { + const column = buildExpressionFunction('visdimension', { accessor: data.column?.accessor }); + + const xDomain = buildExpressionFunction('x_domain', { + ...data, + column, + }); + + return buildExpression([xDomain]); +}; + export const toExpressionAst: VisToExpressionAst = async (vis, params) => { const schemas = getVisSchemas(vis, params); const dimensions: Dimensions = { @@ -151,23 +162,22 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params xAgg?.type?.name ); + const xDomain: XDomainArguments = {}; if (dimensions.x && xAgg) { if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { (dimensions.x.params as DateHistogramParams).date = true; - const { esUnit, esValue } = xAgg.buckets.getInterval(); - (dimensions.x.params as DateHistogramParams).intervalESUnit = esUnit; - (dimensions.x.params as DateHistogramParams).intervalESValue = esValue; - (dimensions.x.params as DateHistogramParams).interval = moment - .duration(esValue, esUnit) - .asMilliseconds(); (dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat(); - const bounds = xAgg.buckets.getBounds() as TimeRangeBounds | undefined; + const { esUnit, esValue } = xAgg.buckets.getInterval(); + + xDomain.intervalValue = esValue; + xDomain.intervalUnit = esUnit; + xDomain.minInterval = moment.duration(esValue, esUnit).asMilliseconds(); + + const bounds = xAgg.buckets.getBounds() as TimeRangeBounds | undefined; if (bounds && bounds?.min && bounds?.max) { - (dimensions.x.params as DateHistogramParams).bounds = { - min: bounds.min.valueOf(), - max: bounds.max.valueOf(), - }; + xDomain.min = bounds.min.valueOf(); + xDomain.max = bounds.max.valueOf(); } } else if (xAgg.type.name === BUCKET_TYPES.HISTOGRAM) { const intervalParam = xAgg.type.paramByName('interval'); @@ -176,7 +186,8 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params abortSignal: params.abortSignal, }); intervalParam.write(xAgg, output); - (dimensions.x.params as HistogramParams).interval = output.params.interval; + + xDomain.minInterval = output.params.interval; } } @@ -204,6 +215,11 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params } }); + const considerInterval = + vis.params.seriesParams.filter((sp) => sp.type === ChartType.Histogram).length > 0; + + xDomain.considerInterval = considerInterval; + const visTypeXy = buildExpressionFunction(visName, { type: vis.type.name as XyVisType, chartType: vis.params.type, @@ -236,6 +252,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params splitRowDimension: dimensions.splitRow?.map(prepareXYDimension), splitColumnDimension: dimensions.splitColumn?.map(prepareXYDimension), enableHistogramMode, + xDomain: prepareXDomain(xDomain), }); const ast = buildExpression([getEsaggsFn(vis), visTypeXy]); diff --git a/src/plugins/vis_types/xy/public/types/constants.ts b/src/plugins/vis_types/xy/public/types/constants.ts index 05ed0783d4c68..f416a9bcccf15 100644 --- a/src/plugins/vis_types/xy/public/types/constants.ts +++ b/src/plugins/vis_types/xy/public/types/constants.ts @@ -46,3 +46,9 @@ export enum ColorMode { Labels = 'Labels', None = 'None', } + +export enum LogBase { + Common = 'common', + Binary = 'binary', + Natural = 'natural', +} diff --git a/src/plugins/vis_types/xy/public/types/expression_functions/index.ts b/src/plugins/vis_types/xy/public/types/expression_functions/index.ts new file mode 100644 index 0000000000000..a69b4412adf4c --- /dev/null +++ b/src/plugins/vis_types/xy/public/types/expression_functions/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './x_domain'; diff --git a/src/plugins/vis_types/xy/public/types/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/types/expression_functions/x_domain.ts new file mode 100644 index 0000000000000..531a8a4dc7c97 --- /dev/null +++ b/src/plugins/vis_types/xy/public/types/expression_functions/x_domain.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ExpressionValueBoxed } from '../../../../../expressions/common'; +import { ExpressionValueVisDimension } from '../../../../../visualizations/common'; +import { LogBase } from '../constants'; + +interface XDomainBase { + minInterval?: number; +} + +type XDomainCommon = { + intervalUnit?: string; + intervalValue?: number; + timezone?: string; + considerInterval?: boolean; + column?: ExpressionValueVisDimension; +} & Partial & + Partial & + XDomainBase; + +interface XDomainMin { + min: number; +} + +interface XDomainMax { + max: number; +} + +interface XDomainLogScale { + logBase?: LogBase; +} + +interface XDomainPlain { + coordinates?: Array; +} + +type XDomainArgs = ( + | XDomainCommon + | (XDomainCommon & XDomainMin) + | (XDomainCommon & XDomainMax) + | (XDomainCommon & XDomainMin & XDomainMax) +) & + XDomainLogScale & + XDomainPlain; + +interface AdjustedXDomain { + adjusted?: XDomainBase & Partial & Partial; +} + +export type XDomainArguments = XDomainArgs; + +export type XDomainOutput = XDomainBase & + Partial & + Partial & + XDomainLogScale & + XDomainPlain & + AdjustedXDomain; + +export type ExpressionValueXDomain = ExpressionValueBoxed<'x_domain', XDomainOutput>; diff --git a/src/plugins/vis_types/xy/public/types/index.ts b/src/plugins/vis_types/xy/public/types/index.ts index 6abbdfabaa956..bd2509da0b330 100644 --- a/src/plugins/vis_types/xy/public/types/index.ts +++ b/src/plugins/vis_types/xy/public/types/index.ts @@ -10,3 +10,4 @@ export * from './constants'; export * from './config'; export * from './param'; export type { VisTypeNames, XyVisTypeDefinition } from './vis_type'; +export * from './expression_functions'; diff --git a/src/plugins/vis_types/xy/public/types/param.ts b/src/plugins/vis_types/xy/public/types/param.ts index 06464afc2aec9..eded05cd83db1 100644 --- a/src/plugins/vis_types/xy/public/types/param.ts +++ b/src/plugins/vis_types/xy/public/types/param.ts @@ -33,6 +33,7 @@ import type { ScaleType, ThresholdLineStyle, } from './constants'; +import { ExpressionValueXDomain, XDomainOutput } from './expression_functions'; export interface Scale { boundsMargin?: number | ''; @@ -146,6 +147,7 @@ export interface VisParams { fillOpacity?: number; fittingFunction?: Exclude; enableHistogramMode?: boolean; + xDomain?: XDomainOutput; } export interface XYVisConfig { @@ -187,4 +189,5 @@ export interface XYVisConfig { seriesDimension?: ExpressionValueXYDimension[]; splitRowDimension?: ExpressionValueXYDimension[]; splitColumnDimension?: ExpressionValueXYDimension[]; + xDomain?: ExpressionValueXDomain; } diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index 7d9fa8762c551..c5750a36b9448 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -35,8 +35,6 @@ import { Datatable, IInterpreterRenderHandlers } from '../../../expressions/publ import type { PersistedState } from '../../../visualizations/public'; import { VisParams } from './types'; import { - getAdjustedDomain, - getXDomain, getTimeZone, renderAllSeries, getSeriesNameFn, @@ -48,7 +46,6 @@ import { import { XYAxis, XYEndzones, XYCurrentTime, XYSettings, XYThresholdLine } from './components'; import { getConfig } from './config'; import { getThemeService, getDataActions, getPalettesService, getActiveCursor } from './services'; -import { ChartType } from '../common'; import './_chart.scss'; import { @@ -211,25 +208,17 @@ const VisComponent = (props: VisComponentProps) => { const config = getConfig(visData, visParams); const timeZone = getTimeZone(); - // @TODO: I think, { min, max, interval? } need to come to props to avoid relations with aggregations const xDomain = - config.xAxis.scale.type === ScaleType.Ordinal ? undefined : getXDomain(config.aspects.x.params); - // ------------------------------------------------------------------------------------------------------- - - // @TODO: move this logic to the `pointseries` function or kind of that to separate - // view from logic of processing the result of fetching. - // This will enable the possibility to reuse `xy_vis` as a rendering function. - const hasBars = visParams.seriesParams.some(({ type }) => type === ChartType.Histogram); - // ------------------------------------------------------------------------------------------------------- - - // @TODO: move this logic from `xy_vis` function and renderer to a separate function, which would proceed - // the result of `esaggs` and pass ready visualization params to `xy_vis` function and renderer as a following step. - // Possibly, it makes sence to move this logic to `pointseries` function. - const adjustedXDomain = config.xAxis.scale.type === ScaleType.Ordinal ? undefined - : getAdjustedDomain(visData.rows, config.aspects.x, timeZone, xDomain, hasBars); - // ------------------------------------------------------------------------------------------------------- + : { + min: visParams.xDomain?.min, + max: visParams.xDomain?.max, + minInterval: visParams.xDomain?.minInterval, + }; + + const adjustedXDomain = + config.xAxis.scale.type === ScaleType.Ordinal ? undefined : visParams.xDomain?.adjusted; const legendPosition = useMemo(() => config.legend.position ?? Position.Right, [ config.legend.position, @@ -291,7 +280,6 @@ const VisComponent = (props: VisComponentProps) => { ] ); - // @TODO: move this logic, related to aggregation types, to the other processing function, out of `xy_vis`. const xAccessor = getXAccessor(config.aspects.x); const splitSeriesAccessors = useMemo( @@ -307,7 +295,6 @@ const VisComponent = (props: VisComponentProps) => { const splitChartRowAccessor = config.aspects.splitRow ? getComplexAccessor(COMPLEX_SPLIT_ACCESSOR)(config.aspects.splitRow) : undefined; - // ------------------------------------------------------------------------------------------------------- const renderSeries = useMemo( () => From 86dd48118cd256253c6c422f6389ba9ba05594aa Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Tue, 7 Sep 2021 11:40:35 +0300 Subject: [PATCH 20/43] Added timezone. --- .../xy/public/expression_functions/x_domain.ts | 11 ++++++++--- src/plugins/vis_types/xy/public/to_ast.ts | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts index 2f7a6374440a5..115361d581df5 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts @@ -27,9 +27,15 @@ export const getAdjustedDomain = ( timezone?: string, considerInterval?: boolean ) => { - const accessor = typeof column.accessor === 'number' ? column.accessor : column.accessor.id; - const values = uniq(data.map((d) => d[accessor]).sort()); + const accessor = column.accessor; + const mapData = (d: Datatable['rows'][0]) => { + if (typeof accessor === 'number') { + return Object.values(d)[accessor]; + } + return d[accessor.id]; + }; + const values = uniq(data.map(mapData).sort()); const [first] = values; const last = values[values.length - 1]; const domainMin = Math.min(first, domain.min); @@ -163,7 +169,6 @@ export const xDomain = (): ExpressionFunctionDefinition< ...domain, }; } - const adjusted = getAdjustedDomain( context?.rows, column, diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 442266e258d7f..2386ef5442dbc 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -12,6 +12,7 @@ import { VisToExpressionAst, getVisSchemas, DateHistogramParams, + ExpressionValueVisDimension, } from '../../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { BUCKET_TYPES } from '../../../data/public'; @@ -34,6 +35,7 @@ import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_fun import { ChartType, XyVisType } from '../common'; import { getEsaggsFn } from './to_ast_esaggs'; import { TimeRangeBounds } from '../../../data/common'; +import { getTimeZone } from './utils'; const prepareLabel = (data: Labels) => { const label = buildExpressionFunction('label', { @@ -133,8 +135,9 @@ const prepareXYDimension = (data: Dimension) => { }; const prepareXDomain = (data: XDomainArguments) => { - const column = buildExpressionFunction('visdimension', { accessor: data.column?.accessor }); - + const column = data.column + ? prepareVisDimension((data.column as unknown) as Dimension) + : undefined; const xDomain = buildExpressionFunction('x_domain', { ...data, column, @@ -165,15 +168,19 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params const xDomain: XDomainArguments = {}; if (dimensions.x && xAgg) { if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { + const timeZone = getTimeZone(); + (dimensions.x.params as DateHistogramParams).date = true; (dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat(); const { esUnit, esValue } = xAgg.buckets.getInterval(); + xDomain.timezone = timeZone; xDomain.intervalValue = esValue; xDomain.intervalUnit = esUnit; xDomain.minInterval = moment.duration(esValue, esUnit).asMilliseconds(); - + // @TODO: rewrite x from Dimension to ExpressionValueVisDimension + xDomain.column = (dimensions.x as unknown) as ExpressionValueVisDimension; const bounds = xAgg.buckets.getBounds() as TimeRangeBounds | undefined; if (bounds && bounds?.min && bounds?.max) { xDomain.min = bounds.min.valueOf(); @@ -215,8 +222,8 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params } }); - const considerInterval = - vis.params.seriesParams.filter((sp) => sp.type === ChartType.Histogram).length > 0; + const considerInterval = !vis.params.seriesParams.filter((sp) => sp.type === ChartType.Histogram) + .length; xDomain.considerInterval = considerInterval; From bfe428bd609567f9eaf26219c8779ae90cda7f83 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Tue, 7 Sep 2021 12:53:34 +0300 Subject: [PATCH 21/43] removed all code, connected to 'interval' --- .../vis_types/xy/public/config/get_axis.ts | 11 ++- .../vis_types/xy/public/config/get_config.ts | 7 +- .../vis_types/xy/public/utils/domain.ts | 82 ------------------- .../vis_types/xy/public/utils/index.tsx | 1 - .../vis_types/xy/public/vis_component.tsx | 2 +- 5 files changed, 10 insertions(+), 93 deletions(-) delete mode 100644 src/plugins/vis_types/xy/public/utils/domain.ts diff --git a/src/plugins/vis_types/xy/public/config/get_axis.ts b/src/plugins/vis_types/xy/public/config/get_axis.ts index 887bc2bce1363..a52a6ef37eee3 100644 --- a/src/plugins/vis_types/xy/public/config/get_axis.ts +++ b/src/plugins/vis_types/xy/public/config/get_axis.ts @@ -24,6 +24,7 @@ import { SeriesParam, } from '../types'; import { isSimpleField } from '../utils/accessors'; +import { ChartType } from '../../common'; export function getAxis( { type, title: axisTitle, labels, scale: axisScale, ...axis }: CategoryAxis, @@ -61,7 +62,10 @@ export function getAxis( showDuplicates: !labels.filter, }; - const scale = getScale(axisScale, params, format, isCategoryAxis); + const isHistogram = seriesParams.filter((sp) => sp.type === ChartType.Histogram).length > 0; + + const scale = getScale(axisScale, params, format, isCategoryAxis, isHistogram); + const title = axisTitle.text || fallbackTitle; const fallbackRotation = isCategoryAxis && isDateHistogram ? LabelRotation.Horizontal : LabelRotation.Vertical; @@ -124,14 +128,15 @@ function getScale( scale: Scale, params: Aspect['params'], format: Aspect['format'], - isCategoryAxis: boolean + isCategoryAxis: boolean, + isHistogram: boolean = false ): ScaleConfig { const type = (isCategoryAxis ? getScaleType( scale, format?.id === 'number' || (format?.params?.id === 'number' && format?.id !== 'range'), 'date' in params, - 'interval' in params + isHistogram ) : getScaleType(scale, true)) as S; diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index 16f267d500a30..19d5520c9aceb 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -11,7 +11,6 @@ import { ScaleContinuousType } from '@elastic/charts'; import { Datatable } from '../../../../expressions/public'; import { KBN_FIELD_TYPES } from '../../../../data/public'; import { - Aspect, AxisConfig, AxisMode, ChartMode, @@ -49,8 +48,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { ); const enableHistogramMode = - (params.enableHistogramMode ?? false) && - shouldEnableHistogramMode(params.seriesParams, aspects.y, yAxes); + (params.enableHistogramMode ?? false) && shouldEnableHistogramMode(params.seriesParams, yAxes); const timeChartFieldTypes: string[] = [KBN_FIELD_TYPES.DATE, KBN_FIELD_TYPES.DATE_RANGE]; const isTimeChart = timeChartFieldTypes.includes(aspects.x.format?.id ?? ''); @@ -96,11 +94,9 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { */ const shouldEnableHistogramMode = ( seriesParams: SeriesParam[], - yAspects: Aspect[], yAxes: Array> ): boolean => { const bars = seriesParams.filter(({ type }) => type === ChartType.Histogram); - const groupIds = [ ...bars.reduce>((acc, { valueAxis: groupId, mode }) => { acc.add(groupId); @@ -114,7 +110,6 @@ const shouldEnableHistogramMode = ( return bars.every(({ valueAxis: groupId, mode }) => { const yAxisScale = yAxes.find(({ groupId: axisGroupId }) => axisGroupId === groupId)?.scale; - return mode === ChartMode.Stacked || yAxisScale?.mode === AxisMode.Percentage; }); }; diff --git a/src/plugins/vis_types/xy/public/utils/domain.ts b/src/plugins/vis_types/xy/public/utils/domain.ts deleted file mode 100644 index fa8dd74e3942a..0000000000000 --- a/src/plugins/vis_types/xy/public/utils/domain.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { uniq } from 'lodash'; -import { unitOfTime } from 'moment'; - -import { DomainRange } from '@elastic/charts'; - -import { getAdjustedInterval } from '../../../../charts/public'; -import { Datatable } from '../../../../expressions/public'; -import { DateHistogramParams, HistogramParams } from '../../../../visualizations/public'; - -import { Aspect } from '../types'; - -export const getXDomain = (params: Aspect['params']): DomainRange => { - const minInterval = (params as DateHistogramParams | HistogramParams)?.interval ?? undefined; - const bounds = (params as DateHistogramParams).date - ? (params as DateHistogramParams).bounds - : null; - - if (bounds) { - return { - min: bounds.min as number, - max: bounds.max as number, - minInterval, - }; - } - - return { - minInterval, - }; -}; - -export const getAdjustedDomain = ( - data: Datatable['rows'], - { accessor, params }: Aspect, - timeZone: string, - domain: DomainRange | undefined, - hasBars?: boolean -): DomainRange => { - if ( - accessor && - domain && - 'min' in domain && - 'max' in domain && - 'intervalESValue' in params && - 'intervalESUnit' in params - ) { - const { interval, intervalESValue, intervalESUnit } = params; - const xValues = uniq(data.map((d) => d[accessor]).sort()); - - const [firstXValue] = xValues; - const lastXValue = xValues[xValues.length - 1]; - - const domainMin = Math.min(firstXValue, domain.min); - const domainMaxValue = Math.max(domain.max - interval, lastXValue); - const domainMax = hasBars ? domainMaxValue : domainMaxValue + interval; - const minInterval = getAdjustedInterval( - xValues, - intervalESValue, - intervalESUnit as unitOfTime.Base, - timeZone - ); - - return { - min: domainMin, - max: domainMax, - minInterval, - }; - } - - return 'interval' in params - ? { - minInterval: params.interval, - } - : {}; -}; diff --git a/src/plugins/vis_types/xy/public/utils/index.tsx b/src/plugins/vis_types/xy/public/utils/index.tsx index d68a6e8068fa8..720c8f9e6f947 100644 --- a/src/plugins/vis_types/xy/public/utils/index.tsx +++ b/src/plugins/vis_types/xy/public/utils/index.tsx @@ -10,7 +10,6 @@ export { renderAllSeries } from './render_all_series'; export { getTimeZone } from './get_time_zone'; export { getLegendActions } from './get_legend_actions'; export { getSeriesNameFn } from './get_series_name_fn'; -export { getXDomain, getAdjustedDomain } from './domain'; export { getColorPicker } from './get_color_picker'; export { getXAccessor } from './accessors'; export { getAllSeries } from './get_all_series'; diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index c5750a36b9448..a36fadb5c693a 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -367,7 +367,7 @@ const VisComponent = (props: VisComponentProps) => { splitSeriesAccessors, splitChartColumnAccessor ?? splitChartRowAccessor )} - onBrushEnd={handleBrush(visData, xAccessor, 'interval' in config.aspects.x.params)} + onBrushEnd={handleBrush(visData, xAccessor, visParams.xDomain?.minInterval !== undefined)} onRenderChange={onRenderChange} legendAction={ config.aspects.series && (config.aspects.series?.length ?? 0) > 0 From 5ff3a002f1f916288c1951703b761994eee593c4 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Tue, 7 Sep 2021 16:11:07 +0300 Subject: [PATCH 22/43] Fixed types at to_ast.ts. --- .../data/common/search/aggs/agg_config.ts | 2 + .../public/expression_functions/x_domain.ts | 11 +-- src/plugins/vis_types/xy/public/to_ast.ts | 78 ++++++++++++------- .../vis_types/xy/public/types/param.ts | 12 +-- .../vis_types/xy/public/utils/accessors.tsx | 26 ++++++- .../vis_types/xy/public/vis_component.tsx | 5 +- .../expression_functions/xy_dimension.ts | 2 +- 7 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/plugins/data/common/search/aggs/agg_config.ts b/src/plugins/data/common/search/aggs/agg_config.ts index 1a70a41e72dd5..0ddddea890294 100644 --- a/src/plugins/data/common/search/aggs/agg_config.ts +++ b/src/plugins/data/common/search/aggs/agg_config.ts @@ -23,6 +23,7 @@ import { IAggType } from './agg_type'; import { writeParams } from './agg_params'; import { IAggConfigs } from './agg_configs'; import { parseTimeShift } from './utils'; +import { TimeBuckets } from './buckets/lib/time_buckets'; /** @public **/ export type AggConfigSerialized = Ensure< @@ -92,6 +93,7 @@ export class AggConfig { public parent?: IAggConfigs; public brandNew?: boolean; public schema?: string; + public buckets?: TimeBuckets; private __type: IAggType; private __typeDecorations: any; diff --git a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts index 115361d581df5..fe6b5859cc0d1 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts @@ -13,6 +13,7 @@ import { ExpressionValueVisDimension } from '../../../../visualizations/common'; import type { ExpressionFunctionDefinition, Datatable } from '../../../../expressions/public'; import { getAdjustedInterval } from '../../common'; import { XDomainArguments, ExpressionValueXDomain } from '../types'; +import { getValueByAccessor } from '../utils/accessors'; export const getAdjustedDomain = ( data: Datatable['rows'], @@ -27,15 +28,7 @@ export const getAdjustedDomain = ( timezone?: string, considerInterval?: boolean ) => { - const accessor = column.accessor; - const mapData = (d: Datatable['rows'][0]) => { - if (typeof accessor === 'number') { - return Object.values(d)[accessor]; - } - return d[accessor.id]; - }; - - const values = uniq(data.map(mapData).sort()); + const values = uniq(data.map((row) => getValueByAccessor(row, column.accessor)).sort()); const [first] = values; const last = values[values.length - 1]; const domainMin = Math.min(first, domain.min); diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index 2386ef5442dbc..7d200ab4ede52 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -13,6 +13,7 @@ import { getVisSchemas, DateHistogramParams, ExpressionValueVisDimension, + SchemaConfig, } from '../../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; import { BUCKET_TYPES } from '../../../data/public'; @@ -20,7 +21,6 @@ import { Labels } from '../../../charts/public'; import { Dimensions, - Dimension, VisParams, CategoryAxis, SeriesParam, @@ -30,12 +30,18 @@ import { TimeMarker, AxisMode, XDomainArguments, + Dimension, } from './types'; import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_functions/xy_vis_fn'; import { ChartType, XyVisType } from '../common'; import { getEsaggsFn } from './to_ast_esaggs'; import { TimeRangeBounds } from '../../../data/common'; import { getTimeZone } from './utils'; +import { getColumnByAccessor } from './utils/accessors'; + +type XDomainPreArgs = Omit & { + column?: XDomainArguments['column']; +}; const prepareLabel = (data: Labels) => { const label = buildExpressionFunction('label', { @@ -112,7 +118,7 @@ const prepareSeriesParam = (data: SeriesParam) => { return buildExpression([seriesParam]); }; -const prepareVisDimension = (data: Dimension) => { +const prepareVisDimension = >(data: T) => { const visDimension = buildExpressionFunction('visdimension', { accessor: data.accessor }); if (data.format) { @@ -123,21 +129,25 @@ const prepareVisDimension = (data: Dimension) => { return buildExpression([visDimension]); }; -const prepareXYDimension = (data: Dimension) => { +const prepareXYDimension = (data: T) => { const xyDimension = buildExpressionFunction('xydimension', { params: JSON.stringify(data.params), label: data.label, - visDimension: prepareVisDimension(data), + visDimension: prepareVisDimension({ + ...data, + format: { + ...data.format, + params: data.format.params ?? {}, + }, + }), id: data.id, }); return buildExpression([xyDimension]); }; -const prepareXDomain = (data: XDomainArguments) => { - const column = data.column - ? prepareVisDimension((data.column as unknown) as Dimension) - : undefined; +const prepareXDomain = (data: XDomainPreArgs) => { + const column = data.column ? prepareVisDimension(data.column) : undefined; const xDomain = buildExpressionFunction('x_domain', { ...data, column, @@ -146,42 +156,54 @@ const prepareXDomain = (data: XDomainArguments) => { return buildExpression([xDomain]); }; +const getDimensionFromSchemaConfig = (schemaConfig: SchemaConfig): Dimension => ({ + ...schemaConfig, + params: {}, +}); + export const toExpressionAst: VisToExpressionAst = async (vis, params) => { const schemas = getVisSchemas(vis, params); const dimensions: Dimensions = { - x: schemas.segment ? schemas.segment[0] : null, - y: schemas.metric, - z: schemas.radius, - width: schemas.width, - series: schemas.group, - splitRow: schemas.split_row, - splitColumn: schemas.split_column, + x: schemas.segment ? getDimensionFromSchemaConfig(schemas.segment[0]) : null, + y: schemas.metric.map(getDimensionFromSchemaConfig), + z: schemas.radius?.map(getDimensionFromSchemaConfig), + width: schemas.width?.map(getDimensionFromSchemaConfig), + series: schemas.group?.map(getDimensionFromSchemaConfig), + splitRow: schemas.split_row?.map(getDimensionFromSchemaConfig), + splitColumn: schemas.split_column?.map(getDimensionFromSchemaConfig), }; const responseAggs = vis.data.aggs?.getResponseAggs().filter(({ enabled }) => enabled) ?? []; - const xAgg = dimensions.x ? (responseAggs[dimensions.x?.accessor] as any) : null; - const enableHistogramMode = [BUCKET_TYPES.HISTOGRAM, BUCKET_TYPES.DATE_HISTOGRAM].includes( - xAgg?.type?.name - ); + const xAgg = dimensions.x ? getColumnByAccessor(responseAggs, dimensions.x?.accessor) : null; + + const enableHistogramMode = ([ + BUCKET_TYPES.HISTOGRAM, + BUCKET_TYPES.DATE_HISTOGRAM, + ] as string[]).includes(xAgg?.type?.name ?? ''); + + const xDomain: XDomainPreArgs = {}; + if (dimensions.x && !dimensions.x.params) { + dimensions.x.params = {}; + } - const xDomain: XDomainArguments = {}; if (dimensions.x && xAgg) { if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { const timeZone = getTimeZone(); (dimensions.x.params as DateHistogramParams).date = true; - (dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat(); + (dimensions.x.params as DateHistogramParams).format = + xAgg.buckets?.getScaledDateFormat() ?? ''; - const { esUnit, esValue } = xAgg.buckets.getInterval(); + const { esUnit, esValue } = xAgg.buckets?.getInterval() ?? {}; xDomain.timezone = timeZone; xDomain.intervalValue = esValue; xDomain.intervalUnit = esUnit; xDomain.minInterval = moment.duration(esValue, esUnit).asMilliseconds(); - // @TODO: rewrite x from Dimension to ExpressionValueVisDimension - xDomain.column = (dimensions.x as unknown) as ExpressionValueVisDimension; - const bounds = xAgg.buckets.getBounds() as TimeRangeBounds | undefined; + + const bounds = xAgg.buckets?.getBounds() as TimeRangeBounds | undefined; + if (bounds && bounds?.min && bounds?.max) { xDomain.min = bounds.min.valueOf(); xDomain.max = bounds.max.valueOf(); @@ -189,17 +211,17 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params } else if (xAgg.type.name === BUCKET_TYPES.HISTOGRAM) { const intervalParam = xAgg.type.paramByName('interval'); const output = { params: {} as any }; - await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, { + await intervalParam?.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, { abortSignal: params.abortSignal, }); - intervalParam.write(xAgg, output); + intervalParam?.write(xAgg, output); xDomain.minInterval = output.params.interval; } } (dimensions.y || []).forEach((yDimension) => { - const yAgg = responseAggs[yDimension.accessor]; + const yAgg = getColumnByAccessor(responseAggs, yDimension.accessor); const seriesParam = (vis.params.seriesParams || []).find( (param: any) => param.data.id === yAgg.id ); diff --git a/src/plugins/vis_types/xy/public/types/param.ts b/src/plugins/vis_types/xy/public/types/param.ts index eded05cd83db1..684ba2fcbe2e1 100644 --- a/src/plugins/vis_types/xy/public/types/param.ts +++ b/src/plugins/vis_types/xy/public/types/param.ts @@ -8,13 +8,7 @@ import type { Fit, Position } from '@elastic/charts'; import type { Style, Labels, PaletteOutput } from '../../../../charts/public'; -import type { - SchemaConfig, - ExpressionValueXYDimension, - FakeParams, - HistogramParams, - DateHistogramParams, -} from '../../../../visualizations/public'; +import type { ExpressionValueXYDimension } from '../../../../visualizations/public'; import type { ChartType, XyVisType } from '../../common'; import type { ExpressionValueCategoryAxis, @@ -102,9 +96,7 @@ export interface TimeMarker { width?: number; } -export type Dimension = Omit & { - params: DateHistogramParams | HistogramParams | FakeParams | {}; -} & { params: { integersOnly?: boolean } }; +export type Dimension = Omit; export interface Dimensions { x: Dimension | null; diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index ed7009cbdbe33..322d4054238b3 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -7,9 +7,9 @@ */ import { AccessorFn, Accessor } from '@elastic/charts'; -import { DatatableColumn } from '../../../../expressions'; +import { Datatable, DatatableColumn } from '../../../../expressions'; import { KBN_FIELD_TYPES } from '../../../../data/public'; -import { FakeParams } from '../../../../visualizations/public'; +import { ExpressionValueVisDimension, FakeParams } from '../../../../visualizations/public'; import { Aspect } from '../types'; export const COMPLEX_X_ACCESSOR = '__customXAccessor__'; @@ -108,3 +108,25 @@ export const isValidSeriesForDimension = (seriesColumnId: string) => ({ }) => (id === seriesColumnId || isPercentileIdEqualToSeriesId(id ?? '', seriesColumnId)) && accessor !== null; + +export const getValueByAccessor = ( + data: Datatable['rows'][0], + accessor: ExpressionValueVisDimension['accessor'] +) => { + if (typeof accessor === 'number') { + return Object.values(data)[accessor]; + } + + return data[accessor.id]; +}; + +export const getColumnByAccessor = ( + columns: T[], + accessor: ExpressionValueVisDimension['accessor'] +) => { + if (typeof accessor === 'number') { + return columns[accessor]; + } + + return columns.filter((col) => col.id === accessor.id)[0]; +}; diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index a36fadb5c693a..42452e9d079dd 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -50,6 +50,7 @@ import { getThemeService, getDataActions, getPalettesService, getActiveCursor } import './_chart.scss'; import { COMPLEX_SPLIT_ACCESSOR, + getColumnByAccessor, getComplexAccessor, getSplitSeriesAccessorFnMap, } from './utils/accessors'; @@ -333,9 +334,9 @@ const VisComponent = (props: VisComponentProps) => { ); const splitChartDimension = visParams.dimensions.splitColumn - ? visData.columns[visParams.dimensions.splitColumn[0].accessor] + ? getColumnByAccessor(visData.columns, visParams.dimensions.splitColumn[0].accessor) : visParams.dimensions.splitRow - ? visData.columns[visParams.dimensions.splitRow[0].accessor] + ? getColumnByAccessor(visData.columns, visParams.dimensions.splitRow[0].accessor) : undefined; return ( diff --git a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts index 0d6bb2ee5e962..1ad50883e3478 100644 --- a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts +++ b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts @@ -49,7 +49,7 @@ export type ExpressionValueXYDimension = ExpressionValueBoxed< 'xy_dimension', { label: string; - aggType: string; + aggType?: string; params: DateHistogramParams | HistogramParams | FakeParams | {}; accessor: number | DatatableColumn; format: SerializedFieldFormat; From f4ea45c1f873033cdee2ef02b05a32b266a0115e Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Tue, 7 Sep 2021 16:46:58 +0300 Subject: [PATCH 23/43] updated tests. --- .../public/__snapshots__/to_ast.test.ts.snap | 5 ++++ .../components/detailed_tooltip.mock.ts | 9 ------- .../vis_types/xy/public/config/get_config.ts | 1 + .../xy/public/sample_vis.test.mocks.ts | 1 - .../vis_types/xy/public/types/config.ts | 2 ++ .../public/utils/get_series_name_fn.test.ts | 3 --- .../utils/render_all_series.test.mocks.ts | 27 ++++++++++++------- .../vis_types/xy/public/vis_component.tsx | 8 +++--- .../expression_functions/xy_dimension.ts | 3 --- 9 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap index 0282c6204e41d..3692dfd76e30c 100644 --- a/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap @@ -73,6 +73,11 @@ Object { "toAst": [Function], }, ], + "xDomain": Array [ + Object { + "toAst": [Function], + }, + ], "yDimension": Array [ Object { "toAst": [Function], diff --git a/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts b/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts index b366074d5f085..2ef58537b012d 100644 --- a/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts +++ b/src/plugins/vis_types/xy/public/components/detailed_tooltip.mock.ts @@ -20,9 +20,6 @@ export const aspects = { id: '3', params: { date: true, - intervalESUnit: 'h', - intervalESValue: 3, - interval: 10800000, format: 'YYYY-MM-DD HH:mm', }, }, @@ -54,9 +51,6 @@ export const aspectsWithSplitColumn = { id: '3', params: { date: true, - intervalESUnit: 'h', - intervalESValue: 3, - interval: 10800000, format: 'YYYY-MM-DD HH:mm', }, }, @@ -103,9 +97,6 @@ export const aspectsWithSplitRow = { id: '3', params: { date: true, - intervalESUnit: 'h', - intervalESValue: 3, - interval: 10800000, format: 'YYYY-MM-DD HH:mm', }, }, diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index 19d5520c9aceb..cd8d6d5b301a4 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -82,6 +82,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { legend: getLegend(params), rotation: getRotation(params.categoryAxes[0]), thresholdLine: getThresholdLine(thresholdLine, yAxes, params.seriesParams), + xDomain: params.xDomain, }; } diff --git a/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts index 307da89b0a7e6..5b770afb86a66 100644 --- a/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts @@ -281,7 +281,6 @@ export const sampleAreaVis = { }, params: { date: true, - interval: 43200000, format: 'YYYY-MM-DD HH:mm', bounds: { min: '2020-09-30T12:41:13.795Z', diff --git a/src/plugins/vis_types/xy/public/types/config.ts b/src/plugins/vis_types/xy/public/types/config.ts index 6120ef08dfbc4..6f8dd58ac0876 100644 --- a/src/plugins/vis_types/xy/public/types/config.ts +++ b/src/plugins/vis_types/xy/public/types/config.ts @@ -19,6 +19,7 @@ import { TooltipValueFormatter, YDomainRange, } from '@elastic/charts'; +import { XDomainOutput } from './expression_functions'; import type { Dimension, Scale, ThresholdLine } from './param'; @@ -118,4 +119,5 @@ export interface VisConfig { fillOpacity?: number; detailedTooltip?: boolean; isVislibVis?: boolean; + xDomain?: XDomainOutput; } diff --git a/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts b/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts index 32f5360415e06..bb48bbdabdbaf 100644 --- a/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts +++ b/src/plugins/vis_types/xy/public/utils/get_series_name_fn.test.ts @@ -40,9 +40,6 @@ const aspects = { id: '2', params: { date: true, - intervalESUnit: 'd', - intervalESValue: 1, - interval: 86400000, format: 'YYYY-MM-DD', }, }, diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts index d3898dbf82b0d..7c2f7d63cc7e9 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.test.mocks.ts @@ -20,6 +20,12 @@ export const getVisConfig = (): VisConfig => { tooltip: { type: 'vertical', }, + xDomain: { + minInterval: 60000, + adjusted: { + minInterval: 60000, + }, + }, aspects: { x: { accessor: 'col-0-2', @@ -34,9 +40,6 @@ export const getVisConfig = (): VisConfig => { id: '2', params: { date: true, - intervalESUnit: 'm', - intervalESValue: 1, - interval: 60000, format: 'HH:mm', }, }, @@ -141,6 +144,12 @@ export const getVisConfigMutipleYaxis = (): VisConfig => { tooltip: { type: 'vertical', }, + xDomain: { + minInterval: 60000, + adjusted: { + minInterval: 60000, + }, + }, aspects: { x: { accessor: 'col-0-2', @@ -155,9 +164,6 @@ export const getVisConfigMutipleYaxis = (): VisConfig => { id: '2', params: { date: true, - intervalESUnit: 'm', - intervalESValue: 1, - interval: 60000, format: 'HH:mm', }, }, @@ -272,6 +278,12 @@ export const getVisConfigPercentiles = (): VisConfig => { tooltip: { type: 'vertical', }, + xDomain: { + minInterval: 60000, + adjusted: { + minInterval: 60000, + }, + }, aspects: { x: { accessor: 'col-0-2', @@ -286,9 +298,6 @@ export const getVisConfigPercentiles = (): VisConfig => { id: '2', params: { date: true, - intervalESUnit: 'm', - intervalESValue: 1, - interval: 60000, format: 'HH:mm', }, }, diff --git a/src/plugins/vis_types/xy/public/vis_component.tsx b/src/plugins/vis_types/xy/public/vis_component.tsx index 42452e9d079dd..c6eee0c523952 100644 --- a/src/plugins/vis_types/xy/public/vis_component.tsx +++ b/src/plugins/vis_types/xy/public/vis_component.tsx @@ -213,13 +213,13 @@ const VisComponent = (props: VisComponentProps) => { config.xAxis.scale.type === ScaleType.Ordinal ? undefined : { - min: visParams.xDomain?.min, - max: visParams.xDomain?.max, - minInterval: visParams.xDomain?.minInterval, + min: config.xDomain?.min, + max: config.xDomain?.max, + minInterval: config.xDomain?.minInterval, }; const adjustedXDomain = - config.xAxis.scale.type === ScaleType.Ordinal ? undefined : visParams.xDomain?.adjusted; + config.xAxis.scale.type === ScaleType.Ordinal ? undefined : config.xDomain?.adjusted; const legendPosition = useMemo(() => config.legend.position ?? Position.Right, [ config.legend.position, diff --git a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts index 1ad50883e3478..c50311358ff50 100644 --- a/src/plugins/visualizations/common/expression_functions/xy_dimension.ts +++ b/src/plugins/visualizations/common/expression_functions/xy_dimension.ts @@ -19,9 +19,6 @@ import type { export interface DateHistogramParams { date: boolean; - interval: number; - intervalESValue: number; - intervalESUnit: string; format: string; bounds?: { min: string | number; From 38d066cbe782c62707527e35b4219ff94cd6fc21 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Tue, 7 Sep 2021 16:49:40 +0300 Subject: [PATCH 24/43] Fixed types errors. --- src/plugins/vis_types/xy/public/config/get_aspects.ts | 5 +++-- .../vis_types/xy/public/expression_functions/x_domain.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/vis_types/xy/public/config/get_aspects.ts b/src/plugins/vis_types/xy/public/config/get_aspects.ts index e5ad75d5bcccf..272479b8e5a81 100644 --- a/src/plugins/vis_types/xy/public/config/get_aspects.ts +++ b/src/plugins/vis_types/xy/public/config/get_aspects.ts @@ -14,6 +14,7 @@ import { DatatableColumn } from '../../../../expressions/public'; import { Aspect, Dimension, Aspects, Dimensions } from '../types'; import { getFormatService } from '../services'; +import { getColumnByAccessor } from '../utils/accessors'; export function getEmptyAspect(): Aspect { return { @@ -61,13 +62,13 @@ function getAspectsFromDimension( if (Array.isArray(dimensions)) { return compact( dimensions.map((d) => { - const column = d && columns[d.accessor]; + const column = d && getColumnByAccessor(columns, d.accessor); return column && getAspect(column, d); }) ); } - const column = columns[dimensions.accessor]; + const column = getColumnByAccessor(columns, dimensions.accessor); return column && getAspect(column, dimensions); } diff --git a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts index fe6b5859cc0d1..0622448da0491 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts @@ -163,7 +163,7 @@ export const xDomain = (): ExpressionFunctionDefinition< }; } const adjusted = getAdjustedDomain( - context?.rows, + context?.rows ?? [], column, { min: min as number, From 10d17a38df4c3f37b04ab94a4d9dda2d119c5dc9 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Wed, 8 Sep 2021 10:11:31 +0300 Subject: [PATCH 25/43] updated code of x_domain. --- .../public/expression_functions/x_domain.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts index 0622448da0491..059d5e86c8609 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts @@ -15,6 +15,8 @@ import { getAdjustedInterval } from '../../common'; import { XDomainArguments, ExpressionValueXDomain } from '../types'; import { getValueByAccessor } from '../utils/accessors'; +export const X_DOMAIN_EXPRESSION = 'x_domain'; + export const getAdjustedDomain = ( data: Datatable['rows'], column: ExpressionValueVisDimension, @@ -54,11 +56,11 @@ export const xDomain = (): ExpressionFunctionDefinition< XDomainArguments, ExpressionValueXDomain > => ({ - name: 'x_domain', + name: X_DOMAIN_EXPRESSION, help: i18n.translate('visTypeXy.function.valueaxis.help', { defaultMessage: 'Generates value axis object', }), - type: 'x_domain', + type: X_DOMAIN_EXPRESSION, args: { minInterval: { types: ['number'], @@ -146,30 +148,28 @@ export const xDomain = (): ExpressionFunctionDefinition< } = args; const domain = { min, max, minInterval, logBase, coordinates }; - const shouldReturnPlainDomain = !( + const shouldReturnAdjustedDomain = context?.rows && column && intervalUnit && timezone && - (intervalValue ?? false) && - (min ?? false) && - (max ?? false) - ); + intervalValue !== undefined && + min !== undefined && + max !== undefined && + minInterval !== undefined; - if (shouldReturnPlainDomain) { - return { - type: 'x_domain', - ...domain, - }; + if (!shouldReturnAdjustedDomain) { + return { type: X_DOMAIN_EXPRESSION, ...domain }; } + const adjusted = getAdjustedDomain( context?.rows ?? [], column, { - min: min as number, - max: max as number, - minInterval: minInterval as number, - intervalValue: intervalValue as number, + min, + max, + minInterval, + intervalValue, intervalUnit, }, timezone, @@ -177,7 +177,7 @@ export const xDomain = (): ExpressionFunctionDefinition< ); return { - type: 'x_domain', + type: X_DOMAIN_EXPRESSION, ...domain, adjusted, }; From 5b0fd1c06d4e2bb3ed837b3ac8a2bbd815359d9c Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 10 Sep 2021 16:15:49 +0300 Subject: [PATCH 26/43] Applied enableHistogramMode for single bars. --- .../vis_types/xy/public/config/get_config.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index cd8d6d5b301a4..946ca79ba8043 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -97,13 +97,15 @@ const shouldEnableHistogramMode = ( seriesParams: SeriesParam[], yAxes: Array> ): boolean => { - const bars = seriesParams.filter(({ type }) => type === ChartType.Histogram); - const groupIds = [ - ...bars.reduce>((acc, { valueAxis: groupId, mode }) => { - acc.add(groupId); - return acc; - }, new Set()), - ]; + const bars = seriesParams.filter(({ type, show }) => show && type === ChartType.Histogram); + const groupsCount = bars.reduce>((acc, { valueAxis: groupId }) => { + acc[groupId] = (acc[groupId] ?? 0) + 1; + return acc; + }, {}); + + const groupIds = Object.keys(groupsCount) + .filter((groupId) => groupsCount[groupId] > 1) + .map((groupId) => groupsCount[groupId]); if (groupIds.length > 1) { return false; From bea0dbde44a5063201607b706d53ff5898099bbb Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 13 Sep 2021 10:07:43 +0300 Subject: [PATCH 27/43] added fix for histogram mode. --- src/plugins/vis_types/xy/public/config/get_config.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plugins/vis_types/xy/public/config/get_config.ts b/src/plugins/vis_types/xy/public/config/get_config.ts index 946ca79ba8043..0dca64e49b261 100644 --- a/src/plugins/vis_types/xy/public/config/get_config.ts +++ b/src/plugins/vis_types/xy/public/config/get_config.ts @@ -103,9 +103,14 @@ const shouldEnableHistogramMode = ( return acc; }, {}); - const groupIds = Object.keys(groupsCount) - .filter((groupId) => groupsCount[groupId] > 1) - .map((groupId) => groupsCount[groupId]); + const groupIds = Object.keys(groupsCount); + + const singleBarGroupIds = groupIds.filter((groupId) => groupsCount[groupId] === 1); + const stackedGroupIds = groupIds.filter((groupId) => groupsCount[groupId] > 1); + + if (!stackedGroupIds.length && singleBarGroupIds.length === 1) { + return true; + } if (groupIds.length > 1) { return false; From 566c1d1de8996c19d689420818b77a10eea3860b Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 13 Sep 2021 11:38:22 +0300 Subject: [PATCH 28/43] Fixed types error at `x_domain`. --- .../public/expression_functions/x_domain.ts | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts index 059d5e86c8609..a285df4f4b2af 100644 --- a/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts +++ b/src/plugins/vis_types/xy/public/expression_functions/x_domain.ts @@ -148,38 +148,37 @@ export const xDomain = (): ExpressionFunctionDefinition< } = args; const domain = { min, max, minInterval, logBase, coordinates }; - const shouldReturnAdjustedDomain = + + if ( context?.rows && - column && intervalUnit && timezone && intervalValue !== undefined && min !== undefined && max !== undefined && - minInterval !== undefined; - - if (!shouldReturnAdjustedDomain) { - return { type: X_DOMAIN_EXPRESSION, ...domain }; + minInterval !== undefined && + column !== undefined + ) { + const adjusted = getAdjustedDomain( + context?.rows ?? [], + column, + { + min, + max, + minInterval, + intervalValue, + intervalUnit, + }, + timezone, + considerInterval + ); + + return { + type: X_DOMAIN_EXPRESSION, + ...domain, + adjusted, + }; } - - const adjusted = getAdjustedDomain( - context?.rows ?? [], - column, - { - min, - max, - minInterval, - intervalValue, - intervalUnit, - }, - timezone, - considerInterval - ); - - return { - type: X_DOMAIN_EXPRESSION, - ...domain, - adjusted, - }; + return { type: X_DOMAIN_EXPRESSION, ...domain }; }, }); From 7139a7169a3cf047b4e9f9f14689e5e653c357dd Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 13 Sep 2021 15:15:26 +0300 Subject: [PATCH 29/43] Removed references to xy types at vislib. --- .../vis_types/vislib/public/constants.ts | 48 ++++++++++ .../editor/components/heatmap/index.tsx | 2 +- .../components/heatmap/labels_panel.tsx | 2 +- .../vis_types/vislib/public/heatmap.ts | 3 +- src/plugins/vis_types/vislib/public/to_ast.ts | 10 +- src/plugins/vis_types/vislib/public/types.ts | 96 +++++++++++++++++-- .../vislib/public/vislib/helpers/accessor.ts | 31 ++++++ .../build_hierarchical_data.test.ts | 7 +- .../hierarchical/build_hierarchical_data.ts | 19 +++- .../vislib/public/vislib/helpers/index.ts | 1 + .../helpers/point_series/_add_to_siri.test.ts | 2 +- .../helpers/point_series/_add_to_siri.ts | 2 +- .../helpers/point_series/_get_aspects.test.ts | 2 +- .../helpers/point_series/_get_aspects.ts | 5 +- .../vislib/helpers/point_series/_get_point.ts | 11 ++- .../helpers/point_series/_init_x_axis.ts | 3 +- .../helpers/point_series/point_series.test.ts | 2 +- .../helpers/point_series/point_series.ts | 2 +- .../vislib/public/vislib/response_handler.js | 8 +- .../expression_functions/xy_dimension.ts | 11 ++- .../visualizations/public/vis_schemas.ts | 1 + 21 files changed, 228 insertions(+), 40 deletions(-) create mode 100644 src/plugins/vis_types/vislib/public/constants.ts create mode 100644 src/plugins/vis_types/vislib/public/vislib/helpers/accessor.ts diff --git a/src/plugins/vis_types/vislib/public/constants.ts b/src/plugins/vis_types/vislib/public/constants.ts new file mode 100644 index 0000000000000..964fa70b648da --- /dev/null +++ b/src/plugins/vis_types/vislib/public/constants.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export enum AxisType { + Category = 'category', + Value = 'value', +} + +export enum ScaleType { + Linear = 'linear', + Log = 'log', + SquareRoot = 'square root', +} + +export enum AxisMode { + Normal = 'normal', + Percentage = 'percentage', + Wiggle = 'wiggle', + Silhouette = 'silhouette', +} + +export enum InterpolationMode { + Linear = 'linear', + Cardinal = 'cardinal', + StepAfter = 'step-after', +} + +export enum ChartMode { + Normal = 'normal', + Stacked = 'stacked', +} + +export enum ChartType { + Line = 'line', + Area = 'area', + Histogram = 'histogram', +} + +export enum ThresholdLineStyle { + Full = 'full', + Dashed = 'dashed', + DotDashed = 'dot-dashed', +} diff --git a/src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx b/src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx index c0d89f2f66958..688a329f163d5 100644 --- a/src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/heatmap/index.tsx @@ -13,7 +13,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { VisEditorOptionsProps } from 'src/plugins/visualizations/public'; -import { ValueAxis } from '../../../../../xy/public'; +import { ValueAxis } from '../../../types'; import { BasicOptions, SelectOption, diff --git a/src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx b/src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx index 05b8949901e79..17c9f8e804c84 100644 --- a/src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx +++ b/src/plugins/vis_types/vislib/public/editor/components/heatmap/labels_panel.tsx @@ -14,7 +14,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { VisEditorOptionsProps } from 'src/plugins/visualizations/public'; import { SwitchOption } from '../../../../../../vis_default_editor/public'; -import { ValueAxis } from '../../../../../xy/public'; +import { ValueAxis } from '../../../types'; import { HeatmapVisParams } from '../../../heatmap'; diff --git a/src/plugins/vis_types/vislib/public/heatmap.ts b/src/plugins/vis_types/vislib/public/heatmap.ts index 3ea3a4b1e4a06..37b4da9e8a0a9 100644 --- a/src/plugins/vis_types/vislib/public/heatmap.ts +++ b/src/plugins/vis_types/vislib/public/heatmap.ts @@ -13,7 +13,8 @@ import { RangeValues } from '../../../vis_default_editor/public'; import { AggGroupNames } from '../../../data/public'; import { ColorSchemas, ColorSchemaParams } from '../../../charts/public'; import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../../visualizations/public'; -import { ValueAxis, ScaleType, AxisType } from '../../xy/public'; +import { ScaleType, AxisType } from './constants'; +import { ValueAxis } from './types'; import { HeatmapOptions } from './editor'; import { TimeMarker } from './vislib/visualizations/time_marker'; diff --git a/src/plugins/vis_types/vislib/public/to_ast.ts b/src/plugins/vis_types/vislib/public/to_ast.ts index c1de94ba0f5f9..766e42227bca0 100644 --- a/src/plugins/vis_types/vislib/public/to_ast.ts +++ b/src/plugins/vis_types/vislib/public/to_ast.ts @@ -15,7 +15,7 @@ import { VisParams, } from '../../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; -import type { Dimensions } from '../../xy/public'; +import type { Dimensions } from './types'; import type { DateHistogramParams, HistogramParams } from '../../../visualizations/public'; import { BUCKET_TYPES } from '../../../data/public'; @@ -23,6 +23,7 @@ import { BUCKET_TYPES } from '../../../data/public'; import { vislibVisName, VisTypeVislibExpressionFunctionDefinition } from './vis_type_vislib_vis_fn'; import { BasicVislibParams, VislibChartType } from './types'; import { getEsaggsFn } from './to_ast_esaggs'; +import { getColumnByAccessor } from './vislib/helpers'; export const toExpressionAst = async ( vis: Vis, @@ -42,7 +43,8 @@ export const toExpressionAst = async ( const responseAggs = vis.data.aggs?.getResponseAggs() ?? []; if (dimensions.x) { - const xAgg = responseAggs[dimensions.x.accessor] as any; + const xAgg = getColumnByAccessor(responseAggs, dimensions.x?.accessor) as any; + if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { (dimensions.x.params as DateHistogramParams).date = true; const { esUnit, esValue } = xAgg.buckets.getInterval(); @@ -67,7 +69,9 @@ export const toExpressionAst = async ( const visConfig = { ...vis.params }; (dimensions.y || []).forEach((yDimension) => { - const yAgg = responseAggs.filter(({ enabled }) => enabled)[yDimension.accessor]; + const enabledAggs = responseAggs.filter(({ enabled }) => enabled); + const yAgg = getColumnByAccessor(enabledAggs, yDimension.accessor); + const seriesParam = ((visConfig.seriesParams as BasicVislibParams['seriesParams']) || []).find( (param) => param.data.id === yAgg.id ); diff --git a/src/plugins/vis_types/vislib/public/types.ts b/src/plugins/vis_types/vislib/public/types.ts index 9184e2a4c884c..e40229baa3fac 100644 --- a/src/plugins/vis_types/vislib/public/types.ts +++ b/src/plugins/vis_types/vislib/public/types.ts @@ -9,16 +9,82 @@ import { $Values } from '@kbn/utility-types'; import { Position } from '@elastic/charts'; -import { Labels } from '../../../charts/public'; import { - CategoryAxis, - Dimensions, - Grid, - SeriesParam, - ThresholdLine, - ValueAxis, -} from '../../../vis_types/xy/public'; + DateHistogramParams, + FakeParams, + HistogramParams, + SchemaConfig, +} from '../../../visualizations/public'; +import { Labels, Style } from '../../../charts/public'; import { TimeMarker } from './vislib/visualizations/time_marker'; +import { + AxisMode, + AxisType, + ChartMode, + ChartType, + InterpolationMode, + ScaleType, + ThresholdLineStyle, +} from './constants'; + +export interface ThresholdLine { + show: boolean; + value: number | null; + width: number | null; + style: ThresholdLineStyle; + color: string; +} + +export interface SeriesParam { + data: { label: string; id: string }; + drawLinesBetweenPoints?: boolean; + interpolate?: InterpolationMode; + lineWidth?: number; + mode: ChartMode; + show: boolean; + showCircles: boolean; + circlesRadius: number; + type: ChartType; + valueAxis: string; +} + +export interface Grid { + categoryLines: boolean; + valueAxis?: string; +} + +export interface Scale { + boundsMargin?: number | ''; + defaultYExtents?: boolean; + max?: number | null; + min?: number | null; + mode?: AxisMode; + setYExtents?: boolean; + type: ScaleType; +} + +export interface CategoryAxis { + id: string; + labels: Labels; + position: Position; + scale: Scale; + show: boolean; + title: { + text?: string; + }; + type: AxisType; + /** + * Used only for heatmap, here for consistent types when used in vis_type_vislib + * + * remove with vis_type_vislib + * https://github.com/elastic/kibana/issues/56143 + */ + style?: Partial