iOS Accessibility in SwiftUI: Create Accessible Charts using Audio Graphs

In this iOS accessibility tutorial, learn how to make charts in your app more accessible by using Audio Graphs. By David Piper.

Leave a rating/review
Download materials
Save for later
Share

Charts and graphs are integral elements of many apps because they provide concise views of large sets of data. Whether it’s stocks, fitness, news or weather, charts will improve your users’ comprehension.

However, charts can be inaccessible to visually impaired users. As Apple says in its session Bring accessibility to charts in your app: “There’s no value in a chart you can’t see.”

In this tutorial, you’ll learn how to use Apple’s Audio Graphs to improve the accessibility of a chart. Audio Graphs provides an audible representation of a chart’s data by playing a pitch for each data point. This pitch modulates up or down, depending on the y value of a data point. Developers can add descriptions of the data and axes for VoiceOver to read out.

You’ll learn how to:

  • Navigate to and use Audio Graphs.
  • Create Audio Graphs for continuous and noncontinuous data sets.
  • Show many data sets in one Audio Graph.
Note: Audio Graphs, and VoiceOver in general, are not supported on the iOS simulator. To follow along with this tutorial you will need a device and a developer account.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of this tutorial.

You might already know this app from SwiftUI Tutorial for iOS: Creating Charts. You’ll build on your knowledge to make the charts more accessible.

Open the starter project in Xcode, then build and run the app:

Screenshot of the first view of the example app WeatherChart. It shows a list of weather stations to show data for.

The app shows weather information for different weather stations. Select the first station and you’ll see three tabs: Temperatures, Snowfall and Precipitation.

Three screenshots showing the three tabs for a weather station in the example app WeatherChart. The first chart is a line chart and shows the temperature for 2018. The second screenshot shows a horizontal bar chart showing the snowfall in 2018. The last screenshot shows the precipitation as a bar chart.

Each of these tabs uses a different type of chart. You’ll start by making the Precipitation bar chart accessible and learn about noncontinuous data sets.

After that, you’ll add an Audio Graph for the Temperature line chart showing two continuous data sets. One represents each day’s minimum temperature and the other the maximum temperature.

Check out the original tutorial SwiftUI Tutorial for iOS: Creating Charts to learn how to create these charts in SwiftUI.

Continuous vs. Noncontinuous Data

There is an important difference you need to consider. Audio Graphs can show continuous and noncontinuous data sets.

In continuous data sets, each data point connects with its predecessor and follower. Audio Graphs presents that kind of data as a line chart.

Typical examples of continuous data are bodyweight or temperature over time. Continuous data allows you to interpolate the y value for an x value, which has no measurement. If it’s 68 degrees Fahrenheit at 8 a.m. and 70 degrees at 8:10 a.m., you can assume it was around 69 degrees at 8:05 a.m., even though that time isn’t presented.

In noncontinuous data sets, also called discrete data sets, each data point is separated. The Audio Graph looks like a bar chart for categorical axes or shows circles for numerical axes.

As opposed to continuous data, it’s not possible to say anything about values between two data points. Examples of discrete data include the number of apps you use daily or the precipitation per month in inches.

Take a look at the charts in the example app WeatherChart. On the left is the temperature chart. Because the temperature data is continuous, its chart is a line chart. On the right side, you see the precipitation chart. The precipitation per month is noncontinuous and thus shown as a bar chart:

Two charts side-by-side. The left one shows temperature data as a continuous line chart. The right one shows precipitation per month. Its data is non-continuous and shown as a bar chart.

Navigating With VoiceOver

Your users will access Audio Graphs via VoiceOver. VoiceOver reads out what’s visible on the screen and allows visually impaired users to move focus around and interact using gestures.

For this tutorial, you will find it helpful to set up an accessibility shortcut to activate and deactivate voiceover. Open Settings ▸ Accessibility ▸ Accessibility Shortcut and select VoiceOver. Now you can turn VoiceOver on or off by triple-clicking the power button.

When VoiceOver is active, you don’t use the screen in the same way. You swipe left and right to move between focusable areas of the screen, and double-tap to activate the focused element. Have a play around in the settings app to get used to how it works.

