Library / SDK
medialab/iwanthue avatar
medialab/iwanthue

iWantHue: generating categorical palettes that stay distinguishable

Colors for data scientists.

693 stars60 forksHTMLNOASSERTION

At a glance

What is it?
A JavaScript library and web tool that generate palettes of perceptually distinct colours by optimising a distance metric in the CIE Lab space, with a colourblind mode, a categorical Palette helper and precomputed palettes shipped in the npm package. It has been part of the Sciences Po MediaLab toolset for years.
Who is it for?
Adopt iWantHue if you assign colours to categories, a treemap, a chart series or a network diagram and you need the result to be readable rather than merely pretty, since that is exactly what the distance optimisation and the colourblind distance functions are for. Skip it if you need continuous or sequential scales, since this is built for categorical palettes of distinct hues.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 53 days ago.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is that charts need colours people can tell apart

iWantHue describes itself as colors for data scientists, and its aim is to generate and refine palettes of optimally distinct colors.

The problem it solves is narrow and very real. Any chart that maps categories to colours needs those colours to be distinguishable, and picking them by hand is worse than it sounds, because the constraint is perceptual rather than numerical. Two hex values that are far apart in RGB can look close, and two that are close in RGB can look far apart, depending on where they sit in the space.

The approach is to master the properties of a palette by setting a range of Hue, Chroma, described as unbiased saturation, and Lightness. You can generate palettes of any size, or you can take just the generator for a JavaScript project.

So there are two things here. There is a web tool at tools.medialab.sciences-po.fr/iwanthue/ where you set constraints and get a palette, with examples, a tutorial, explanations of the theory and an experiment on colour theory. And there is an npm module that does the same thing in code, so a chart library or a dashboard can generate a palette at runtime from its own data.

The audience is people who make charts, and the pitch is that this is the step between choosing colours arbitrarily and hand tuning them one by one.

Two colour spaces, one for maths and one for humans

The how it works section is three lines long and each line matters.

First, K-means or force vector repulsion algorithms ensure an even distribution of colors. Second, the CIE Lab color space is used for computation, since it fits human perception. Third, the Hue/Chroma/Lightness color space is used to set constraints, since it is user-friendly.

That split is the interesting engineering decision. Lab is a perceptually uniform-ish space, so a distance computed in it corresponds much better to how a difference looks than a distance computed in RGB, and that is what makes the resulting palette readable. But Lab is not a space a person thinks in, so the user interface exposes the polar HCL-style coordinates, where hue is the obvious knob and lightness is the obvious second one.

The result is a constraint set expressed in human terms and an optimisation performed in perceptual terms. You say which hues and how bright, and the algorithm works out the actual colours that are furthest apart under the chosen distance metric.

The two clustering algorithms are the two ways of doing that spreading. K-means is the classic partitioning approach, and force vector repulsion is the physical intuition where every colour pushes the others away. Both appear again in the precomputed palette names at the end of the readme, which is a good sign that the choice is meant to be visible to the user rather than hidden.

The idea behind the project is stated as distributing colors evenly, in a perceptively coherent space, constrained by user-friendly settings, to generate high quality custom palettes.

The distance function is the setting that decides readability

The settings list is where the tool earns its keep, and one option matters more than the rest.

The distance setting defaults to euclidean, and the readme lists the alternatives: cmc, compromise, protanope, deuteranope or tritanope. The last three are named after the three common forms of colour vision deficiency, and compromise is described as colourblind.

That is the feature that distinguishes iWantHue from a generic colour picker. Euclidean distance in Lab asks whether two colours are different. A protanope distance asks whether two colours are different for a viewer with protanopia, which is a different and stricter question, and it produces a palette that separates categories that a normal viewer would already have told apart easily.

The other settings tune the search rather than the result. The clustering option defaults to k-means and can also be force-vector. The quality setting defaults to 50 and is an iterations factor for force-vector and colorspace sampling for k-means. The attempts option defaults to 1 and is the number of times the function tries to generate a palette in order to keep only the one maximizing the minimum distance between two of the palette colors, so a single attempt by default. There is an ultraPrecision boolean for k-means colorspace sampling.

Two more settings make the output reproducible and extensible. The seed option takes a string or a number as a random number generator seed, which the readme says is useful to produce the same palette every time based on some data attribute. And originalColorsToExpand takes a list of existing colours to expand by adding new colours, using the smallest preset containing all given colours if no colorSpace is set.

