Skip to content

Commit

Permalink
[XY] Mark size configuration. (#130361)
Browse files Browse the repository at this point in the history
* Added tests for the case when markSizeRatio and markSizeAccessor are specified.

* Added markSizeAccessor to extendedDataLayer and xyVis.

* Fixed markSizeRatio default value.

* Added `size` support from `pointseries`.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
Kuznietsov and kibanamachine committed May 19, 2022
1 parent d9e6ef3 commit dd8bd6f
Show file tree
Hide file tree
Showing 21 changed files with 438 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Position } from '@elastic/charts';
import type { PaletteOutput } from '@kbn/coloring';
import { Datatable, DatatableRow } from '@kbn/expressions-plugin';
import { LayerTypes } from '../constants';
import { DataLayerConfig, XYProps } from '../types';
import { DataLayerConfig, ExtendedDataLayerConfig, XYProps } from '../types';

export const mockPaletteOutput: PaletteOutput = {
type: 'palette',
Expand All @@ -35,7 +35,7 @@ export const createSampleDatatableWithRows = (rows: DatatableRow[]): Datatable =
id: 'c',
name: 'c',
meta: {
type: 'date',
type: 'string',
field: 'order_date',
sourceParams: { type: 'date-histogram', params: { interval: 'auto' } },
params: { id: 'string' },
Expand All @@ -61,6 +61,21 @@ export const sampleLayer: DataLayerConfig = {
table: createSampleDatatableWithRows([]),
};

export const sampleExtendedLayer: ExtendedDataLayerConfig = {
layerId: 'first',
type: 'extendedDataLayer',
layerType: LayerTypes.DATA,
seriesType: 'line',
xAccessor: 'c',
accessors: ['a', 'b'],
splitAccessor: 'd',
columnToLabel: '{"a": "Label A", "b": "Label B", "d": "Label D"}',
xScaleType: 'ordinal',
isHistogram: false,
palette: mockPaletteOutput,
table: createSampleDatatableWithRows([]),
};

export const createArgsWithLayers = (
layers: DataLayerConfig | DataLayerConfig[] = sampleLayer
): XYProps => ({
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ export const commonXYArgs: CommonXYFn['args'] = {
types: ['string'],
help: strings.getAriaLabelHelp(),
},
markSizeRatio: {
types: ['number'],
help: strings.getMarkSizeRatioHelp(),
},
minTimeBarInterval: {
types: ['string'],
help: strings.getMinTimeBarIntervalHelp(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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 { ExtendedDataLayerArgs } from '../types';
import { createMockExecutionContext } from '@kbn/expressions-plugin/common/mocks';
import { mockPaletteOutput, sampleArgs } from '../__mocks__';
import { LayerTypes } from '../constants';
import { extendedDataLayerFunction } from './extended_data_layer';

describe('extendedDataLayerConfig', () => {
test('produces the correct arguments', async () => {
const { data } = sampleArgs();
const args: ExtendedDataLayerArgs = {
seriesType: 'line',
xAccessor: 'c',
accessors: ['a', 'b'],
splitAccessor: 'd',
xScaleType: 'linear',
isHistogram: false,
palette: mockPaletteOutput,
markSizeAccessor: 'b',
};

const result = await extendedDataLayerFunction.fn(data, args, createMockExecutionContext());

expect(result).toEqual({
type: 'extendedDataLayer',
layerType: LayerTypes.DATA,
...args,
table: data,
});
});

test('throws the error if markSizeAccessor is provided to the not line/area chart', async () => {
const { data } = sampleArgs();
const args: ExtendedDataLayerArgs = {
seriesType: 'bar',
xAccessor: 'c',
accessors: ['a', 'b'],
splitAccessor: 'd',
xScaleType: 'linear',
isHistogram: false,
palette: mockPaletteOutput,
markSizeAccessor: 'b',
};

expect(
extendedDataLayerFunction.fn(data, args, createMockExecutionContext())
).rejects.toThrowErrorMatchingSnapshot();
});

test("throws the error if markSizeAccessor doesn't have the corresponding column in the table", async () => {
const { data } = sampleArgs();
const args: ExtendedDataLayerArgs = {
seriesType: 'line',
xAccessor: 'c',
accessors: ['a', 'b'],
splitAccessor: 'd',
xScaleType: 'linear',
isHistogram: false,
palette: mockPaletteOutput,
markSizeAccessor: 'nonsense',
};

expect(
extendedDataLayerFunction.fn(data, args, createMockExecutionContext())
).rejects.toThrowErrorMatchingSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export const extendedDataLayerFunction: ExtendedDataLayerFn = {
help: strings.getAccessorsHelp(),
multi: true,
},
markSizeAccessor: {
types: ['string'],
help: strings.getMarkSizeAccessorHelp(),
},
table: {
types: ['datatable'],
help: strings.getTableHelp(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { validateAccessor } from '@kbn/visualizations-plugin/common/utils';
import { ExtendedDataLayerArgs, ExtendedDataLayerFn } from '../types';
import { EXTENDED_DATA_LAYER, LayerTypes } from '../constants';
import { getAccessors, normalizeTable } from '../helpers';
import { validateMarkSizeForChartType } from './validate';

export const extendedDataLayerFn: ExtendedDataLayerFn['fn'] = async (data, args, context) => {
const table = args.table ?? data;
Expand All @@ -18,6 +19,8 @@ export const extendedDataLayerFn: ExtendedDataLayerFn['fn'] = async (data, args,
validateAccessor(accessors.xAccessor, table.columns);
validateAccessor(accessors.splitAccessor, table.columns);
accessors.accessors.forEach((accessor) => validateAccessor(accessor, table.columns));
validateMarkSizeForChartType(args.markSizeAccessor, args.seriesType);
validateAccessor(args.markSizeAccessor, table.columns);

const normalizedTable = normalizeTable(table, accessors.xAccessor);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { layeredXyVisFunction } from '.';
import { createMockExecutionContext } from '@kbn/expressions-plugin/common/mocks';
import { sampleArgs, sampleExtendedLayer } from '../__mocks__';
import { XY_VIS } from '../constants';

describe('layeredXyVis', () => {
test('it renders with the specified data and args', async () => {
const { data, args } = sampleArgs();
const { layers, ...rest } = args;
const result = await layeredXyVisFunction.fn(
data,
{ ...rest, layers: [sampleExtendedLayer] },
createMockExecutionContext()
);

expect(result).toEqual({
type: 'render',
as: XY_VIS,
value: { args: { ...rest, layers: [sampleExtendedLayer] } },
});
});

test('it should throw error if markSizeRatio is lower then 1 or greater then 100', async () => {
const { data, args } = sampleArgs();
const { layers, ...rest } = args;

expect(
layeredXyVisFunction.fn(
data,
{
...rest,
markSizeRatio: 0,
layers: [sampleExtendedLayer],
},
createMockExecutionContext()
)
).rejects.toThrowErrorMatchingSnapshot();

expect(
layeredXyVisFunction.fn(
data,
{
...rest,
markSizeRatio: 101,
layers: [sampleExtendedLayer],
},
createMockExecutionContext()
)
).rejects.toThrowErrorMatchingSnapshot();
});

test('it should throw error if markSizeRatio is specified if no markSizeAccessor is present', async () => {
const { data, args } = sampleArgs();
const { layers, ...rest } = args;

expect(
layeredXyVisFunction.fn(
data,
{
...rest,
markSizeRatio: 10,
layers: [sampleExtendedLayer],
},
createMockExecutionContext()
)
).rejects.toThrowErrorMatchingSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import { XY_VIS_RENDERER } from '../constants';
import { appendLayerIds, getDataLayers } from '../helpers';
import { LayeredXyVisFn } from '../types';
import { logDatatables } from '../utils';
import { validateMinTimeBarInterval, hasBarLayer } from './validate';
import {
validateMarkSizeRatioLimits,
validateMinTimeBarInterval,
hasBarLayer,
errors,
} from './validate';

export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers) => {
const layers = appendLayerIds(args.layers ?? [], 'layers');
Expand All @@ -19,7 +24,14 @@ export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers)

const dataLayers = getDataLayers(layers);
const hasBar = hasBarLayer(dataLayers);
validateMarkSizeRatioLimits(args.markSizeRatio);
validateMinTimeBarInterval(dataLayers, hasBar, args.minTimeBarInterval);
const hasMarkSizeAccessors =
dataLayers.filter((dataLayer) => dataLayer.markSizeAccessor !== undefined).length > 0;

if (!hasMarkSizeAccessors && args.markSizeRatio !== undefined) {
throw new Error(errors.markSizeRatioWithoutAccessor());
}

return {
type: 'render',
Expand All @@ -28,6 +40,7 @@ export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers)
args: {
...args,
layers,
markSizeRatio: hasMarkSizeAccessors && !args.markSizeRatio ? 10 : args.markSizeRatio,
ariaLabel:
args.ariaLabel ??
(handlers.variables?.embeddableTitle as string) ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

import { i18n } from '@kbn/i18n';
import { isValidInterval } from '@kbn/data-plugin/common';
import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common';
import { AxisExtentModes, ValueLabelModes } from '../constants';
import {
SeriesType,
AxisExtentConfigResult,
DataLayerConfigResult,
CommonXYDataLayerConfigResult,
Expand All @@ -18,7 +20,23 @@ import {
} from '../types';
import { isTimeChart } from '../helpers';

const errors = {
export const errors = {
markSizeAccessorForNonLineOrAreaChartsError: () =>
i18n.translate(
'expressionXY.reusable.function.dataLayer.errors.markSizeAccessorForNonLineOrAreaChartsError',
{
defaultMessage:
"`markSizeAccessor` can't be used. Dots are applied only for line or area charts",
}
),
markSizeRatioLimitsError: () =>
i18n.translate('expressionXY.reusable.function.xyVis.errors.markSizeLimitsError', {
defaultMessage: 'Mark size ratio must be greater or equal to 1 and less or equal to 100',
}),
markSizeRatioWithoutAccessor: () =>
i18n.translate('expressionXY.reusable.function.xyVis.errors.markSizeRatioWithoutAccessor', {
defaultMessage: 'Mark size ratio can be applied only with `markSizeAccessor`',
}),
extendBoundsAreInvalidError: () =>
i18n.translate('expressionXY.reusable.function.xyVis.errors.extendBoundsAreInvalidError', {
defaultMessage:
Expand Down Expand Up @@ -117,6 +135,30 @@ export const validateValueLabels = (
}
};

export const validateMarkSizeForChartType = (
markSizeAccessor: ExpressionValueVisDimension | string | undefined,
seriesType: SeriesType
) => {
if (markSizeAccessor && !seriesType.includes('line') && !seriesType.includes('area')) {
throw new Error(errors.markSizeAccessorForNonLineOrAreaChartsError());
}
};

export const validateMarkSizeRatioLimits = (markSizeRatio?: number) => {
if (markSizeRatio !== undefined && (markSizeRatio < 1 || markSizeRatio > 100)) {
throw new Error(errors.markSizeRatioLimitsError());
}
};

export const validateMarkSizeRatioWithAccessor = (
markSizeRatio: number | undefined,
markSizeAccessor: ExpressionValueVisDimension | string | undefined
) => {
if (markSizeRatio !== undefined && !markSizeAccessor) {
throw new Error(errors.markSizeRatioWithoutAccessor());
}
};

export const validateMinTimeBarInterval = (
dataLayers: CommonXYDataLayerConfigResult[],
hasBar: boolean,
Expand Down
Loading

0 comments on commit dd8bd6f

Please sign in to comment.