Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lens] Label each Y axis with its operation label #39461

Merged
merged 4 commits into from
Jun 25, 2019
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

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.

26 changes: 23 additions & 3 deletions x-pack/legacy/plugins/lens/public/xy_visualization_plugin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,15 @@ const axisConfig: { [key in keyof AxisConfig]: ArgumentType<AxisConfig[key]> } =
},
};

export interface YConfig extends AxisConfig {
export interface YState extends AxisConfig {
accessors: string[];
}

export type YConfig = AxisConfig &
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice pattern, I think this will get very handy in the future as we pull more information out of the table data (e.g. formatting)

YState & {
labels: string[];
};

type YConfigResult = YConfig & { type: 'lens_xy_yConfig' };

export const yConfig: ExpressionFunction<'lens_xy_yConfig', null, YConfig, YConfigResult> = {
Expand All @@ -92,6 +97,11 @@ export const yConfig: ExpressionFunction<'lens_xy_yConfig', null, YConfig, YConf
help: 'The columns to display on the y axis.',
multi: true,
},
labels: {
types: ['string'],
help: '',
multi: true,
},
},
fn: function fn(_context: unknown, args: YConfig) {
return {
Expand Down Expand Up @@ -142,5 +152,15 @@ export interface XYArgs {
stackAccessors: string[];
}

export type State = XYArgs;
export type PersistableState = XYArgs;
export interface XYState {
seriesType: SeriesType;
title: string;
legend: LegendConfig;
y: YState;
x: XConfig;
splitSeriesAccessors: string[];
stackAccessors: string[];
}

export type State = XYState;
export type PersistableState = XYState;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Position } from '@elastic/charts';
import { BarSeries, Position } from '@elastic/charts';
import { xyChart, XYChart } from './xy_expression';
import { KibanaDatatable } from '../types';
import React from 'react';
Expand All @@ -27,6 +27,7 @@ function sampleArgs() {
},
y: {
accessors: ['a', 'b'],
labels: ['Label A', 'Label B'],
position: Position.Left,
showGridlines: false,
title: 'A and B',
Expand Down Expand Up @@ -75,6 +76,7 @@ describe('xy_expression', () => {
test('yConfig produces the correct arguments', () => {
const args: YConfig = {
accessors: ['bar'],
labels: [''],
position: Position.Bottom,
showGridlines: true,
title: 'Barrrrrr!',
Expand Down Expand Up @@ -123,5 +125,19 @@ describe('xy_expression', () => {
shallow(<XYChart data={data} args={{ ...args, seriesType: 'area' }} />)
).toMatchSnapshot();
});

test('it remaps rows based on the labels', () => {
const { data, args } = sampleArgs();

const chart = shallow(<XYChart data={data} args={{ ...args, seriesType: 'bar' }} />);
const barSeries = chart.find(BarSeries);

expect(barSeries.prop('yAccessors')).toEqual(['Label A', 'Label B']);
expect(barSeries.prop('data')[0]).toEqual({
'Label A': 1,
'Label B': 2,
c: 3,
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,37 @@ export const xyChartRenderer: RenderFunction<XYChartProps> = {

export function XYChart({ data, args }: XYChartProps) {
const { legend, x, y, splitSeriesAccessors, stackAccessors, seriesType } = args;
// TODO: Stop mapping data once elastic-charts allows axis naming
// https://github.com/elastic/elastic-charts/issues/245
const seriesProps = {
splitSeriesAccessors,
stackAccessors,
id: getSpecId(y.accessors.join(',')),
id: getSpecId(y.labels.join(',')),
xAccessor: x.accessor,
yAccessors: y.accessors,
data: data.rows,
yAccessors: y.labels,
data: data.rows.map(row => {
const newRow: typeof row = {};

// Remap data to { 'Count of documents': 5 }
Object.keys(row).forEach(key => {
const labelIndex = y.accessors.indexOf(key);
if (labelIndex > -1) {
newRow[y.labels[labelIndex]] = row[key];
} else {
newRow[key] = row[key];
}
});
return newRow;
}),
};

return (
<Chart className="lnsChart">
<Settings showLegend={legend.isVisible} legendPosition={legend.position} />
<Settings
showLegend={legend.isVisible}
legendPosition={legend.position}
showLegendDisplayValue={false}
/>

<Axis
id={getAxisId('x')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

import { xyVisualization } from './xy_visualization';
import { Position } from '@elastic/charts';
import { DatasourcePublicAPI } from '../types';
import { Ast } from '@kbn/interpreter/target/common';
import { Operation } from '../types';
import { State } from './types';
import { createMockDatasource } from '../editor_frame_plugin/mocks';

Expand Down Expand Up @@ -89,8 +90,34 @@ Object {
describe('#toExpression', () => {
it('should map to a valid AST', () => {
expect(
xyVisualization.toExpression(exampleState(), {} as DatasourcePublicAPI)
xyVisualization.toExpression(exampleState(), createMockDatasource().publicAPIMock)
).toMatchSnapshot();
});

it('should default to labeling all columns with their column label', () => {
const mockDatasource = createMockDatasource();

mockDatasource.publicAPIMock.getOperationForColumnId
.mockReturnValueOnce({
label: 'First',
} as Operation)
.mockReturnValueOnce({
label: 'Second',
} as Operation);

const expression = xyVisualization.toExpression(
exampleState(),
mockDatasource.publicAPIMock
)! as Ast;

expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledTimes(2);
expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('b');
expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('c');

expect((expression.chain[0].arguments.y[0] as Ast).chain[0].arguments.labels).toEqual([
'First',
'Second',
]);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const xyVisualization: Visualization<State, PersistableState> = {
domElement
),

toExpression: state => ({
toExpression: (state, datasource) => ({
type: 'expression',
chain: [
{
Expand Down Expand Up @@ -103,6 +103,10 @@ export const xyVisualization: Visualization<State, PersistableState> = {
showGridlines: [state.y.showGridlines],
position: [state.y.position],
accessors: state.y.accessors,
labels: state.y.accessors.map(accessor => {
const operation = datasource.getOperationForColumnId(accessor);
return operation ? operation.label : accessor;
}),
},
},
],
Expand Down