The colorSpace setting itself accepts a preset name, or you can pass a [hmin, hmax, cmin, cmax, lmin, lmax] array or an object with the same keys, where keys can be omitted.

Using it from code, and the settings that change the output

The library installs from npm for both Node.js and the browser:

bash
npm install iwanthue

The call is a function with a count and an optional settings object:

js
var iwanthue = require('iwanthue');

// Generate a simple palette with 5 colors
var palette = iwanthue(5);

// With some options
var palette = iwanthue(5, {
  clustering: 'force-vector',
  seed: 'cool-palette',
  quality: 100
});

The count is the number of colors in the generated palette, and the settings object is the one described above. The two calls show the interesting combination: force-vector clustering with a higher quality factor and a named seed, which is how you get a reproducible, more carefully spread palette.

The colourSpace preset names live in a file called presets.js in the npm directory of the repository, and the readme points you there for the full list, or at the website to try them.

One design decision worth noting is that the seed is a string as readily as a number, and the readme describes it as useful to produce the same palette every time based on some data attribute. That means you can derive a stable seed from the data you are colouring, for example a category name or a table name, and get the same colours for the same category on every page load and across runs. Without that, a chart that regenerates its palette on each render will show different colours for the same category every time, which is a real problem in dashboards and for anyone comparing screenshots.

The Palette helper, and precomputed palettes for a fast start

There are two ways to consume the output, and they suit different situations.

The first is the Palette helper class, described as a helper class representing a categorical color palette over a set of given values. It is required from its own subpath, iwanthue/palette, and it comes with three constructors:

js
// To build your palette from a unique list of values
var Palette = require('iwanthue/palette');

var palette = Palette.generateFromValues(
  'cities',
  ['one', 'two', 'three'],
  {defaultColor: '#000'}
);

palette.get('one');
>>> '#19d3a2'

palette.get('unknown');
>>> '#000'

There is also a fromEntries form taking key, value entries and a fromMapping form taking a mapping object or Map, and a fromJSON form taking serialized palette data with name, defaultColor and entries.

The important behaviour is the fallback. The default color is returned in case the desired value is not known, and the members are name, size, defaultColor and a map from values to colors, with methods get, has, forEach, colors and toJSON. The name argument is used as the seed for iwanthue, so the same category name always produces the same colours.

The second route is precomputed palettes. If you don't want to load iwanthue's whole code into your client app, or you just want to prototype things quickly, the npm module also packs some precomputed palettes you can import. All of the presets export palettes ranging from 2 to 15 colors:

js
// Default palettes
var palettes = require('iwanthue/precomputed');

// Need a palette for 6 colors:
var sixColorsPalette = palettes[6];

// K-means palettes
var palettes = require('iwanthue/precomputed/k-means');

// Force vector palettes
var palettes = require('iwanthue/precomputed/force-vector');

// Colorblind alternatives
var palettes = require('iwanthue/precomputed/k-means-colorblind');
var palettes = require('iwanthue/precomputed/force-vector-colorblind');

So there is a fixed palette for every size from 2 to 15, in the default flavour, in each clustering flavour, and in colourblind variants. That is the option for a dashboard that wants a stable palette with no computation at all.

A PHP site and an npm package sharing one repository

The repository is two things at once, and the tree shows both.

The web tool is PHP. There is an index.php, palettes.php, tutorial.php, theory.php, experiment.php, examples.php, completion.php and corrector.php, plus an example_treemap.php, and directories for css, img, includes, res and js. It is a static site generated from those templates, which is why the build tooling exists.

The build tooling is the npm part. The package manifest in the repository root is not the library itself but iwanthue-build, marked private, with the description Scripts to build static site. The build script removes the build directory and runs node build.js with three environment variables set from the package config: MATOMO_ANALYTICS, TWEET and PREFIX, where the config values are 20, iWantHue: make clever color palettes, and the path /iwanthue/. The deploy script runs the build and then pushes to gh-pages.

So the site is deployed to GitHub Pages under a path prefix, with Matomo analytics enabled by configuration and a share text for the social card. The actual library is the separate npm package built from the npm directory in the tree.

The dependency list of the build tooling is small and tells you it is a static site generator rather than a framework. There is escape-string-regexp, fs-extra, gh-pages and glob, and that is the whole list. No template engine, no bundler, because the site is PHP rendered and the build step appears to assemble static output.

