d3-jnd is a D3 extension that supports just-noticeable difference calculations for color based on work done by Maureen Stone, Danielle Albers Szafir, and Vidya Setlur [1].
d3-jnd is open sourced here. If you want to look at or use the compiled extension without downloading the source code, check it out on unpkg.
The just-noticeable difference functions in this library can be used to determine whether two colors are too similar to be easily differentiated. This is often critical for visualization color design because information legibility directly affects usability.
The two functions in d3-jnd are:
d3.noticeablyDifferent(…)
, which returns true or false
based on whether the two colors are noticeably different (i.e., ≥1
JND distant).d3.jndLabInterval(…)
, which returns the minimum JND
intervals for CIELAB L*, a*, and b* color channels.
Each interval can be thought of as "1 JND" unit for that channel, and
it is often sufficient to only have one channel that is ≥1 JND to
maintain legibility.
Be sure to check that colors that meet the recommended L*, a*, and b* intervals still fall within displayable RGB color space when considering the intervals that jndLabInterval provides.
Table of contentsTo access the latest version of d3-jnd, grab it on unpkg. Be sure to load d3-jnd after d3-color is loaded (be it through d3.v4.js, d3-color.js, or otherwise).
If installing and building from scratch, download the repo either through
GitHub or through
npm.
Once you've downloaded it, just run npm install
, which will
install the required dependencies.
Note that building requires
node.js and
npm.
D3 module dependencies: d3-color.
A just-noticeable difference (JND) is, "the amount [that a color] must be changed in order for a difference to be noticeable" [2]. Or, phrased another way, how different do two colors need to be in order for humans to recognize them as different? Given that this differentiability is directly dependent on human color vision, d3-jnd performs JND calculations using CIELAB, which is a perceptually modeled color space.
CIELAB defines color in terms of its perceptual lightness (L*), redness-to-greenness (a*), and blueness-to-yellowness (b*). d3-jnd does color conversion for you, so it's not critical to become an expert if you're just using the noticeablyDifferent function. If you're interested in learning more, check out Wikipedia's entry on CIELAB [3] or the d3-cam02 library to learn more about CIECAM02, which is an updated and more accurate perceptual color space. In this library we use CIELAB because it is what Stone, Szafir, and Setlur used in their experiments to derive regression-based JND formulas.
Unfortunately, determining whether two colors are discriminable is an involved process in part because it is harder to discriminate colors that are smaller in area. You can see this for yourself in the example below.
Because size in this context is a physical property that can greatly vary with viewing conditions (e.g., dpi or viewing distance with phones compared to laptops), d3-jnd uses visual angle as a measurement of size rather than pixels. At arms length, the width of a thumb's knuckle is approximately 2° and an index fingernail is approximately 1°. d3-jnd uses a default colored area size assumption of 0.1°, which was selected as a conservatively small size without resulting in overly restrictive color selection; however, the default assumed size can be overridden to create more generous or strict JND distances.
The physical size of visualizations can affect usability in a number of ways that include, but are not limited to, color legibility. If you're interested in learning more, we suggest Connor C. Gramazio, Karen B. Schloss, David H. Laidlaw's paper on size's affect on visualization search [4] and Maureen Stone's IEEE Viewpoint article [5].
Due to differences between people's perceptual acuity, the JND intervals that d3-jnd provides are predictions, not absolute truth. To accomodate this ambiguity, the d3-jnd functions' percentage argument can be used to incorporate what percentage of your audience should quickly and easily notice a difference in color. The default value used by d3-jnd is 50%, given that using 50% to refer to JNDs is standard practice in perception research; however, whether that threshold is sufficient for a visualization is contextually dependent. We encourage d3-jnd users to carefully consider whether they need to use a more conservative number (e.g., require JND intervals where an estimated 95% of users could reliably differentiate colors).
Another important individual difference to consider is people's different perceptions of color (e.g., red-green or blue-yellow color vision deficiencies). Given that a large portion of the population perceive color differently, consider whether the recommended L*, a*, or *b intervals you choose to use are sufficient. For example, a* modulates the redness-to-greeness of color and differences along only this channel might not be visible to all.
Although two colors might appear discriminable on your own monitor, consider whether that discriminability would be visible on your audience's displays. Developers and designers often use bright monitors that support wide color gamuts (e.g., any Apple device), which is not representative of displays used by the general population. Further, color can be aversely affected by environment (e.g., indoor vs. outdoor lighting). It is important to treat d3-jnd as only a prediction or recommendation of what may be noticeably different rather than an absolute truth.
Interactive demo of how changing percent and size JND arguments can alter L*, a*, and b* intervals.
Provided free-to-use and open-sourced. See Github for specific licensing information.