Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions x-pack/plugins/lens/public/xy_visualization/expression.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,48 @@ function sampleArgs() {
return { data, args };
}

function sampleArgsWithThreshold(thresholdValue: number = 150) {
const { data, args } = sampleArgs();

return {
data: {
...data,
tables: {
...data.tables,
threshold: {
type: 'datatable',
columns: [
{
id: 'threshold-a',
meta: { params: { id: 'number' }, type: 'number' },
name: 'Static value',
},
],
rows: [{ 'threshold-a': thresholdValue }],
},
},
} as LensMultiTable,
args: {
...args,
layers: [
...args.layers,
{
layerType: layerTypes.THRESHOLD,
accessors: ['threshold-a'],
layerId: 'threshold',
seriesType: 'line',
xScaleType: 'linear',
yScaleType: 'linear',
palette: mockPaletteOutput,
isHistogram: false,
hide: true,
yConfig: [{ axisMode: 'left', forAccessor: 'threshold-a', type: 'lens_xy_yConfig' }],
},
],
} as XYArgs,
};
}

describe('xy_expression', () => {
describe('configs', () => {
test('legendConfig produces the correct arguments', () => {
Expand Down Expand Up @@ -829,6 +871,53 @@ describe('xy_expression', () => {
max: undefined,
});
});

test('it does include threshold values when in full extent mode', () => {
const { data, args } = sampleArgsWithThreshold();

const component = shallow(<XYChart {...defaultProps} data={data} args={args} />);
expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({
fit: false,
min: 0,
max: 150,
});
});

test('it should ignore threshold values when set to custom extents', () => {
const { data, args } = sampleArgsWithThreshold();

const component = shallow(
<XYChart
{...defaultProps}
data={data}
args={{
...args,
yLeftExtent: {
type: 'lens_xy_axisExtentConfig',
mode: 'custom',
lowerBound: 123,
upperBound: 456,
},
}}
/>
);
expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({
fit: false,
min: 123,
max: 456,
});
});

test('it should work for negative values in thresholds', () => {
const { data, args } = sampleArgsWithThreshold(-150);

const component = shallow(<XYChart {...defaultProps} data={data} args={args} />);
expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({
fit: false,
min: -150,
max: 5,
});
});
});

test('it has xDomain undefined if the x is not a time scale or a histogram', () => {
Expand Down
40 changes: 37 additions & 3 deletions x-pack/plugins/lens/public/xy_visualization/expression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export function calculateMinInterval({ args: { layers }, data }: XYChartProps) {
return intervalDuration.as('milliseconds');
}

const isPrimitive = (value: unknown): boolean => value != null && typeof value !== 'object';

export const getXyChartRenderer = (dependencies: {
formatFactory: FormatFactory;
chartsThemeService: ChartsPluginStart['theme'];
Expand Down Expand Up @@ -395,6 +397,41 @@ export function XYChart({
min = extent.lowerBound;
max = extent.upperBound;
}
} else {
const axisHasThreshold = thresholdLayers.some(({ yConfig }) =>
yConfig?.some(({ axisMode }) => axisMode === axis.groupId)
);
if (!fit && axisHasThreshold) {
// Remove this once the chart will support automatic annotation fit for other type of charts
for (const series of axis.series) {
const table = data.tables[series.layer];
for (const row of table.rows) {
for (const column of table.columns) {
if (column.id === series.accessor) {
const value = row[column.id];
if (typeof value === 'number') {
// keep the 0 in view
max = Math.max(value, max || 0, 0);
min = Math.min(value, min || 0, 0);
}
}
}
}
}
for (const { layerId, yConfig } of thresholdLayers) {
const table = data.tables[layerId];
for (const { axisMode, forAccessor } of yConfig || []) {
if (axis.groupId === axisMode) {
for (const row of table.rows) {
const value = row[forAccessor];
// keep the 0 in view
max = Math.max(value, max || 0, 0);
min = Math.min(value, min || 0, 0);
}
}
}
}
}
}

return {
Expand Down Expand Up @@ -652,9 +689,6 @@ export function XYChart({

const table = data.tables[layerId];

const isPrimitive = (value: unknown): boolean =>
value != null && typeof value !== 'object';

// what if row values are not primitive? That is the case of, for instance, Ranges
// remaps them to their serialized version with the formatHint metadata
// In order to do it we need to make a copy of the table as the raw one is required for more features (filters, etc...) later on
Expand Down