Roughly 4.5% of the world’s inhabitants is colorblind.
million individuals worldwide having only one kind of visible impairment. The numbers get considerably larger should you had been to take all situations under consideration. But, it’s a not often mentioned subject.
As a knowledge skilled, you don’t need anybody misinterpreting your visuals. Positive, being additional clear is extra work, however you’ll make an honest chunk of the inhabitants happier.
At the moment you’ll get 5 actionable suggestions for making your present visualizations accessible.
Concrete Pointers for Implementing Accessibility In Your Information Visualization
However first, let’s go over some basic tips you need to comply with when Accessibility is a prime precedence.
All the pieces listed under is a curated and considerably shortened guidelines of the A11Y undertaking. In the event you’re questioning, “A11Y” is an abbreviation for “accessibility” (11 letters between “A” and “Y”).
Anyhow, right here’s what you need to take note of:
- Don’t depend on shade to clarify the information – An honest chunk of the inhabitants is shade blind or suffers from another visible impairment. Patterns are a strategy to go.
- If utilizing shade, go along with darker, high-contrast tones – Mild and low-contrast colours make it almost unattainable to tell apart between teams on a chart visually.
- Don’t disguise essential information behind interactions – Hover occasions can be found solely on the desktop. The vast majority of your customers are on smartphones.
- Use labels and legends – With out them, the reader doesn’t know what the information represents.
- Translate information into clear insights – Simplify the information as a lot as doable, after which some. You don’t need something to be open for interpretation.
- Present context and clarify the visualization – If possible, annotate information factors of curiosity, and add subtitle/caption.
- Have customers with display readers in thoughts – Individuals with visible impairments use display readers to navigate net pages. Use alt textual content to explain your embedded charts.
With these in thoughts, I got here up with 5 actionable tweaks you can also make to your visualizations proper now.
Let’s dive into #1.
1. Use a Excessive-Distinction or Colorblind-Pleasant Coloration Palette
The simplest strategy to perceive why shade alternative issues is by doing the improper factor first.
Take into account the next dataset:
x = np.array(["New York", "San Francisco", "Los Angeles", "Chicago", "Miami"])
y1 = np.array([50, 63, 40, 68, 35])
y2 = np.array([77, 85, 62, 89, 58])
y3 = np.array([50, 35, 79, 43, 67])
y4 = np.array([59, 62, 33, 77, 72])
It’s an ideal candidate for a stacked bar chart. In different phrases, to indicate workplace areas on the X-axis and stack worker counts on the Y-axis.
Now think about you’re actually into the colour inexperienced.
You would possibly need to shade particular person bar parts in numerous shades of inexperienced. It’s a horrible observe (apart from some monochromatic shade palettes), as you possibly can see from the next:
plt.bar(x, y1, label="HR", shade="#32a852")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#3ebd61")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#2bc254")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#44c767")
plt.title("[DON'T] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

Many individuals surprise what their chart would appear like if it was printed in a black-and-white guide.
This one would look solely marginally worse, however solely as a result of it appears horrendous from the get-go. Distinguishing between bar parts is difficult even for individuals with out visible impairments.
You should utilize this web site to test the distinction between two colours.
Let’s repair it through the use of a high-contrast shade palette.
Customized Excessive-Distinction Coloration Palette
I’ll proceed with the belief you want the colour inexperienced.
Query: how will you create a high-contrast shade palette from one shade?
Reply: begin with a darkish shade and end with a shade comparable sufficient to your major shade. On this case, yellow-gold is an ideal candidate.
You get the perfect of each worlds this manner. You’re nonetheless utilizing colours you want and the colours don’t must get lighter (which would scale back the distinction) as you undergo bar segments.
In observe, this boils right down to enjoying round with the shade
parameter for all segments:
plt.bar(x, y1, label="HR", shade="#14342B")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#60935D")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#BAB700")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#F5E400")
plt.title("[DO] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

A lot simpler on the eyes.
Predefined Colorblind Coloration Palette
However think about the next eventualities:
- You don’t have the time to mess around with completely different shade mixtures
- You do have the time, however there are a few dozen classes in your dataset (learn: dozen colours to seek out)
There’s a better resolution to make your chart shade scheme simpler on the eyes whereas accounting for individuals with visible impairments.
One such resolution is to make use of a colorblind-friendly shade palette.
The primary line of the snippet exhibits you ways:
plt.model.use("tableau-colorblind10")
plt.bar(x, y1, label="HR")
plt.bar(x, y2, backside=y1, label="Engineering")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales")
plt.title("[DO] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

This palette accommodates 10 colorblind-friendly colours, so it’s match for charts with 10 teams or much less.
In the event you want extra, perhaps you’ll be higher off rethinking your visualization technique.
2. Cease Utilizing Colours – Use Patterns As a substitute
One other nice strategy to take away any type of misinterpretation out of your charts is to make use of patterns as a substitute of colours (or as an addition to colours).
Matplotlib has 10 hatch patterns you possibly can select from.
You possibly can additional customise the hatches by growing their density or by combining a number of patterns. However that’s a subject for one more time.
To implement patterns, add the hatch
parameter to plt.bar()
. The instance under removes shade altogether by setting fill=False
:
plt.bar(x, y1, label="HR", fill=False, hatch="*")
plt.bar(x, y2, backside=y1, label="Engineering", fill=False, hatch="xx")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", fill=False, hatch="..")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", fill=False, hatch="//")
plt.title("[DO] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

Now there’s no strategy to misread information on this chart.
Can You Combine Patterns with Coloration?
If you need the perfect of each worlds, shade + sample is the place it’s at.
You’ll need to take away the fill=False parameter and alter it with shade
. Or, simply copy the next code snippet:
plt.bar(x, y1, label="HR", shade="#14342B", hatch="*")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#60935D", hatch="xx")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#BAB700", hatch="..")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#F5E400", hatch="//")
plt.title("[DO] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

Darkish patterns are clearly seen on bar segments, however that may not all the time be the case.
The edgecolor
parameter controls the sample shade. Let’s see what occurs after setting it to white:
plt.bar(x, y1, label="HR", shade="#14342B", hatch="*", edgecolor="#FFFFFF")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#60935D", hatch="xx", edgecolor="#FFFFFF")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#BAB700", hatch="..", edgecolor="#FFFFFF")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#F5E400", hatch="///", edgecolor="#FFFFFF")
plt.title("[MAYBE] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

The sample is seen for HR and Engineering departments, however the two on the highest are a special story.
You may need no hassle seeing the strains on the topmost chart phase, however put your self within the footwear of an individual with visible impairments. They need to all the time be your body of reference.
Keep in mind: Mild-colored patterns work properly on darkish backgrounds. Darkish-colored patterns work properly on mild backgrounds. Alter accordingly.
3. Don’t Overwhelm Consumer with the Info
This precept goes in two instructions:
- Don’t put an excessive amount of info on a single chart
- Don’t put too many charts subsequent to one another, e.g., in your functions/dashboards
Doing each concurrently is considerably of an final sin in information visualization.
Let’s begin by including a pair extra departments into the combination.
The info is getting tough to handle with Python lists, so I’ve opted for a Pandas DataFrame as a substitute:
import pandas as pd
df = pd.DataFrame({
"HR": [50, 63, 40, 68, 35],
"Engineering": [77, 85, 62, 89, 58],
"Advertising and marketing": [50, 35, 79, 43, 67],
"Gross sales": [59, 62, 33, 77, 72],
"Buyer Service": [31, 34, 61, 70, 39],
"Distribution": [35, 21, 66, 90, 31],
"Logistics": [50, 54, 13, 71, 32],
"Manufacturing": [22, 51, 54, 28, 40],
"Upkeep": [50, 32, 61, 69, 50],
"High quality Management": [20, 21, 88, 89, 39]
}, index=["New York", "San Francisco", "Los Angeles", "Chicago", "Miami"])
df

Now, utilizing the colorblind-friendly palette, let’s plot the worker depend per location and division as a stacked bar chart. To make issues additional crammed, I’ve additionally thrown textual content counts into the combination:
plt.model.use("tableau-colorblind10")
ax = df.plot(variety="bar", stacked=True)
for container in ax.containers:
ax.bar_label(container, label_type="middle", fontsize=10, shade="#000000", fontweight="daring")
plt.title("[DON'T] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(title="Division", bbox_to_anchor=(1.05, 1), loc='higher left', ncol=1)
plt.present()

Now that’s simply ugly.
Repair #1 – Current Much less Info
One strategy to resolve this unpresentable mess is by displaying much less info to the person.
For instance, solely present worker depend in a single metropolis (throughout departments). You possibly can then add a dropdown menu to the aspect of the chart so the person can management the workplace location.
The next snippet plots staff per division in Chicago as a horizontal bar chart:
chicago_data = df.loc["Chicago"].sort_values()
bars = plt.barh(chicago_data.index, chicago_data.values, shade="#60935D", edgecolor="#000000")
for bar in bars:
plt.textual content(bar.get_width() + 2, bar.get_y() + bar.get_height() / 2, f"{int(bar.get_width())}", va="middle", ha="left", fontsize=14, shade="#000000")
plt.title("[DO] Worker Depend by Division in Chicago", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Depend")
plt.ylabel("Division")
plt.present()

Repair #2 – Reorganize the Information
If displaying much less info isn’t an possibility, perhaps you possibly can transpose your information.
For instance, we’re coping with 5 workplace areas and 10 departments. Displaying 10 columns as a substitute of 10 bar segments is simpler on the eyes.
This fashion, you’ll find yourself displaying workplace areas as bar segments as a substitute of departments:
df_transposed = df.T
df_sorted = df_transposed.loc[df_transposed.sum(axis=1).sort_values().index]
ax = df_sorted.plot(variety="barh", width=0.8, edgecolor="#000000", stacked=True)
for container in ax.containers:
ax.bar_label(container, label_type="middle", fontsize=10, shade="#FFFFFF", fontweight="daring")
plt.title("[DO] Worker Depend Per Location And Division", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.present()

It’s only a matter of reframing the issue.
The chart on Picture 10 is miles forward of the chart on Picture 8. It’s a truth. Nobody can argue with it.
4. Present In-Depth Explanations of Information On Your Charts
You possibly can leverage subtitle and/or caption sections of your chart so as to add additional info.
This is useful while you need to present extra context in regards to the information, cite sources, or summarize the primary level(s) of your visualization. The final one is most relevant for individuals with visible impairments.
The issue with matplotlib is that it doesn’t have a devoted perform for chart subtitles and captions. You should utilize suptitle(), however you’ll must mess around with x and y-axis coordinates.
Right here’s an instance:
plt.bar(x, y1, label="HR", shade="#14342B", hatch="*")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#60935D", hatch="xx")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#BAB700", hatch="..")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#F5E400", hatch="//")
plt.suptitle("Chart exhibits how the workers are distributed per division and per workplace location.nChicago workplace has essentially the most staff.", x=0.125, y=0.98, ha="left", fontsize=14, fontstyle="italic")
plt.title("Worker Depend Per Location And Division", fontsize=20, fontweight="daring", y=1.15, loc="left")
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

In the event you choose a caption over a subtitle, you solely have the change y-axis coordinate in plt.suptitle()
:
plt.bar(x, y1, label="HR", shade="#14342B", hatch="*")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#60935D", hatch="xx")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#BAB700", hatch="..")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#F5E400", hatch="//")
plt.suptitle("Chart exhibits how the workers are distributed per division and per workplace location.nChicago workplace has essentially the most staff.", x=0.125, y=0, ha="left", fontsize=14, fontstyle="italic")
plt.title("Worker Depend Per Location And Division", fontsize=20, fontweight="daring", y=1.06, loc="left")
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.present()

All in all, a subtitle or a caption will be the deciding consider appropriately getting your message to an individual with visible impairments.
Simply don’t make it 10 paragraphs lengthy. In any other case, it’s the third level of this text another time.
5. Add Alt Textual content When Embedding Plots
Many individuals with visible impairments use display readers.
The issue with display readers and charts is that they merely can’t coexist. They may be capable of choose up textual components from the graph, however they will’t interpret the visible content material. So, everytime you’re sharing your visualizations (e.g., embedding them into a web site), you have to add alt textual content.
It is a paragraph the display reader will learn to your person.
To display, let’s use the plt.savefig()
perform to avoid wasting the chart as a picture:
plt.bar(x, y1, label="HR", shade="#14342B", hatch="*")
plt.bar(x, y2, backside=y1, label="Engineering", shade="#60935D", hatch="xx")
plt.bar(x, y3, backside=y1 + y2, label="Advertising and marketing", shade="#BAB700", hatch="..")
plt.bar(x, y4, backside=y1 + y2 + y3, label="Gross sales", shade="#F5E400", hatch="//")
plt.suptitle("Chart exhibits how the workers are distributed per division and per workplace location.nChicago workplace has essentially the most staff.", x=0.125, y=0, ha="left", fontsize=14, fontstyle="italic")
plt.title("Worker Depend Per Location And Division", fontsize=20, fontweight='daring', y=1.06, loc="left")
plt.xlabel("Workplace Location")
plt.ylabel("Depend")
plt.legend(loc="higher proper", ncol=4)
plt.ylim(prime=320)
plt.savefig("determine.jpg", dpi=300, bbox_inches="tight")
In a brand new HTML doc, add an
tag that factors to the picture. That is the place you need to present alt textual content:
Doc

You possibly can’t see alt textual content while you open the HTML file, however that’s since you’re not utilizing a display reader.
If the display reader is detected, the alt textual content will likely be robotically learn to the person.
One of the best you are able to do is use a display reader plugin or level to the picture that doesn’t exist in HTML:


Now the picture can’t be discovered, so alt textual content is displayed as a substitute.
Summing Up Information Visualization Accessibility
And there you’ve gotten it — 5 issues you need to all the time take into account when designing information visualizations.
The following tips are useful normally however are of important significance when accessibility is important. And it all the time needs to be. It requires a tiny bit of additional work out of your finish, however makes your findings accessible to thousands and thousands of further individuals worldwide.