Color palettes and accessibility features for data visualization

Colors can’t do it all. And data tables really aren’t so bad.



An illustration showing a grid of 6 images of the same eye in colors from the categorical palette.
Colors and perception

Last October, the Carbon team added Data Visualization (‘Carbon Charts’) to the growing family of open source libraries that deliver the IBM Design Language to software. Since then, we’ve published updates to the color palette, accessibility features, usage guidance, and major improvements to functionality and implementation.

This article aims to document our process, and also to share some of our underlying challenges. Open source systems can always use more bright minds, so we’d love to hear your thoughts!

A complex sub-system

Take one look at our website and you’ll see that Carbon’s data visualization library is like a mini-design system in itself. It has all the standard hierarchies of construction — elements, components, and patterns — each accompanied by usage guidance and code.

Elements, or primitives, are abstract and foundational. For example, color, typography, textures, shapes, iconography and in some cases motion. Although it may not seem as intuitive, we classify points, lines and (graph) areas as components because they are interactive and have reusable states. Finally, the chart type occupies the third level of this hierarchy. Since the charts are categorized by their use cases, chart types map to the way we think of patterns in the larger design system. This third level is where the system delivers the most value.

Elements include color, type styles; components include axis, legends, tooltips; Charts include trends, correlations, maps
Three levels of hierarchy (Elements, Components, and Charts) in the organization of Carbon Charts library

I will focus mainly on our work at the element and component level to maximize accessibility. Carbon Design System is compliant with the WCAG 2.1 web standard. The Success Criterion 1.4.11 Non-text Contrast (Level AA)—which describes that meaningful graphics has to be 3:1 contrast ratio against adjacent colors—poses a key challenge for data visualization. As we discussed in a previous article, some issues emerged with the first version of IBM’s brand color palette as it rolled out into products. Although we addressed them in a new release, the experience underscored the lesson that good design cannot rely solely on colors to convey meaning.

Drawing from IBM’s brand palette

Carbon’s core data visualization palette is a curated subset of IBM’s brand palette. Data visualization libraries rely on two types of color coding for data sets: sequential and categorical palettes. Sequential palettes — often light to dark shades of the same color — demonstrate ranges in a data sets (they’re often seen in heat and choropleth maps). Categorical palettes are used to assign non-numeric meaning to categories in visualizations.

Comparison of brand palette and the colors used in Data visualization — a selected subset, with added yellows and oranges.
Left: IBM Design Language palette V2. Right: colors for data visualization usage.

A case for extended palette

Because IBM’s brand palette intentionally skews cool, we found ourselves running out of warm options for visualizations. A balance of warm and cool hues is essential to avoid creating false associations. For example, a single magenta data point in a sea of blues and greens can read as an error — or create the impression that the cooler data points are related. After some thought, we made one key addition to address this problem: an extended yellow and orange spectrum. The extension is only available for Carbon data visualizations.

Two rows of 10 squares showing all shades of the extended yellow and orange palette
Extended yellow and orange spectrum

Reduced background options

Strategic palette limitations are just as important as the additions for accessibility. Keeping background contrast ratios above the 3:1 accessibility requirement is a challenge in data visualization. So to enable maximum contrast, we restricted chart backgrounds to only the brightest (White) and darkest (Gray 100) of the theme backgrounds.

Two charts in white theme on white background and gray 10 background, and two in dark theme on gray 90 and gray 100 backgrd
Bright and dark themed charts as seen on four different UI backgrounds.

Accessibility and the sequential palettes

The sequential palettes are the easier problem to solve.

All sequential palettes in Carbon charts
Sequential palettes: four monochromatic options, and two diverging options

Carbon provides the same sequential palettes for both the light and dark themes, which means nearly half of the colors do not satisfy 3:1 contrast ratio against the background.

But maintaining a full range of light and dark is more effective for data reading, as it increases the differentiation between data points. As you can see below, a limited palette would render visualizations like heat maps meaningless for all users. Overemphasis on background contrast can thus reduce the accessibility inside the visualization. In turn, we rely on additional features such as axes and outlines to assist with the graphic’s read.

On white, left heatmap uses contrast accessible colors, 50–100, but is harder to read than right headmap, which uses 10–100.
The left side heat map is 3:1 contrast accessible against background, but not necessarily a more readable visualization.

Here are some of the color-agnostic features we apply to visualizations using sequential palettes.

Accessible vertical and horizontal axes

Rectangular charts such as heat maps need to include 3:1 contrast-accessible x and y axes to help define the boundaries of the chart. We recommend including accessible axes in general to provide visual anchors for axes ticks.

Close up on a corner of heat map showing both x and y axes in gray-50
Use accessible axes


When using the sequential palette on maps, active regions should be outlined with a 3:1 contrast-accessible stroke against the background. Otherwise, regions with low contrast colors, especially islands, can easily get lost.

Close up of a light theme map of Southeast Asia region where Philippines islands are outlined in gray-50.
Outline low contrast areas to prevent them from getting lost in the sea 🌊

Caps on bars

Occasionally, a grouped bar chart might need the sequential palette. A border top of 1px stroke in an accessible shade can be added to assist the read.

