Skip to content

Commit

Permalink
[lens] tag cloud (#157751)
Browse files Browse the repository at this point in the history
Part of #154307
Closes #95542

PR adds tagcloud visualization to lens

<img width="600" alt="Screen Shot 2023-05-31 at 1 11 00 PM"
src="https://github.com/elastic/kibana/assets/373691/f54f76a3-9757-4a00-ac65-a203e5bb113a">

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co>
  • Loading branch information
3 people authored Jun 8, 2023
1 parent 6e81ae8 commit ec62e15
Show file tree
Hide file tree
Showing 33 changed files with 736 additions and 33 deletions.
1 change: 1 addition & 0 deletions packages/kbn-chart-icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ export {
IconChartHeatmap,
IconChartHorizontalBullet,
IconChartVerticalBullet,
IconChartTagcloud,
} from './src/assets';
29 changes: 29 additions & 0 deletions packages/kbn-chart-icons/src/assets/chart_tagcloud.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 React, { FunctionComponent } from 'react';
import type { EuiIconProps } from '@elastic/eui';
import { colors } from './common_styles';

export const IconChartTagcloud: FunctionComponent = ({
title,
titleId,
...props
}: Omit<EuiIconProps, 'type'>) => (
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="22" viewBox="0 0 30 22" {...props}>
{title ? <title id={titleId} /> : null}
<path
d="M19 5a2 2 0 0 1 2-2h4a2 2 0 1 1 0 4h-4a2 2 0 0 1-2-2ZM2 11a2 2 0 0 1 2-2h8a2 2 0 1 1 0 4H4a2 2 0 0 1-2-2Zm15 4a2 2 0 1 0 0 4h6a2 2 0 1 0 0-4h-6Z"
className={colors.accent}
/>
<path
d="M6 4a1 1 0 0 0 0 2h4a1 1 0 1 0 0-2H6Zm8 0a1 1 0 1 0 0 2h2a1 1 0 1 0 0-2h-2Zm2 7a1 1 0 0 1 1-1h10a1 1 0 1 1 0 2H17a1 1 0 0 1-1-1Zm-8 5a1 1 0 1 0 0 2h4a1 1 0 1 0 0-2H8Z"
className={colors.subdued}
/>
</svg>
);
1 change: 1 addition & 0 deletions packages/kbn-chart-icons/src/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ export { IconRegionMap } from './region_map';
export { IconChartHeatmap } from './chart_heatmap';
export { IconChartHorizontalBullet } from './chart_horizontal_bullet';
export { IconChartVerticalBullet } from './chart_vertical_bullet';
export { IconChartTagcloud } from './chart_tagcloud';

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 @@ -20,7 +20,7 @@ const strings = {
help: i18n.translate('expressionTagcloud.functions.tagcloudHelpText', {
defaultMessage: 'Tagcloud visualization.',
}),
args: {
argHelp: {
scale: i18n.translate('expressionTagcloud.functions.tagcloud.args.scaleHelpText', {
defaultMessage: 'Scale to determine font size of a word',
}),
Expand Down Expand Up @@ -48,6 +48,9 @@ const strings = {
ariaLabel: i18n.translate('expressionTagcloud.functions.tagcloud.args.ariaLabelHelpText', {
defaultMessage: 'Specifies the aria label of the tagcloud',
}),
isPreview: i18n.translate('expressionTagcloud.functions.tagcloud.args.isPreviewHelpText', {
defaultMessage: 'Set isPreview to true to avoid showing out of room warnings',
}),
},
dimension: {
tags: i18n.translate('expressionTagcloud.functions.tagcloud.dimension.tags', {
Expand Down Expand Up @@ -81,7 +84,7 @@ export const errors = {
};

export const tagcloudFunction: ExpressionTagcloudFunction = () => {
const { help, args: argHelp, dimension } = strings;
const { help, argHelp, dimension } = strings;

return {
name: EXPRESSION_NAME,
Expand Down Expand Up @@ -137,6 +140,12 @@ export const tagcloudFunction: ExpressionTagcloudFunction = () => {
help: argHelp.ariaLabel,
required: false,
},
isPreview: {
types: ['boolean'],
help: argHelp.isPreview,
default: false,
required: false,
},
},
fn(input, args, handlers) {
validateAccessor(args.metric, input.columns);
Expand All @@ -157,6 +166,7 @@ export const tagcloudFunction: ExpressionTagcloudFunction = () => {
args.ariaLabel ??
(handlers.variables?.embeddableTitle as string) ??
handlers.getExecutionContext?.()?.description,
isPreview: Boolean(args.isPreview),
};

if (handlers?.inspectorAdapters?.tables) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
*/

export { EXPRESSION_NAME, ScaleOptions, Orientation } from './constants';

export type { ExpressionTagcloudFunctionDefinition } from './types/expression_functions';
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common';
import { EXPRESSION_NAME, ScaleOptions, Orientation } from '../constants';

interface TagCloudCommonParams {
scale: $Values<typeof ScaleOptions>;
scale?: $Values<typeof ScaleOptions>;
orientation: $Values<typeof Orientation>;
minFontSize: number;
maxFontSize: number;
showLabel: boolean;
ariaLabel?: string;
metric: ExpressionValueVisDimension | string;
bucket?: ExpressionValueVisDimension | string;
palette: PaletteOutput;
}

export interface TagCloudVisConfig extends TagCloudCommonParams {
metric: ExpressionValueVisDimension | string;
bucket?: ExpressionValueVisDimension | string;
isPreview?: boolean;
}

export interface TagCloudRendererParams extends TagCloudCommonParams {
palette: PaletteOutput;
metric: ExpressionValueVisDimension | string;
bucket?: ExpressionValueVisDimension | string;
isPreview: boolean;
}

export interface TagcloudRendererConfig {
Expand All @@ -43,13 +43,11 @@ export interface TagcloudRendererConfig {
syncColors: boolean;
}

interface Arguments extends TagCloudVisConfig {
palette: PaletteOutput;
}

export type ExpressionTagcloudFunction = () => ExpressionFunctionDefinition<
'tagcloud',
export type ExpressionTagcloudFunctionDefinition = ExpressionFunctionDefinition<
typeof EXPRESSION_NAME,
Datatable,
Arguments,
TagCloudVisConfig,
ExpressionValueRender<TagcloudRendererConfig>
>;

export type ExpressionTagcloudFunction = () => ExpressionTagcloudFunctionDefinition;
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"requiredBundles": [
"kibanaUtils",
"kibanaReact"
],
"extraPublicDirs": [
"common"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const config: TagcloudRendererConfig = {
format: { id: 'string', params: {} },
},
palette: { type: 'palette', name: 'default' },
isPreview: false,
},
syncColors: false,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const visParams: TagCloudRendererParams = {
minFontSize: 12,
maxFontSize: 70,
showLabel: true,
isPreview: false,
};

const formattedData: WordcloudSpec['data'] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ import React, { useCallback, useState, useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { throttle } from 'lodash';
import { EuiIconTip, EuiResizeObserver } from '@elastic/eui';
import { IconChartTagcloud } from '@kbn/chart-icons';
import { Chart, Settings, Wordcloud, RenderChangeListener } from '@elastic/charts';
import { EmptyPlaceholder } from '@kbn/charts-plugin/public';
import type { PaletteRegistry, PaletteOutput } from '@kbn/coloring';
import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/public';
import {
getColumnByAccessor,
getAccessor,
getFormatByAccessor,
} from '@kbn/visualizations-plugin/common/utils';
import { getColumnByAccessor, getFormatByAccessor } from '@kbn/visualizations-plugin/common/utils';
import { getFormatService } from '../format_service';
import { TagcloudRendererConfig } from '../../common/types';
import { ScaleOptions, Orientation } from '../../common/constants';
Expand Down Expand Up @@ -153,6 +151,11 @@ export const TagCloudChart = ({
const termsBucketId = getColumnByAccessor(bucket, visData.columns)!.id;
const clickedValue = elements[0][0].text;

const columnIndex = visData.columns.findIndex((col) => col.id === termsBucketId);
if (columnIndex < 0) {
return;
}

const rowIndex = visData.rows.findIndex((row) => {
const formattedValue = bucketFormatter
? bucketFormatter.convert(row[termsBucketId], 'text')
Expand All @@ -170,7 +173,7 @@ export const TagCloudChart = ({
data: [
{
table: visData,
column: getAccessor(bucket),
column: columnIndex,
row: rowIndex,
},
],
Expand All @@ -180,6 +183,10 @@ export const TagCloudChart = ({
[bucket, bucketFormatter, fireEvent, visData]
);

if (visData.rows.length === 0) {
return <EmptyPlaceholder icon={IconChartTagcloud} renderComplete={renderComplete} />;
}

return (
<EuiResizeObserver onResize={updateChart}>
{(resizeRef) => (
Expand Down Expand Up @@ -215,7 +222,7 @@ export const TagCloudChart = ({
{label}
</div>
)}
{warning && (
{!visParams.isPreview && warning && (
<div className="tgcChart__warning">
<EuiIconTip
type="warning"
Expand All @@ -229,7 +236,7 @@ export const TagCloudChart = ({
/>
</div>
)}
{tagCloudData.length > MAX_TAG_COUNT && (
{!visParams.isPreview && tagCloudData.length > MAX_TAG_COUNT && (
<div className="tgcChart__warning">
<EuiIconTip
type="warning"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ export const tagcloudRenderer: (

const palettesRegistry = await plugins.charts.palettes.getPalettes();

const showNoResult = config.visData.rows.length === 0;

render(
<KibanaThemeProvider theme$={core.theme.theme$}>
<I18nProvider>
Expand All @@ -81,7 +79,6 @@ export const tagcloudRenderer: (
// It is used for rendering at `Canvas`.
className={cx('tagCloudContainer', css(tagCloudVisClass))}
renderComplete={renderComplete}
showNoResult={showNoResult}
>
<TagCloudChart
{...config}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@kbn/kibana-react-plugin",
"@kbn/analytics",
"@kbn/chart-expressions-common",
"@kbn/chart-icons",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"ariaLabel":null,"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":null,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}}
{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"ariaLabel":null,"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"isPreview":false,"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":null,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"ariaLabel":null,"bucket":{"accessor":1,"format":{"id":"number"},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":null,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}}
{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"ariaLabel":null,"bucket":{"accessor":1,"format":{"id":"number"},"type":"vis_dimension"},"isPreview":false,"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":null,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}}
Loading

0 comments on commit ec62e15

Please sign in to comment.