Swiping up or down offers information about the focused element. What these up or down gestures do is controlled by the VoiceOver rotor. You bring up the rotor by placing two fingers on the screen then rotating them, like turning a key in a lock. Each rotation switches to a different way of working through the details of the focused element.

When a view supports Audio Graphs, this appears as an option on the VoiceOver rotor. It lets up and down swipes offer the following options for a graph:

  • Describe chart: Reads a description of the chart.
  • Play Audio Graph: Plays sounds based on the data in the chart.
  • Chart Details: Opens a separate screen so the user can navigate through more details.

This is how the VoiceOver rotor looks. It shows the option Audio Graph once a view supports this feature.

A screenshot of the example app WeatherChart. When rotating two fingers over the screen, the rotor opens and show options to select. In the screenshot the setting Audio Graph is selected.

To learn about VoiceOver, go to iOS Accessibility: Getting Started or Apples iPhone User Guide Learn VoiceOver gestures on iPhone.

Creating Accessible Charts

Build and run the app on your device. Activate VoiceOver by pressing the side button three times. Swipe right to select the first weather station. Navigate to this weather station with a double tap. Again, swipe right until you have selected the label Temperatures for 2018. Swipe right one more time — you have selected the tab bar.

You can’t move focus onto the chart because it’s not visible to VoiceOver yet. This is the first thing you will change.

Open TemperatureTab.swift. Add this modifier to TemperatureChart:

.accessibilityLabel("A chart showing Temperatures for 2018")

Build and run the app again. Follow the same steps as described above, but now you are able to focus the temperature chart with VoiceOver. By adding a accessibilityLabel, VoiceOver knows what to read to the user.

This is a major improvement, but it’s only a first step toward fully accessible charts.

Creating Explorable Charts

The explanation you’ve added in the previous step isn’t providing a lot of information, is it? In this section, you’ll change that.

Open PrecipitationChart.swift. This chart shows the precipitation per month as a bar chart.

Start by making this View conform to the new protocol, AXChartDescriptorRepresentable. Add this extension above PrecipitationChart_Previews:

extension PrecipitationChart: AXChartDescriptorRepresentable {

}

This protocol requires a method, makeChartDescriptor() so add this code inside the extension:

func makeChartDescriptor() -> AXChartDescriptor {
  AXChartDescriptor(
    title: precipitationChartTitle,
    summary: precipitationChartSummary,
    xAxis: makeXAxisDescriptor(),
    yAxis: makeYAxisDescriptor(),
    series: makeDataSeriesDescriptor()
  )
}

Here, you create a AXChartDescriptor. This class encapsulates all data iOS needs to show the Audio Graph. It includes a title and a summary, information about the axes and the data the chart presents.

In the following sections, you’ll take a detailed look at how to describe axes and data series. But first, let’s provide a reasonable title and a more detailed summary.

Add two computed properties inside the extension before makeChartDescriptor ():

// 1
private var precipitationChartTitle: String {
  // 2
  let sortedMeasurements = measurements.sorted { 
    $0.date < $1.date 
  }
  if 
    let firstDay = sortedMeasurements.first?.date
      .formatted(date: .long, time: .omitted), 
    let lastDay = sortedMeasurements.last?.date
      .formatted(date: .long, time: .omitted) {
    return "Precipitation from \(firstDay) to \(lastDay)"
  }

  // 3
  return "Precipitation"
}

// 4
private var precipitationChartSummary: String {
  "\(measurements.count) measurements of precipitation, grouped by month"
}

Here's what's happening:

  1. Each Audio Graph needs a title. To give your users more information, you'll use the first and last day with measurements to create a better title.
  2. Sort the measurements by date and get the first and last measurement. Use them to make the title more specific.
  3. If a first and last day isn't given, fall back to a simpler title.
  4. Finally, provide a summary for the chart. This summary should give the user more information about what the chart is about. To give a good overview, name the number of measurements and that they are grouped by month. With that information, it'll be easier for users to understand the Audio Graph.