Close up of group bar chart where light colored bars has a border-top in contrast-accessible shade of the same color
Add 1 px border-top to cap the bars using low contrast colors

Divider lines (situational)

A 1px stroke around a region (or around individual cell in a heat map) in the chart’s background color could be helpful. However, if the visualization is very dense, divider lines should be eliminated because they can eat up valuable space for displaying data.

Close up of map of Europe where stroke in background color is used to clarify country boundaries
Stroke in background color help with clarifying countries’ boundaries

Accessibility and the categorical palette

Since Carbon’s sequential palettes are either mono- or duo-chrome, we didn’t have to worry so much about hairy color combinations. Our categorical palette presented a much more challenging problem. It wasn’t enough to just define the palette — the sequence in which users apply the colors and the way they combine them to form a set also affects accessibility. Colors in a categorical palette need to be:

  • Differentiated: they should have a sufficient visual contrast among themselves (optimized for all color deficiencies).
  • Diverse: as a set they should avoid false associations or correlations due
    to similarities in brightness or hue.
  • Sequenced: in order for the palette to be effective in visualizations with as few as 2, and as many as 14 categories, the colors need to be sequenced in such a way that differentiation and diversity is evenly distributed.

To shed some light on how we arrived at a solution, I will briefly recap two of the rejected attempts at solving this challenge. For the final outcome, skip straight to Attempt #3.

Attempt #1: the computational method

Several co-workers at IBM had previously introduced a method for picking accessible color sets computationally. First, they eliminated the semantic colors (colors that denote values like warning or danger), and then they sequenced the swatches by skipping between color steps (or shades) and families. The Carbon team used this method to define our first-generation categorical palette.

Two rows respectively showing a sequence of 20 colors, in light and dark backgrounds
Computationally picking colors is scalable and yields decent results.

The result was promising at a glance, but we quickly noticed that the dark theme palette performed much better than the one for the light theme. Achieving 3:1 contrast against the background required relatively dark colors in the light theme and — to a user with typical sight — differentiating between hues becomes much harder as brightness decreases.

This method excels at maximizing contrast between neighboring colors within a set. But when applied to a complex, color-rich dashboard like IBM Digital Analytics and IBM Cognos Analytics, light theme users would be looking at a lot of dark colors in a dense user interface. Purple 90, Magenta 90, Teal 90 and Green 90, would be hard to differentiate even for those with typical vision.

Light theme dashboard showing 5 charts using categorical color sequence from Attempt #1
Dark theme dashboard showing 5 charts using categorical color sequence from Attempt #1
Same dashboard in dark and light themes. Computational color sequence performs better in dark

The IBM brand palette, intentionally minimal and essential, consists of only 104 colors to begin with. With the elimination of the semantic colors — blues, reds, and cyans — we just had too little room to maneuver.

Attempt #2: Alternating between accessible and inaccessible colors

Since the dark theme palette of Attempt #1 seemed viable, we kept it and started looking for ways to improve on the light theme palette. First, we expanded it to include shades that did not contrast 3:1 against background, while using the same method to pick colors computationally.

The resulting palette improved the distinction between the colors, and brightened the whole look. However, this approach would require adding border and outlines in some visualizations. It also relies on neighboring colors sufficiently contrasting in situations where the colors might touch.

A row showing a sequence of 20 colors for light theme from Attempt #2
Expanding the pool of choices and computationally picking a light theme sequence
Six pie charts showing increasing number of categories, from 2 to 7
With low contrast colors in the mix, the visualization brightens and distinction between colors is improved; however, steps will need to be taken to meet minimum contrast against the background for lighter colors.

Unfortunately for Attempt #2, the legends in our charts allow users to filter and isolate data sets. If a data category relies on the neighboring colors in order to achieve sufficient contrast, it could fail as soon as users begin interacting with the legends.

Attempt #3: the solution

After a lot of wrestling and iteration we landed on a solution that required both flexibility (loosening the rules) and manual curation:

1. We reintroduced some of the semantic colors back into the mix.

2. We extended the brand palette’s yellows and oranges (previously reserved only for alerts).

3. We manually picked and sequenced the colors.

We bought back Red 50, a very bold color loaded with meaning. The trick is to sequence it to appear after Magenta 70. With the hot magenta warming up the stage, Red 50’s appearance is less alarming. Though now Red 60 doesn’t read as error so much either! To solve this, we used a much thinner stroke and experimented with dotted vs solid line to create differentiation for chart annotations. These are some early explorations, but the general consensus is to not rely on color.

Presenting the Carbon data visualization categorical palette:

Two rows showing a sequence of 14 color on light and dark backgrounds
Carbon Charts categorical palette. A sequence of 14 colors, in dark and light themes.
Four example charts using Attempt #3 results for Categorical palette
Example charts from Carbon Charts library

Evaluating the categorial palette

With these adjustments, the categorical palette is fully 3:1 contrast-accessible against background, and has an average of >2:1 contrast between neighboring colors. Since this falls short of the strict requirement of non-text contrast, we have built up a repository of color-agnostic features to assist with data read, which I will get into shortly.

