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

Palette by terms #119735

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
61e391c
[WIP] Color by terns
stratoula Nov 24, 2021
92b6688
Merge branch 'main' into palette-by-terms
stratoula Nov 24, 2021
b41dc1f
Make the custom palette dynamic
stratoula Nov 24, 2021
6950884
Introduce new SO type and save to library
stratoula Nov 25, 2021
3bba179
Load saved palettes
stratoula Nov 25, 2021
51233fe
Merge with main and add more functionality
stratoula Nov 25, 2021
fddf2cf
Merge branch 'main' into palette-by-terms
kibanamachine Nov 29, 2021
d224de5
Add terms palette in partition charts
stratoula Nov 29, 2021
cb22de3
Add save capabilities to the color palette
stratoula Nov 29, 2021
cccb9cc
Palette by terms with different field
stratoula Nov 30, 2021
54c21d9
Fix types, change SO icon
stratoula Nov 30, 2021
93572b3
Add saving capabilities to datatable palette
stratoula Nov 30, 2021
af0764b
Fix type
stratoula Nov 30, 2021
407c4b0
Fix test
stratoula Nov 30, 2021
df13324
Merge branch 'main' into palette-by-terms
stratoula Nov 30, 2021
c4a5136
Merge branch 'main' into palette-by-terms
stratoula Nov 30, 2021
c113629
Fixes test
stratoula Nov 30, 2021
0d88d6b
Save palette is permitted only for visualize.save capabilities
stratoula Dec 1, 2021
b2b833c
Fix some bugs
stratoula Dec 1, 2021
f43629d
More fixes
stratoula Dec 1, 2021
6b979c3
Make the palette more difficult to be saved
stratoula Dec 1, 2021
59db6e6
Merge branch 'main' into palette-by-terms
stratoula Dec 2, 2021
ad028c3
Fixes
stratoula Dec 2, 2021
53fa83d
Fix color stops memo
stratoula Dec 2, 2021
748de43
Merge branch 'main' into palette-by-terms
stratoula Dec 3, 2021
94bde63
Fix display of compatibility palette
stratoula Dec 3, 2021
5e70cf3
Fix CI
stratoula Dec 3, 2021
2ab506c
Merge branch 'main' into palette-by-terms
kibanamachine Dec 6, 2021
f1653e1
Merge branch 'main' into palette-by-terms
stratoula Dec 7, 2021
77602f3
Merge branch 'main' into palette-by-terms
stratoula Dec 13, 2021
dd049f3
Merge branch 'main' into palette-by-terms
kibanamachine Dec 15, 2021
dc62dfa
Merge branch 'main' into palette-by-terms
kibanamachine Dec 16, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const previouslyRegisteredTypes = [
'legacy-url-alias',
'lens',
'lens-ui-telemetry',
'palette',
'map',
'maps-telemetry',
'metrics-explorer-view',
Expand Down
19 changes: 18 additions & 1 deletion src/plugins/charts/common/palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface CustomPaletteArguments {
gradient: boolean;
reverse?: boolean;
stop?: number[];
term?: string[];
range?: 'number' | 'percent';
rangeMin?: number;
rangeMax?: number;
Expand All @@ -26,6 +27,7 @@ export interface CustomPaletteState {
colors: string[];
gradient: boolean;
stops: number[];
terms?: string[];
range: 'number' | 'percent';
rangeMin: number;
rangeMax: number;
Expand Down Expand Up @@ -104,6 +106,15 @@ export function palette(): ExpressionFunctionDefinition<
}),
required: false,
},
term: {
multi: true,
types: ['string'],
help: i18n.translate('charts.functions.palette.args.termHelpText', {
defaultMessage:
'The palette color terms. When used, it must be associated with each color.',
}),
required: false,
},
continuity: {
types: ['string'],
options: ['above', 'below', 'all', 'none'],
Expand Down Expand Up @@ -142,13 +153,18 @@ export function palette(): ExpressionFunctionDefinition<
},
},
fn: (input, args) => {
const { color, continuity, reverse, gradient, stop, range, rangeMin, rangeMax } = args;
const { color, continuity, reverse, gradient, stop, range, rangeMin, rangeMax, term } = args;
const colors = ([] as string[]).concat(color || defaultCustomColors);
const stops = ([] as number[]).concat(stop || []);
const terms = ([] as string[]).concat(term || []);
if (stops.length > 0 && colors.length !== stops.length) {
throw Error('When stop is used, each color must have an associated stop value.');
}

if (terms.length > 0 && colors.length !== terms.length) {
throw Error('When term is used, each color must have an associated term value.');
}

// If the user has defined stops, choose rangeMin/Max, provided by user or range,
// taken from first/last element of ranges or default range (0 or 100).
const calculateRange = (
Expand All @@ -165,6 +181,7 @@ export function palette(): ExpressionFunctionDefinition<
name: 'custom',
params: {
colors: reverse ? colors.reverse() : colors,
terms,
stops,
range: range ?? 'percent',
gradient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ describe('palettes', () => {
reverse: [false],
continuity: ['above'],
stop: [],
term: [],
range: ['percent'],
rangeMax: [],
rangeMin: [],
Expand Down
36 changes: 31 additions & 5 deletions src/plugins/charts/public/services/palettes/palettes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function buildRoundRobinCategoricalWithMappedColors(): Omit<PaletteDefinition, '
return {
id: 'default',
getCategoricalColor: getColor,
getCategoricalColors: () => euiPaletteColorBlind(),
getCategoricalColors: (size?: number) => colors.slice(0, size ?? 10),
toExpression: () => ({
type: 'expression',
chain: [
Expand Down Expand Up @@ -144,7 +144,7 @@ function buildSyncedKibanaPalette(
return {
id: 'kibana_palette',
getCategoricalColor: getColor,
getCategoricalColors: () => colors.seedColors.slice(0, 10),
getCategoricalColors: (size?: number) => staticColors.slice(0, size ?? 10),
toExpression: () => ({
type: 'expression',
chain: [
Expand Down Expand Up @@ -172,6 +172,7 @@ function buildCustomPalette(): PaletteDefinition {
gradient: boolean;
/** Stops values mark where colors end (non-inclusive value) */
stops: number[];
terms: string[];
/** Important: specify rangeMin/rangeMax if custom stops are defined! */
rangeMax: number;
rangeMin: number;
Expand All @@ -183,12 +184,19 @@ function buildCustomPalette(): PaletteDefinition {
getCategoricalColor: (
series: SeriesLayer[],
chartConfiguration: ChartColorConfiguration = { behindText: false },
{ colors, gradient }: { colors: string[]; gradient: boolean }
{ colors, gradient, terms }: { colors: string[]; gradient: boolean; terms: string[] }
) => {
const actualColors = gradient
? chroma.scale(colors).colors(series[0].totalSeriesAtDepth)
: colors;
const outputColor = actualColors[series[0].rankAtDepth % actualColors.length];
let outputColor = actualColors[series[0].rankAtDepth % actualColors.length];

if (terms && terms.length > 0) {
const idx = terms.findIndex((term) => term === series[0].name);
if (idx !== -1) {
outputColor = colors[idx];
}
}

if (!chartConfiguration.maxDepth || chartConfiguration.maxDepth === 1) {
return outputColor;
Expand All @@ -205,11 +213,19 @@ function buildCustomPalette(): PaletteDefinition {
gradient,
stepped,
stops,
}: { colors: string[]; gradient: boolean; stepped: boolean; stops: number[] } = {
terms,
}: {
colors: string[];
gradient: boolean;
stepped: boolean;
stops: number[];
terms: string[];
} = {
colors: [],
gradient: false,
stepped: false,
stops: [],
terms: [],
}
) => {
if (stepped) {
Expand All @@ -218,13 +234,21 @@ function buildCustomPalette(): PaletteDefinition {
const finalStops = [...stops.map((stop) => (stop - offset) / range)];
return chroma.scale(colors).domain(finalStops).colors(size);
}
if (terms && terms.length > 0) {
const actualColors = gradient ? chroma.scale(colors).colors(terms.length) : colors;
return terms.map((term, index) => {
const outputColor = actualColors[index % actualColors.length];
return outputColor;
});
}
return gradient ? chroma.scale(colors).colors(size) : colors;
},
canDynamicColoring: false,
toExpression: ({
colors,
gradient,
stops = [],
terms = [],
rangeMax,
rangeMin,
rangeType = 'percent',
Expand All @@ -234,6 +258,7 @@ function buildCustomPalette(): PaletteDefinition {
colors: string[];
gradient: boolean;
stops: number[];
terms: string[];
rangeMax?: number;
rangeMin?: number;
rangeType: 'percent' | 'number';
Expand All @@ -251,6 +276,7 @@ function buildCustomPalette(): PaletteDefinition {
reverse: [reverse],
continuity: [continuity],
stop: stops,
term: terms,
range: [rangeType],
rangeMax: rangeMax == null ? [] : [rangeMax],
rangeMin: rangeMin == null ? [] : [rangeMin],
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/charts/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { schema } from '@kbn/config-schema';
import { CoreSetup, Plugin } from 'kibana/server';
import { COLOR_MAPPING_SETTING, LEGACY_TIME_AXIS, palette, systemPalette } from '../common';
import { ExpressionsServerSetup } from '../../expressions/server';
import { setupSavedObjects } from './saved_objects';

interface SetupDependencies {
expressions: ExpressionsServerSetup;
Expand All @@ -20,6 +21,8 @@ export class ChartsServerPlugin implements Plugin<object, object> {
public setup(core: CoreSetup, dependencies: SetupDependencies) {
dependencies.expressions.registerFunction(palette);
dependencies.expressions.registerFunction(systemPalette);
// setup palette saved objects type
setupSavedObjects(core);
core.uiSettings.register({
[COLOR_MAPPING_SETTING]: {
name: i18n.translate('charts.advancedSettings.visualization.colorMappingTitle', {
Expand Down
36 changes: 36 additions & 0 deletions src/plugins/charts/server/saved_objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 { CoreSetup } from 'kibana/server';

export function setupSavedObjects(core: CoreSetup) {
core.savedObjects.registerType({
name: 'palette',
hidden: false,
namespaceType: 'multiple-isolated',
management: {
icon: 'brush',
defaultSearchField: 'title',
importableAndExportable: true,
getTitle: (obj: { attributes: { title: string } }) => obj.attributes.title,
},
mappings: {
properties: {
title: {
type: 'text',
},
name: {
type: 'text',
},
params: {
type: 'flattened',
},
},
},
});
}
1 change: 1 addition & 0 deletions x-pack/plugins/lens/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const PLUGIN_ID = 'lens';
export const APP_ID = 'lens';
export const LENS_EMBEDDABLE_TYPE = 'lens';
export const DOC_TYPE = 'lens';
export const PALETTE_DOC_TYPE = 'palette';
export const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations';
export const BASE_API_URL = '/api/lens';
export const LENS_EDIT_BY_VALUE = 'edit_by_value';
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/lens/common/expressions/pie_chart/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import type { PaletteOutput } from '../../../../../../src/plugins/charts/common';
import type { LensMultiTable, LayerType } from '../../types';
import type { LensMultiTable, LayerType, CustomPaletteParams } from '../../types';

export type PieChartTypes = 'donut' | 'pie' | 'treemap' | 'mosaic' | 'waffle';

Expand All @@ -32,7 +32,7 @@ export type PieLayerState = SharedPieLayerState & {
export interface PieVisualizationState {
shape: PieChartTypes;
layers: PieLayerState[];
palette?: PaletteOutput;
palette?: PaletteOutput<CustomPaletteParams>;
}

export type PieExpressionArgs = SharedPieLayerState & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import type { PaletteOutput } from '../../../../../../src/plugins/charts/common';
import type { ExpressionFunctionDefinition } from '../../../../../../src/plugins/expressions/common';
import type { LayerType } from '../../types';
import type { LayerType, CustomPaletteParams } from '../../types';
import { layerTypes } from '../../constants';
import { axisConfig, YConfig } from './axis_config';
import type { SeriesType } from './series_type';
Expand All @@ -20,7 +20,7 @@ export interface XYLayerConfig {
yConfig?: YConfig[];
seriesType: SeriesType;
splitAccessor?: string;
palette?: PaletteOutput;
palette?: PaletteOutput<CustomPaletteParams>;
layerType: LayerType;
}

Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/lens/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export interface ColorStop {
stop: number;
}

export interface ColorTerm {
color: string;
term: string;
}

export interface CustomPaletteParams {
name?: string;
reverse?: boolean;
Expand All @@ -56,7 +61,10 @@ export interface CustomPaletteParams {
rangeMax?: number;
stops?: ColorStop[];
colorStops?: ColorStop[];
colorTerms?: ColorTerm[];
steps?: number;
title?: string;
paletteType?: string;
}
export type CustomPaletteParamsConfig = CustomPaletteParams & {
maxSteps?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import React from 'react';
import { EuiButtonGroup, EuiComboBox, EuiFieldText } from '@elastic/eui';
import type { SavedObjectsClientContract } from 'kibana/public';
import { FramePublicAPI, Operation, VisualizationDimensionEditorProps } from '../../types';
import { DatatableVisualizationState } from '../visualization';
import { createMockDatasource, createMockFramePublicAPI } from '../../mocks';
Expand All @@ -24,6 +25,8 @@ describe('data table dimension editor', () => {
let setState: (newState: DatatableVisualizationState) => void;
let props: VisualizationDimensionEditorProps<DatatableVisualizationState> & {
paletteService: PaletteRegistry;
savedObjectsClient: SavedObjectsClientContract;
canSavePalettes: boolean;
};

function testState(): DatatableVisualizationState {
Expand Down Expand Up @@ -60,6 +63,11 @@ describe('data table dimension editor', () => {
},
};
setState = jest.fn();
const savedObjectsClient = {
find: jest.fn(() => Promise.resolve({ page: 1, total: 0, savedObjects: [] })),
create: jest.fn(() => Promise.resolve({ id: 'testid' })),
resolve: jest.fn(),
} as unknown as SavedObjectsClientContract;
props = {
accessor: 'foo',
frame,
Expand All @@ -69,6 +77,8 @@ describe('data table dimension editor', () => {
setState,
paletteService: chartPluginMock.createPaletteRegistry(),
panelRef: React.createRef(),
savedObjectsClient,
canSavePalettes: true,
};
});

Expand Down
Loading