5 Crucial Tweaks That Will Make Your Charts Accessible to Individuals with Visual Impairments

-

Roughly 4.5% of the world’s population is colorblind.

million people worldwide having only one style of visual impairment. The numbers get significantly higher in the event you were to take all conditions under consideration. Yet, it’s a rarely discussed topic.

As a knowledge skilled, you don’t want anyone misinterpreting your visuals. Sure, being extra clear is more work, but you’ll make a good chunk of the population happier. 

Today you’ll get 5 actionable suggestions for making your existing visualizations accessible.

Concrete Guidelines for Implementing Accessibility In Your Data Visualization

But first, let’s go over some general guidelines you need to follow when Accessibility is a top priority.

Every thing listed below is a curated and significantly shortened checklist of the A11Y project. Should you’re wondering, “A11Y” is an abbreviation for “accessibility” (11 letters between “A” and “Y”).

Anyhow, here’s what you need to listen to:

  • Don’t depend on color to elucidate the info – A good chunk of the population is color blind or suffers from another visual impairment. Patterns are a technique to go.
  • If using color, go together with darker, high-contrast tones – Light and low-contrast colours make it nearly inconceivable to tell apart between groups on a chart visually.
  • Don’t hide vital data behind interactions – Hover events can be found only on the desktop. The vast majority of your users are on smartphones.
  • Use labels and legends – Without them, the reader doesn’t know what the info represents.
  • Translate data into clear insights – Simplify the info as much as possible, after which some. You don’t want anything to be open for interpretation.
  • Provide context and explain the visualization – If feasible, annotate data points of interest, and add subtitle/caption.
  • Have users with screen readers in mind – Individuals with visual impairments use screen readers to navigate web pages. Use alt text to explain your embedded charts.

With these in mind, I got here up with 5 actionable tweaks you may make to your visualizations straight away.

Let’s dive into #1.

1. Use a High-Contrast or Colorblind-Friendly Color Palette

The simplest technique to understand why color selection matters is by doing the flawed thing first.

Consider 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 other words, to point out office locations on the X-axis and stack worker counts on the Y-axis.

Now imagine you’re really into the colour green. 

It is advisable to color individual bar portions in numerous shades of green. It’s a horrible practice (aside from some monochromatic color palettes), as you may see from the next:

plt.bar(x, y1, label="HR", color="#32a852")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#3ebd61")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#2bc254")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#44c767")

