feat(superset-ui-core): add feature flag for the analogous colors (#19987)

* feat(superset-ui-core): add feature flag for the color analogous generator

* fix: test
This commit is contained in:
Stephen Liu 2022-06-03 21:32:32 +08:00 committed by GitHub
parent 766f737728
commit 80b5578680
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 19 deletions

View File

@ -24,6 +24,7 @@ import { ColorsLookup } from './types';
import stringifyAndTrim from './stringifyAndTrim'; import stringifyAndTrim from './stringifyAndTrim';
import getSharedLabelColor from './SharedLabelColorSingleton'; import getSharedLabelColor from './SharedLabelColorSingleton';
import { getAnalogousColors } from './utils'; import { getAnalogousColors } from './utils';
import { FeatureFlag, isFeatureEnabled } from '../utils';
// Use type augmentation to correct the fact that // Use type augmentation to correct the fact that
// an instance of CategoricalScale is also a function // an instance of CategoricalScale is also a function
@ -79,13 +80,15 @@ class CategoricalColorScale extends ExtensibleFunction {
return forcedColor; return forcedColor;
} }
const multiple = Math.floor( if (isFeatureEnabled(FeatureFlag.USE_ANALAGOUS_COLORS)) {
this.domain().length / this.originColors.length, const multiple = Math.floor(
); this.domain().length / this.originColors.length,
if (multiple > this.multiple) { );
this.multiple = multiple; if (multiple > this.multiple) {
const newRange = getAnalogousColors(this.originColors, multiple); this.multiple = multiple;
this.range(this.originColors.concat(newRange)); const newRange = getAnalogousColors(this.originColors, multiple);
this.range(this.originColors.concat(newRange));
}
} }
const color = this.scale(cleanedValue); const color = this.scale(cleanedValue);

View File

@ -18,7 +18,7 @@
*/ */
import { CategoricalColorNamespace } from '.'; import { CategoricalColorNamespace } from '.';
import makeSingleton from '../utils/makeSingleton'; import { FeatureFlag, isFeatureEnabled, makeSingleton } from '../utils';
import { getAnalogousColors } from './utils'; import { getAnalogousColors } from './utils';
export class SharedLabelColor { export class SharedLabelColor {
@ -37,25 +37,39 @@ export class SharedLabelColor {
if (colorScheme) { if (colorScheme) {
const categoricalNamespace = const categoricalNamespace =
CategoricalColorNamespace.getNamespace(colorNamespace); CategoricalColorNamespace.getNamespace(colorNamespace);
const colors = categoricalNamespace.getScale(colorScheme).range();
const sharedLabels = this.getSharedLabels(); const sharedLabels = this.getSharedLabels();
let generatedColors: string[] = []; let generatedColors: string[] = [];
let sharedLabelMap; let sharedLabelMap;
if (sharedLabels.length) { if (sharedLabels.length) {
const multiple = Math.ceil(sharedLabels.length / colors.length); const colorScale = categoricalNamespace.getScale(colorScheme);
generatedColors = getAnalogousColors(colors, multiple); const colors = colorScale.range();
sharedLabelMap = sharedLabels.reduce( if (isFeatureEnabled(FeatureFlag.USE_ANALAGOUS_COLORS)) {
(res, label, index) => ({ const multiple = Math.ceil(sharedLabels.length / colors.length);
...res, generatedColors = getAnalogousColors(colors, multiple);
[label.toString()]: generatedColors[index], sharedLabelMap = sharedLabels.reduce(
}), (res, label, index) => ({
{}, ...res,
); [label.toString()]: generatedColors[index],
}),
{},
);
} else {
// reverse colors to reduce color conflicts
colorScale.range(colors.reverse());
sharedLabelMap = sharedLabels.reduce(
(res, label) => ({
...res,
[label.toString()]: colorScale(label),
}),
{},
);
}
} }
const labelMap = Object.keys(this.sliceLabelColorMap).reduce( const labelMap = Object.keys(this.sliceLabelColorMap).reduce(
(res, sliceId) => { (res, sliceId) => {
// get new color scale instance
const colorScale = categoricalNamespace.getScale(colorScheme); const colorScale = categoricalNamespace.getScale(colorScheme);
return { return {
...res, ...res,

View File

@ -54,6 +54,7 @@ export enum FeatureFlag {
ALLOW_FULL_CSV_EXPORT = 'ALLOW_FULL_CSV_EXPORT', ALLOW_FULL_CSV_EXPORT = 'ALLOW_FULL_CSV_EXPORT',
UX_BETA = 'UX_BETA', UX_BETA = 'UX_BETA',
GENERIC_CHART_AXES = 'GENERIC_CHART_AXES', GENERIC_CHART_AXES = 'GENERIC_CHART_AXES',
USE_ANALAGOUS_COLORS = 'USE_ANALAGOUS_COLORS',
} }
export type ScheduleQueriesProps = { export type ScheduleQueriesProps = {
JSONSCHEMA: { JSONSCHEMA: {

View File

@ -18,7 +18,7 @@
*/ */
import { ScaleOrdinal } from 'd3-scale'; import { ScaleOrdinal } from 'd3-scale';
import { CategoricalColorScale } from '@superset-ui/core'; import { CategoricalColorScale, FeatureFlag } from '@superset-ui/core';
describe('CategoricalColorScale', () => { describe('CategoricalColorScale', () => {
it('exists', () => { it('exists', () => {
@ -62,7 +62,36 @@ describe('CategoricalColorScale', () => {
expect(c2).not.toBe(c3); expect(c2).not.toBe(c3);
expect(c3).not.toBe(c1); expect(c3).not.toBe(c1);
}); });
it('recycles colors when number of items exceed available colors', () => {
window.featureFlags = {
[FeatureFlag.USE_ANALAGOUS_COLORS]: false,
};
const colorSet: { [key: string]: number } = {};
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
const colors = [
scale.getColor('pig'),
scale.getColor('horse'),
scale.getColor('cat'),
scale.getColor('cow'),
scale.getColor('donkey'),
scale.getColor('goat'),
];
colors.forEach(color => {
if (colorSet[color]) {
colorSet[color] += 1;
} else {
colorSet[color] = 1;
}
});
expect(Object.keys(colorSet)).toHaveLength(3);
['blue', 'red', 'green'].forEach(color => {
expect(colorSet[color]).toBe(2);
});
});
it('get analogous colors when number of items exceed available colors', () => { it('get analogous colors when number of items exceed available colors', () => {
window.featureFlags = {
[FeatureFlag.USE_ANALAGOUS_COLORS]: true,
};
const scale = new CategoricalColorScale(['blue', 'red', 'green']); const scale = new CategoricalColorScale(['blue', 'red', 'green']);
scale.getColor('pig'); scale.getColor('pig');
scale.getColor('horse'); scale.getColor('horse');

View File

@ -425,6 +425,7 @@ DEFAULT_FEATURE_FLAGS: Dict[str, bool] = {
"UX_BETA": False, "UX_BETA": False,
"GENERIC_CHART_AXES": False, "GENERIC_CHART_AXES": False,
"ALLOW_ADHOC_SUBQUERY": False, "ALLOW_ADHOC_SUBQUERY": False,
"USE_ANALAGOUS_COLORS": True,
# Apply RLS rules to SQL Lab queries. This requires parsing and manipulating the # Apply RLS rules to SQL Lab queries. This requires parsing and manipulating the
# query, and might break queries and/or allow users to bypass RLS. Use with care! # query, and might break queries and/or allow users to bypass RLS. Use with care!
"RLS_IN_SQLLAB": False, "RLS_IN_SQLLAB": False,