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

[Backport 2.x] [Vis Colors] Update color mapper to prioritize unique colors per vis #4898

Merged
merged 1 commit into from
Sep 1, 2023
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
2 changes: 1 addition & 1 deletion src/plugins/charts/public/services/colors/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ColorsService {
) {
if (!Array.isArray(arrayOfStringsOrNumbers)) {
throw new Error(
`createColorLookupFunction expects an array but recived: ${typeof arrayOfStringsOrNumbers}`
`createColorLookupFunction expects an array but received: ${typeof arrayOfStringsOrNumbers}`
);
}

Expand Down
28 changes: 15 additions & 13 deletions src/plugins/charts/public/services/colors/mapped_colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,34 +83,36 @@ export class MappedColors {
const configColors = _.values(configMapping);
const oldColors = _.values(this._oldMap);

const alreadyUsedColors: string[] = [];
const keysToMap: Array<string | number> = [];
_.each(keys, (key) => {
// If this key is mapped in the config, it's unnecessary to have it mapped here
if (configMapping[key as any]) delete this._mapping[key];
if (configMapping[key as any]) {
delete this._mapping[key];
alreadyUsedColors.push(configMapping[key]);
}

// If this key is mapped to a color used by the config color mapping, we need to remap it
if (_.includes(configColors, this._mapping[key])) keysToMap.push(key);

// if key exist in oldMap, move it to mapping
if (this._oldMap[key]) this._mapping[key] = this._oldMap[key];
if (this._oldMap[key]) {
this._mapping[key] = this._oldMap[key];
alreadyUsedColors.push(this._mapping[key]);
}

// If this key isn't mapped, we need to map it
if (this.get(key) == null) keysToMap.push(key);
});

// Generate a color palette big enough that all new keys can have unique color values
const allColors = _(this._mapping).values().union(configColors).union(oldColors).value();
const numColors = allColors.length + keysToMap.length;
// Choose colors from euiPaletteColorBlind and filter out any already assigned to keys
const colorPalette = euiPaletteColorBlind({
rotations: Math.ceil(numColors / 10),
rotations: Math.ceil(keys.length / 10),
direction: 'both',
}).slice(0, numColors);
let newColors = _.difference(colorPalette, allColors);
})
.filter((color) => !alreadyUsedColors.includes(color.toLowerCase()))
.slice(0, keysToMap.length);

while (keysToMap.length > newColors.length) {
newColors = newColors.concat(_.sampleSize(allColors, keysToMap.length - newColors.length));
}

_.merge(this._mapping, _.zipObject(keysToMap, newColors));
_.merge(this._mapping, _.zipObject(keysToMap, colorPalette));
}
}