plt.title("[DON'T] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 1 – Color palette with indistinguishable colours (image by writer)

Many individuals wonder what their chart would appear like if it was printed in a black-and-white book. 

This one would look only marginally worse, but only since it looks horrendous from the get-go. Distinguishing between bar portions is difficult even for people without visual impairments.

Let’s fix it by utilizing a high-contrast color palette.

Custom High-Contrast Color Palette

I’ll proceed with the belief you just like the color green.

Query: how will you create a high-contrast color palette from one color? 
Answer: start with a dark shade and finish with a color similar enough to your primary color. On this case, yellow-gold is an ideal candidate.

You get the perfect of each worlds this manner. You’re still using colours you want and the colours don’t must get lighter (which would scale back the contrast) as you undergo bar segments.

In practice, this boils right down to fooling around with the color parameter for all segments:

plt.bar(x, y1, label="HR", color="#14342B")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#60935D")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#BAB700")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#F5E400")

plt.title("[DO] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 2 – Custom color palette (image by writer)

A lot easier on the eyes.

Predefined Colorblind Color Palette

But consider the next scenarios:

  • You don’t have the time to mess around with different color combos
  • You do have the time, but there are a few dozen categories in your dataset (read: dozen colours to search out)

There’s a better solution to make your chart color scheme easier on the eyes while accounting for individuals with visual impairments.

One such solution is to make use of a colorblind-friendly color palette.

The primary line of the snippet shows you the way:

plt.style.use("tableau-colorblind10")

plt.bar(x, y1, label="HR")
plt.bar(x, y2, bottom=y1, label="Engineering")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales")

plt.title("[DO] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 3 – Built-in colorblind palette (image by writer)

This palette accommodates 10 colorblind-friendly colours, so it’s fit for charts with 10 groups or less.

Should you need more, perhaps you’ll be higher off rethinking your visualization strategy.

2. Stop Using Colours – Use Patterns As an alternative

One other great technique to remove 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 may select from.

You’ll be able to further customize the hatches by increasing their density or by combining multiple patterns. But that’s a subject for one more time.

To implement patterns, add the hatch parameter to plt.bar(). The instance below removes color altogether by setting fill=False:

plt.bar(x, y1, label="HR", fill=False, hatch="*")
plt.bar(x, y2, bottom=y1, label="Engineering", fill=False, hatch="xx")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", fill=False, hatch="..")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", fill=False, hatch="//")

plt.title("[DO] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 4 – Plotting with patterns (image by writer)

Now there’s no technique to misinterpret data on this chart.

Can You Mix Patterns with Color?

Should you want the perfect of each worlds, color + pattern is where it’s at.

You’ll wish to remove the fill=False parameter and alter it with color. Or, just copy the next code snippet:

plt.bar(x, y1, label="HR", color="#14342B", hatch="*")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#60935D", hatch="xx")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#BAB700", hatch="..")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#F5E400", hatch="//")

plt.title("[DO] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 5 – Plotting with colours and patterns (image by writer)

Dark patterns are clearly visible on bar segments, but which may not all the time be the case.

The edgecolor parameter controls the pattern color. Let’s see what happens after setting it to white:

plt.bar(x, y1, label="HR", color="#14342B", hatch="*", edgecolor="#FFFFFF")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#60935D", hatch="xx", edgecolor="#FFFFFF")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#BAB700", hatch="..", edgecolor="#FFFFFF")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#F5E400", hatch="///", edgecolor="#FFFFFF")

plt.title("[MAYBE] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 6 – Plotting with colours and patterns (2) (image by writer)

The pattern is visible for  and  departments, however the two on the highest are a special story.

You may don’t have any trouble seeing the lines on the topmost chart segment, but put yourself within the shoes of an individual with visual impairments. They need to all the time be your frame of reference.

Remember: Light-colored patterns work well on dark backgrounds. Dark-colored patterns work well on light backgrounds. Adjust accordingly.

3. Don’t Overwhelm User with the Information

This principle goes in two directions:

  • Don’t put an excessive amount of information on a single chart
  • Don’t put too many charts next to one another, e.g., in your applications/dashboards

Doing each concurrently is somewhat of an ultimate sin in data visualization.

Let’s start by adding a pair more departments into the combo.

The information is getting difficult to administer 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],
    "Marketing": [50, 35, 79, 43, 67],
    "Sales": [59, 62, 33, 77, 72],
    "Customer Service": [31, 34, 61, 70, 39],
    "Distribution": [35, 21, 66, 90, 31],
    "Logistics": [50, 54, 13, 71, 32],
    "Production": [22, 51, 54, 28, 40],
    "Maintenance": [50, 32, 61, 69, 50],
    "Quality Control": [20, 21, 88, 89, 39]
}, index=["New York", "San Francisco", "Los Angeles", "Chicago", "Miami"])

df
Image 7 – Wider dataset (image by writer)

Now, using the colorblind-friendly palette, let’s plot the worker count per location and department as a stacked bar chart. To make things extra crammed, I’ve also thrown text counts into the combo:

plt.style.use("tableau-colorblind10")
ax = df.plot(kind="bar", stacked=True)

for container in ax.containers:
    ax.bar_label(container, label_type="center", fontsize=10, color="#000000", fontweight="daring")

plt.title("[DON'T] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")
plt.legend(title="Department", bbox_to_anchor=(1.05, 1), loc='upper left', ncol=1)

plt.show()
Image 8 – Crammed visualization (image by writer)

Now that’s just ugly.

Fix #1 – Present Less Information

One technique to solve this unpresentable mess is by showing less information to the user.

For instance, only show worker count in a single city (across departments). You’ll be able to then add a dropdown menu to the side of the chart so the user can control the office location.

The next snippet plots employees per department in Chicago as a horizontal bar chart:

chicago_data = df.loc["Chicago"].sort_values()

bars = plt.barh(chicago_data.index, chicago_data.values, color="#60935D", edgecolor="#000000")
for bar in bars:
    plt.text(bar.get_width() + 2, bar.get_y() + bar.get_height() / 2, f"{int(bar.get_width())}", va="center", ha="left", fontsize=14, color="#000000")

plt.title("[DO] Worker Count by Department in Chicago", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Count")
plt.ylabel("Department")

plt.show()
Image 9 – More readable visualization (image by writer)

Fix #2 – Reorganize the Data

If showing less information isn’t an option, perhaps you may transpose your data.

For instance, we’re coping with 5 office locations and 10 departments. Showing 10 columns as a substitute of 10 bar segments is simpler on the eyes. 

This manner, you’ll find yourself showing office locations 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(kind="barh", width=0.8, edgecolor="#000000", stacked=True)

for container in ax.containers:
    ax.bar_label(container, label_type="center", fontsize=10, color="#FFFFFF", fontweight="daring")

plt.title("[DO] Worker Count Per Location And Department", loc="left", fontdict={"weight": "daring"}, y=1.06)
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.show()
Image 10 – Transposed column chart (image by writer)

It’s only a matter of reframing the issue.

The chart on  is miles ahead of the chart on . It’s a fact. Nobody can argue with it.

4. Provide In-Depth Explanations of Data On Your Charts

You’ll be able to leverage subtitle and/or caption sections of your chart so as to add extra information.

This turns out to be useful when you must provide more context concerning the data, cite sources, or summarize the primary point(s) of your visualization. The last one is most applicable for individuals with visual impairments.

The issue with matplotlib is that it doesn’t have a dedicated function for chart subtitles and captions. You should use suptitle(), but you’ll must mess around with x and y-axis coordinates.

Here’s an example:

plt.bar(x, y1, label="HR", color="#14342B", hatch="*")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#60935D", hatch="xx")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#BAB700", hatch="..")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#F5E400", hatch="//")

plt.suptitle("Chart shows how the staff are distributed per department and per office location.nChicago office has probably the most employees.", x=0.125, y=0.98, ha="left", fontsize=14, fontstyle="italic")
plt.title("Worker Count Per Location And Department", fontsize=20, fontweight="daring", y=1.15, loc="left")
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 11 – Chart with title and subtitle (image by writer)

Should you prefer a caption over a subtitle, you simply have the change y-axis coordinate in plt.suptitle():

plt.bar(x, y1, label="HR", color="#14342B", hatch="*")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#60935D", hatch="xx")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#BAB700", hatch="..")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#F5E400", hatch="//")

plt.suptitle("Chart shows how the staff are distributed per department and per office location.nChicago office has probably the most employees.", x=0.125, y=0, ha="left", fontsize=14, fontstyle="italic")
plt.title("Worker Count Per Location And Department", fontsize=20, fontweight="daring", y=1.06, loc="left")
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.show()
Image 12 – Chart with title and caption (image by writer)

All in all, a subtitle or a caption often is the deciding think about accurately getting your message to an individual with visual impairments. 

Just don’t make it 10 paragraphs long. Otherwise, it’s the third point of this text all all over again.

5. Add Alt Text When Embedding Plots

Many individuals with visual impairments use screen readers.

The issue with screen readers and charts is that they simply can’t coexist. They may have the option to choose up textual elements from the graph, but they’ll’t interpret the visual content. So, at any time when you’re sharing your visualizations (e.g., embedding them into a web site), you could add alt text.

It is a paragraph the screen reader will read to your user.

To reveal, let’s use the plt.savefig() function to avoid wasting the chart as a picture:

plt.bar(x, y1, label="HR", color="#14342B", hatch="*")
plt.bar(x, y2, bottom=y1, label="Engineering", color="#60935D", hatch="xx")
plt.bar(x, y3, bottom=y1 + y2, label="Marketing", color="#BAB700", hatch="..")
plt.bar(x, y4, bottom=y1 + y2 + y3, label="Sales", color="#F5E400", hatch="//")

plt.suptitle("Chart shows how the staff are distributed per department and per office location.nChicago office has probably the most employees.", x=0.125, y=0, ha="left", fontsize=14, fontstyle="italic")
plt.title("Worker Count Per Location And Department", fontsize=20, fontweight='daring', y=1.06, loc="left")
plt.xlabel("Office Location")
plt.ylabel("Count")

plt.legend(loc="upper right", ncol=4)
plt.ylim(top=320)
plt.savefig("figure.jpg", dpi=300, bbox_inches="tight")

In a brand new HTML document, add an  tag that points to the image. That is where you need to provide alt text:




    
    
    Document


    "Stacked

Image 13 – Plot image embedded in HTML (image by writer)

You’ll be able to’t see alt text once you open the HTML file, but that’s since you’re not using a screen reader.

If the screen reader is detected, the alt text might be routinely read to the user.

The perfect you may do is use a screen reader plugin or point to the image that doesn’t exist in HTML:

"Stacked
Image 14 – Alt text for unfound images (image by writer)

Now the image can’t be found, so alt text is displayed as a substitute.

Summing Up Data Visualization Accessibility

And there you might have it — 5 things you need to all the time take note when designing data visualizations. 

The following tips are helpful typically but are of important importance when accessibility is crucial. And it all the time must be. It requires a tiny bit of additional work out of your end, but makes your findings accessible to tens of millions of additional people worldwide.

ASK ANA

What are your thoughts on this topic?
Let us know in the comments below.

0 0 votes
Article Rating
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Share this article

Recent posts

0
Would love your thoughts, please comment.x
()
x