The author is credited as yomguithereal, and the repository carries both a COPYING file, a LICENSE.CECILL-C file and a LICENSE.LGPL file, while the package manifest for the build tooling says MIT. That split is worth noticing if you are choosing a licence for your own use of the tool or the data.

Where iWantHue is the wrong tool

There are clear limits, and they follow from the tool being built for one kind of colour problem.

The first is that this is for categorical palettes. Distinct, separable colours for a finite set of categories is exactly the problem the distance optimisation solves. It is not a tool for sequential or diverging scales, where you want a smooth ramp across a continuous variable, and using a palette generator for that would be the wrong instrument entirely.

The second is the number of categories. The distance optimisation spreads colours apart in a perceptual space, and a space has a finite amount of room. The precomputed palettes stop at 15 colours, which is a reasonable signal of where the method stops being comfortable, and asking for a hundred distinct, equally distinguishable colours is not a request any palette generator can satisfy.

The third is the cost of the search. The attempts setting exists because a single generation can land on a poor arrangement, and keeping only the palette that maximises the minimum distance means generating several and comparing them. On a large dataset with a colourblind distance function and a high quality factor, that is real computation, which is exactly why the precomputed palettes exist as an escape hatch.

The fourth is that colour alone is not enough for accessibility. A palette that is distinguishable for a protanope viewer is better, but a chart that relies on colour alone to distinguish series is still failing for readers who cannot see the difference at all, and no amount of palette optimisation fixes that. The distance functions reduce the problem, they do not solve it.

And the fifth is the state of the project. The repository is not archived, but the last push was on 2026-09-02 and there are no GitHub releases, so the version you get is whatever npm last published, and the readme in the repository root is the one that describes the API you can rely on. The web tool at the sciences-po.fr address is the place to try the presets, and it is the artefact most people actually use.

Editorial conclusion

Adopt iWantHue if you assign colours to categories, a treemap, a chart series or a network diagram and you need the result to be readable rather than merely pretty, since that is exactly what the distance optimisation and the colourblind distance functions are for. Skip it if you need continuous or sequential scales, since this is built for categorical palettes of distinct hues. Verify first which distance function you want, because euclidean, cmc, compromise, protanope, deuteranope and tritanope give different results, and check the seed option so that the same input data produces the same palette every time.

Frequently asked questions

How do I install and use iwanthue?

Install it with npm install iwanthue for Node.js or the browser, then require it and call it with a count and optional settings. A simple call is iwanthue(5), and passing a settings object such as { clustering: 'force-vector', seed: 'cool-palette', quality: 100 } gives a reproducible, more carefully spread palette.

Which colour spaces does iwanthue use and why?

K-means or force vector repulsion algorithms ensure an even distribution of colours, the CIE Lab colour space is used for computation since it fits human perception, and the Hue, Chroma and Lightness space is used to set constraints since it is user friendly. You can pass a colorSpace preset name, a [hmin, hmax, cmin, cmax, lmin, lmax] array, or an object with the same keys.

Does iWantHue produce colourblind friendly palettes?

Yes. The distance setting can be euclidean, cmc, compromise, which is described as colourblind, protanope, deuteranope or tritanope, and the precomputed palettes include k-means-colorblind and force-vector-colorblind variants. You can also raise the attempts setting so the algorithm keeps the palette that maximises the minimum distance between colours.

What is the Palette helper in iwanthue?

It is a helper class representing a categorical colour palette over a set of given values, required from iwanthue/palette. You can build it with generateFromValues, fromEntries, fromMapping or fromJSON, and it exposes name, size, defaultColor and a map, with get, has, forEach, colors and toJSON methods, returning the default colour for unknown values.

What are the precomputed palettes in the iwanthue npm package?

If you don't want to load iwanthue's whole code into your client app, or you just want to prototype things quickly, the module packs precomputed palettes importable from iwanthue/precomputed and its k-means, force-vector, k-means-colorblind and force-vector-colorblind variants. All of the presets export palettes ranging from 2 to 15 colors.

How do I get the same palette every time in iwanthue?

Use the seed setting, which takes a string or a number as a random number generator seed and is described as useful to produce the same palette every time based on some data attribute. The Palette helper also uses its name argument as the seed, so the same category name always yields the same colours.

Official sources

  1. Issues
  2. medialab/iwanthue on GitHub
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/medialab-iwanthue.svg)](https://hysenlabs.com/projects/medialab-iwanthue)

Was this useful?