Skip to content

Commit

Permalink
[Lens][Agg based Heatmap] Navigate to Lens Agg based Heatmap. (#143820)
Browse files Browse the repository at this point in the history
* Added base code for converting heatmap to lens.

* Added navigateToLens to visType.

* Added canNavigateToLens event.

* Fixed type.

* Added basic support of heatmap converting to lens.

* Added visType as arg.

* Added validation according to the

* Fixed heatmap std_dev.

* Fixed failing xy.

* Fixed tests.

* Added config for legend.

* Added support of converting color ranges.

* Fixed palette for default ranges.

* Refactored.

* Added tests for convertToLens.

* Added tests for getConfiguration.

* Fixed problem

* Added basic functional tests for heatmap.

* Added functional test for not convertable case.

* Added tests for not valid config and fixed one with valid.

* Added test for custom ranges.

* Added empty filters if x-axis is not defined.

- Added empty filters if y-axis is defined, but x-axis is not and if no x/y-axis was defined.
- Added/fixed tests.

* Removed unused service.

* Histogram problems fixed.

* Fixed include/exclude regexp.

* Fixed terms.
  • Loading branch information
Kuznietsov authored Oct 27, 2022
1 parent cb306df commit 9ae3880
Show file tree
Hide file tree
Showing 63 changed files with 1,573 additions and 363 deletions.

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 @@ -232,6 +232,7 @@ export const heatmapFunction = (): HeatmapExpressionFunctionDefinition => ({
},
syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false,
syncCursor: handlers?.isSyncCursorEnabled?.() ?? true,
canNavigateToLens: Boolean(handlers?.variables?.canNavigateToLens),
},
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export interface HeatmapExpressionProps {
args: HeatmapArguments;
syncTooltips: boolean;
syncCursor: boolean;
canNavigateToLens?: boolean;
}

export interface HeatmapRender {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,14 @@ export const heatmapRenderer: (
const visualizationType = extractVisualizationType(executionContext);

if (containerType && visualizationType) {
plugins.usageCollection?.reportUiCounter(containerType, METRIC_TYPE.COUNT, [
const events = [
`render_${visualizationType}_${EXPRESSION_HEATMAP_NAME}`,
]);
config.canNavigateToLens
? `render_${visualizationType}_${EXPRESSION_HEATMAP_NAME}_convertable`
: undefined,
].filter<string>((event): event is string => Boolean(event));

plugins.usageCollection?.reportUiCounter(containerType, METRIC_TYPE.COUNT, events);
}

handlers.done();
Expand Down
39 changes: 26 additions & 13 deletions src/plugins/vis_types/heatmap/kibana.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
{
"id": "visTypeHeatmap",
"version": "kibana",
"ui": true,
"server": true,
"requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection", "fieldFormats"],
"requiredBundles": ["visDefaultEditor"],
"extraPublicDirs": ["common/index"],
"owner": {
"name": "Vis Editors",
"githubTeam": "kibana-vis-editors"
},
"description": "Contains the heatmap implementation using the elastic-charts library. The goal is to eventually deprecate the old implementation and keep only this. Until then, the library used is defined by the Legacy heatmap charts library advanced setting."
}
"id": "visTypeHeatmap",
"version": "kibana",
"ui": true,
"server": true,
"requiredPlugins": [
"charts",
"data",
"expressions",
"visualizations",
"usageCollection",
"fieldFormats",
"dataViews"
],
"requiredBundles": [
"visDefaultEditor",
"kibanaUtils"
],
"extraPublicDirs": [
"common/index"
],
"owner": {
"name": "Vis Editors",
"githubTeam": "kibana-vis-editors"
},
"description": "Contains the heatmap implementation using the elastic-charts library. The goal is to eventually deprecate the old implementation and keep only this. Until then, the library used is defined by the Legacy heatmap charts library advanced setting."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* 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 { AvgColumn, DateHistogramColumn } from '@kbn/visualizations-plugin/common/convert_to_lens';
import { Vis } from '@kbn/visualizations-plugin/public';
import { getConfiguration } from '.';
import { sampleHeatmapVis } from '../../sample_vis.test.mocks';
import { HeatmapVisParams } from '../../types';

describe('getConfiguration', () => {
const layerId = 'layer-id';
let vis: Vis<HeatmapVisParams>;

const metric: AvgColumn = {
sourceField: 'price',
columnId: 'column-1',
operationType: 'average',
isBucketed: false,
isSplit: false,
dataType: 'string',
params: {},
};
const xColumn: DateHistogramColumn = {
sourceField: 'price',
columnId: 'column-2',
operationType: 'date_histogram',
isBucketed: true,
isSplit: false,
dataType: 'string',
params: {
interval: '1h',
},
};

const yColumn: DateHistogramColumn = {
sourceField: 'price',
columnId: 'column-3',
operationType: 'date_histogram',
isBucketed: true,
isSplit: true,
dataType: 'string',
params: {
interval: '1h',
},
};

beforeEach(() => {
vis = sampleHeatmapVis as unknown as Vis<HeatmapVisParams>;
});

test('should return valid configuration', async () => {
const result = await getConfiguration(layerId, vis, {
metrics: [metric.columnId],
buckets: [xColumn.columnId, yColumn.columnId],
});
expect(result).toEqual({
gridConfig: {
isCellLabelVisible: true,
isXAxisLabelVisible: true,
isXAxisTitleVisible: true,
isYAxisLabelVisible: true,
isYAxisTitleVisible: true,
type: 'heatmap_grid',
},
layerId,
layerType: 'data',
legend: { isVisible: undefined, position: 'right', type: 'heatmap_legend' },
palette: {
accessor: 'column-1',
name: 'custom',
params: {
colorStops: [
{ color: '#F7FBFF', stop: 0 },
{ color: '#DEEBF7', stop: 12.5 },
{ color: '#C3DBEE', stop: 25 },
{ color: '#9CC8E2', stop: 37.5 },
{ color: '#6DAED5', stop: 50 },
{ color: '#4391C6', stop: 62.5 },
{ color: '#2271B3', stop: 75 },
{ color: '#0D5097', stop: 87.5 },
],
continuity: 'none',
maxSteps: 5,
name: 'custom',
progression: 'fixed',
rangeMax: 100,
rangeMin: 0,
rangeType: 'number',
reverse: false,
stops: [
{ color: '#F7FBFF', stop: 12.5 },
{ color: '#DEEBF7', stop: 25 },
{ color: '#C3DBEE', stop: 37.5 },
{ color: '#9CC8E2', stop: 50 },
{ color: '#6DAED5', stop: 62.5 },
{ color: '#4391C6', stop: 75 },
{ color: '#2271B3', stop: 87.5 },
{ color: '#0D5097', stop: 100 },
],
},
type: 'palette',
},
shape: 'heatmap',
valueAccessor: metric.columnId,
xAccessor: xColumn.columnId,
yAccessor: yColumn.columnId,
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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 { HeatmapConfiguration } from '@kbn/visualizations-plugin/common';
import { Vis } from '@kbn/visualizations-plugin/public';
import { HeatmapVisParams } from '../../types';
import { getPaletteForHeatmap } from './palette';

export const getConfiguration = async (
layerId: string,
vis: Vis<HeatmapVisParams>,
{
metrics,
buckets,
}: {
metrics: string[];
buckets: string[];
}
): Promise<HeatmapConfiguration> => {
const [valueAccessor] = metrics;
const [xAccessor, yAccessor] = buckets;

const { params, uiState } = vis;
const state = uiState.get('vis', {}) ?? {};

const palette = await getPaletteForHeatmap(params);
return {
layerId,
layerType: 'data',
shape: 'heatmap',
legend: {
type: 'heatmap_legend',
isVisible: state.legendOpen,
position: params.legendPosition,
},
gridConfig: {
type: 'heatmap_grid',
isCellLabelVisible: params.valueAxes?.[0].labels.show ?? false,
isXAxisLabelVisible: true,
isYAxisLabelVisible: true,
isYAxisTitleVisible: true,
isXAxisTitleVisible: true,
},
valueAccessor,
xAccessor,
yAccessor,
palette: palette ? { ...palette, accessor: valueAccessor } : undefined,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 { Range } from '@kbn/expressions-plugin/common';
import { convertToLensModule } from '@kbn/visualizations-plugin/public';
import { HeatmapVisParams } from '../../types';
import { getStopsWithColorsFromColorsNumber } from '../../utils/palette';

type HeatmapVisParamsWithRanges = Omit<HeatmapVisParams, 'colorsRange'> & {
colorsRange: Exclude<HeatmapVisParams['colorsRange'], undefined>;
};

const isHeatmapVisParamsWithRanges = (
params: HeatmapVisParams | HeatmapVisParamsWithRanges
): params is HeatmapVisParamsWithRanges => {
return Boolean(params.setColorRange && params.colorsRange && params.colorsRange.length);
};

export const getPaletteForHeatmap = async (params: HeatmapVisParams) => {
const { getPalette, getPaletteFromStopsWithColors, getPercentageModeConfig } =
await convertToLensModule;

if (isHeatmapVisParamsWithRanges(params)) {
const percentageModeConfig = getPercentageModeConfig(params, false);
return getPalette(params, percentageModeConfig, params.percentageMode);
}

const { color, stop = [] } = getStopsWithColorsFromColorsNumber(
params.colorsNumber,
params.colorSchema,
params.invertColors,
true
);
const colorsRange: Range[] = [{ from: stop[0], to: stop[stop.length - 1], type: 'range' }];
const { colorSchema, invertColors, percentageMode } = params;
const percentageModeConfig = getPercentageModeConfig(
{
colorsRange,
colorSchema,
invertColors,
percentageMode,
},
false
);

return getPaletteFromStopsWithColors({ color, stop: stop ?? [] }, percentageModeConfig, true);
};
Loading

0 comments on commit 9ae3880

Please sign in to comment.