Skip to content

Commit

Permalink
✨ Add axis extent for histogram
Browse files Browse the repository at this point in the history
  • Loading branch information
dej611 committed Jun 9, 2022
1 parent 7db3e58 commit a075626
Show file tree
Hide file tree
Showing 23 changed files with 891 additions and 210 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ export const createArgsWithLayers = (
yLeft: false,
yRight: false,
},
xExtent: {
mode: 'dataBounds',
type: 'axisExtentConfig',
},
yLeftExtent: {
mode: 'full',
type: 'axisExtentConfig',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export const commonXYArgs: CommonXYFn['args'] = {
types: ['string'],
help: strings.getYRightTitleHelp(),
},
xExtent: {
types: [AXIS_EXTENT_CONFIG],
help: strings.getXExtentHelp(),
default: `{${AXIS_EXTENT_CONFIG}}`,
},
yLeftExtent: {
types: [AXIS_EXTENT_CONFIG],
help: strings.getYLeftExtentHelp(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export const strings = {
i18n.translate('expressionXY.xyVis.yRightTitle.help', {
defaultMessage: 'Y right axis title',
}),
getXExtentHelp: () =>
i18n.translate('expressionXY.xyVis.xExtent.help', {
defaultMessage: 'X axis extents',
}),
getYLeftExtentHelp: () =>
i18n.translate('expressionXY.xyVis.yLeftExtent.help', {
defaultMessage: 'Y left axis extents',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ export interface XYArgs extends DataLayerArgs {
xTitle: string;
yTitle: string;
yRightTitle: string;
xExtent: AxisExtentConfigResult;
yLeftExtent: AxisExtentConfigResult;
yRightExtent: AxisExtentConfigResult;
yLeftScale: YScaleType;
Expand Down Expand Up @@ -230,6 +231,7 @@ export interface LayeredXYArgs {
xTitle: string;
yTitle: string;
yRightTitle: string;
xExtent: AxisExtentConfigResult;
yLeftExtent: AxisExtentConfigResult;
yRightExtent: AxisExtentConfigResult;
yLeftScale: YScaleType;
Expand Down Expand Up @@ -261,6 +263,7 @@ export interface XYProps {
xTitle: string;
yTitle: string;
yRightTitle: string;
xExtent: AxisExtentConfigResult;
yLeftExtent: AxisExtentConfigResult;
yRightExtent: AxisExtentConfigResult;
yLeftScale: YScaleType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
getAccessorByDimension,
getColumnByAccessor,
} from '@kbn/visualizations-plugin/common/utils';
import type { CommonXYDataLayerConfig } from '../../common';
import type { AxisExtentConfigResult, CommonXYDataLayerConfig } from '../../common';

export interface XDomain {
min?: number;
Expand Down Expand Up @@ -43,7 +43,8 @@ export const getXDomain = (
layers: CommonXYDataLayerConfig[],
minInterval: number | undefined,
isTimeViz: boolean,
isHistogram: boolean
isHistogram: boolean,
xExtent?: AxisExtentConfigResult
) => {
const appliedTimeRange = getAppliedTimeRange(layers)?.timeRange;
const from = appliedTimeRange?.from;
Expand All @@ -59,6 +60,16 @@ export const getXDomain = (
: undefined;

if (isHistogram && isFullyQualified(baseDomain)) {
if (xExtent) {
return {
extendedDomain: {
min: xExtent.lowerBound ?? NaN,
max: xExtent.upperBound ?? NaN,
minInterval: baseDomain.minInterval,
},
baseDomain,
};
}
const xValues = uniq(
layers
.flatMap<number>(({ table, xAccessor }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,33 @@ describe('XYChart component', () => {
});
});

describe('x axis extents', () => {
const { args } = sampleArgs();

test('it passes custom x axis extents to elastic-charts settings spec', () => {
{
const component = shallow(
<XYChart
{...defaultProps}
args={{
...args,
xExtent: {
type: 'axisExtentConfig',
mode: 'custom',
lowerBound: 123,
upperBound: 456,
},
}}
/>
);
expect(component.find(Settings).prop('xDomain')).toEqual({
min: 123,
max: 456,
});
}
});
});

describe('y axis extents', () => {
const { args } = sampleArgs();

Expand Down Expand Up @@ -2256,6 +2283,10 @@ describe('XYChart component', () => {
yLeft: 0,
yRight: 0,
},
xExtent: {
mode: 'dataBounds',
type: 'axisExtentConfig',
},
yLeftExtent: {
mode: 'full',
type: 'axisExtentConfig',
Expand Down Expand Up @@ -2347,6 +2378,10 @@ describe('XYChart component', () => {
yLeft: 0,
yRight: 0,
},
xExtent: {
mode: 'dataBounds',
type: 'axisExtentConfig',
},
yLeftExtent: {
mode: 'full',
type: 'axisExtentConfig',
Expand Down Expand Up @@ -2423,6 +2458,10 @@ describe('XYChart component', () => {
yLeft: 0,
yRight: 0,
},
xExtent: {
mode: 'dataBounds',
type: 'axisExtentConfig',
},
yLeftExtent: {
mode: 'full',
type: 'axisExtentConfig',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export function XYChart({
gridlinesVisibilitySettings,
valueLabels,
hideEndzones,
xExtent,
yLeftExtent,
yRightExtent,
valuesInLegend,
Expand Down Expand Up @@ -280,7 +281,8 @@ export function XYChart({
dataLayers,
minInterval,
isTimeViz,
isHistogramViz
isHistogramViz,
xExtent
);

const getYAxesTitles = (axisSeries: Series[]) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiFormRow, EuiButtonGroup, htmlIdGenerator } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { RangeInputField } from '../range_input_field';
import { validateAxisDomain } from './helpers';
import { UnifiedAxisExtentConfig } from './types';

const idPrefix = htmlIdGenerator()();
export function BucketAxisBoundsControl({
testSubjPrefix,
extent,
setExtent,
dataBounds,
}: {
testSubjPrefix: string;
extent: UnifiedAxisExtentConfig;
setExtent: (newExtent: UnifiedAxisExtentConfig | undefined) => void;
dataBounds: { min: number; max: number } | undefined;
}) {
const boundaryError = !validateAxisDomain(extent);
return (
<>
<EuiFormRow
display="columnCompressed"
fullWidth
label={i18n.translate('xpack.lens.axisExtent.label', {
defaultMessage: 'Bounds',
})}
>
<EuiButtonGroup
isFullWidth
legend={i18n.translate('xpack.lens.axisExtent.label', {
defaultMessage: 'Bounds',
})}
data-test-subj={`${testSubjPrefix}_axisBounds_groups`}
name="axisBounds"
buttonSize="compressed"
options={[
{
id: `${idPrefix}dataBounds`,
label: i18n.translate('xpack.lens.axisExtent.dataBounds', {
defaultMessage: 'Data',
}),
'data-test-subj': `${testSubjPrefix}_axisExtent_groups_DataBounds'`,
},
{
id: `${idPrefix}custom`,
label: i18n.translate('xpack.lens.axisExtent.custom', {
defaultMessage: 'Custom',
}),
'data-test-subj': `${testSubjPrefix}_axisExtent_groups_custom'`,
},
]}
idSelected={`${idPrefix}${extent.mode ?? 'dataBounds'}`}
onChange={(id) => {
const newMode = id.replace(idPrefix, '') as UnifiedAxisExtentConfig['mode'];
setExtent({
...extent,
mode: newMode,
lowerBound: newMode === 'custom' && dataBounds ? dataBounds.min : undefined,
upperBound: newMode === 'custom' && dataBounds ? dataBounds.max : undefined,
});
}}
/>
</EuiFormRow>
{extent?.mode === 'custom' && (
<RangeInputField
isInvalid={boundaryError}
label={' '}
error={
boundaryError
? i18n.translate('xpack.lens.boundaryError', {
defaultMessage: 'Lower bound has to be larger than upper bound',
})
: undefined
}
testSubjLayout={`${testSubjPrefix}_axisExtent_customBounds`}
testSubjLower={`${testSubjPrefix}_axisExtent_lowerBound`}
testSubjUpper={`${testSubjPrefix}_axisExtent_upperBound`}
lowerValue={extent.lowerBound ?? ''}
onLowerValueChange={(e) => {
const val = Number(e.target.value);
const isEmptyValue = e.target.value === '' || Number.isNaN(Number(val));
setExtent({
...extent,
lowerBound: isEmptyValue ? undefined : val,
});
}}
onLowerValueBlur={() => {
if (extent.lowerBound === undefined && dataBounds) {
setExtent({
...extent,
lowerBound: dataBounds.min,
});
}
}}
upperValue={extent.upperBound ?? ''}
onUpperValueChange={(e) => {
const val = Number(e.target.value);
const isEmptyValue = e.target.value === '' || Number.isNaN(Number(val));
setExtent({
...extent,
upperBound: isEmptyValue ? undefined : val,
});
}}
onUpperValueBlur={() => {
if (extent.upperBound === undefined && dataBounds) {
setExtent({
...extent,
upperBound: dataBounds.max,
});
}
}}
/>
)}
</>
);
}
Loading

0 comments on commit a075626

Please sign in to comment.