A shortcoming of “contrast ratio” is that it only measures differentiation between two colors. To evaluate the effectiveness of a categorical palette, we need an index that measures the differentiation of all colors in the palette as a group, in all combinations and permutations.

We used Viz Palette made by Susie Lu and Elijah Meeks, to evaluate our results. Viz Palette generated color reports visualizing the just-noticeable difference (JND) between colors. A JND is defined as “the amount something must be changed for a difference to be noticeable.” Colors that are difficult to tell apart are linked with increasingly thick arcs.

2 dark and 2 light theme palettes with JND reports under them.
Left side: palettes generated by the computational method (attempt #1). Right side: palettes created manually (attempt #3). Comparing only the first 14 colors, the number of arcs is significantly less in the manually created palette.

Additional accessibility cues for the categorical palette

Divider lines

The divider line is actually more important in charts using the categorical palette, because here colors are used to differentiate between categories.

Although we’ve ensured that all the colors are 3:1 accessible against the background, it’s not possible to keep them 3:1 accessible against each other at the same time. So we’ll add a contrast divider in the theme background color to separate any touching colors.

Close up on a donut chart showing divider line in background color segmenting the arc
Divider line on donut chart between categories


Hover tooltips are a must-have to communicate more detailed information without over crowding the visualization. Carbon data visualization has two types of tooltips: single data point tooltip, and comparative tooltip for hover on multiple data points.

Single tooltips can be surprisingly complex, displaying up to 4 dimensions of data (name of category, values of both axis, and size dimension on some charts).

Close up of tooltip on a bubble chart: x axis (months), y axis ( rate), color (category), and size (total count)
Example of single data point tooltip displaying 4 dimensions of data

Comparative tooltips display multiple data points in one tooltip and may also provide a sum when relevant. If the cursor rests at any point between lines on line chart, or above a stacked bar, a tooltip ruler will appear and all y-axis outputs will be displayed for that particular x-axis time stamp.

Close up of a tooltip showing as cursor hovers a column in stacked bar chart
An example of comparative tooltips on stacked bar chart

Textures and shapes

Texture is a well-established alternative to color coding areas, though it also pose a scalability challenge. When textures are used on bar charts, the bars need to be outlined in a 1px stroke and double the width to ensure the patterns are recognizable.

Textures are distinguished by dots and line density, as well as cross-hatching and other patterns
Texture on bar chart. Note bars double in width when patterns are used
List of 8 textures in increasing density
List of 8 texture options with varying density

Shapes can also serve as an alternative or enhancement to color coded data points. The main considerations when designing these are ease of differentiation and consistency of use. Just like semantic colors, certain shapes can have semantic meaning too (e.g. triangles for warning or caution). For this reason, it’s important for teams to align on their use, especially in status alerts.

Another drawbacks is users would have to trace the line to read categories. To avoid this, use shapes in combination with colors.

Two sets of 8 shapes, outlined and filled, with names of the shape above
Two sets of 8 shapes, outlined and filled
Close up on a black and white line chart using shapes for points of different categories
The obvious drawback is all users would have to trace the line to read categories. To avoid this, use shapes in combination with colors.

Keyboard navigation

Carbon is still working on implementing keyboard navigation for charts. Future functionality will allow users who are tabbing through a page to focus on individual data points in a given chart by pressing ‘Enter’, and then ‘Tab’ again to exit the chart. This will allow keyboard users to access the hover tooltips inside the graph frame.

Close up of chart with “Enter chart” button activated on tab
“Enter chart” button becomes visible when user tabs to the chart

Data table

Although they sometimes require a little work to understand, data tables are the most accessible way to present data. They also happen to be the most unbiased, in that no design decisions could potentially mislead users (e.g. a poor color decision or not starting the y-axis at 0). “View as data table” should always be an option in the visualization’s overflow menu.

Close up on a chart’s overflow menu opened, with cursor hovering on “View as data table” option
“View as data table” should always be an option in the visualization’s overflow menu

Closing note

Thank you for sticking with me till the end!

The Carbon data visualization library is still very much a work in progress. Here are some areas that are currently in the works or on the road map for future exploration:

Meet the team

I cannot say enough good things about the stellar talents I’ve worked with during this project. Data visualization is a world we all love and it will be an ongoing journey.

8-bit portraits of Shixie, Jeannie, Sadek, Cameron and Eliad
Core team working on data visualization

This has been a collaboration between many disciplines and teams — including the Accessibility team, Cognos Analytics, SPSS, Security, and Cloud.

Design: Shixie, Cameron Calder, Sadek Bazaraa, Jeannie Servaas
Development: Eliad Moosavi, Dean Williams, Natasha Decoste, Zvonimir Fras, TJ Egan
Accessibility: Mike Gower
Key sponsor users: Anne Stevens, Tricia Garrett, Diana Tran, Derek Bressler, David Levinson, Anna Hazard
Agency partner: Accurat, Guidea

Co-written with Jeannie Servaas, Anne Stevens and Mike Gower.




Crafting design systems and design language at IBM. ❤ Motion, color, data viz, AR/VR