Swift Charts Tutorial: Getting Started

Learn how to use Swift Charts to transform data into elegant and accessible graphs. By Vidhur Voora.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Tidying up the Bar Chart

There's a better and more succinct way to write the code above! When ForEach is the only content within the chart body, you can move the data from it into the chart initializer.

Remove ForEach from Chart{} body and move the data into the chart initializer as below:

Chart(0..<12, id: \.self) { month in
  let precipitationValue = sumPrecipitation(month)
  let monthName = DateUtils.monthAbbreviationFromInt(month)
  BarMark(
    x: .value("Month", monthName),
    y: .value("Precipitation", precipitationValue)
  )
}

Check the preview again. There is no change to the bar chart's appearance, and the code is cleaner.

Vertical Bar Chart in the Xcode preview canvas

Does that chart look a bit cramped though? It could look better.

Thankfully, you can adjust that, and that's exactly what you'll do in the next section.

Changing to a Horizontal Bar Chart

Making a horizontal bar chart — rather than a vertical one — is as simple as swapping the axes.

Update the values of BarMark as shown below:

BarMark(
  x: .value("Precipitation", precipitationValue),
  y: .value("Month", monthName)
)

Here, you've swapped the values of x and y. Check the preview again.

Horizontal Bar Chart in the Xcode preview canvas

Voila! You’ll see that the chart is transposed and no longer looks cramped.

So the chart is there, but it doesn't stand out nor does it specify the values for each bar and units for the axes. Your next task is to customize the chart so it's easier to read and more informative.

Customizing the Bar Chart

By default, the color of the bar charts is blue, which isn't a bad choice for a chart about water. But you're here to learn, so keep going to learn how to change it.

Add the following to BarMark():

.foregroundStyle(.mint)

This sets the bar color to mint.

Bar Chart with Mint Style

Take a moment to look at the chart — can you tell exactly how much rain fell in a given month? There's no indication, and that's what you'll fix next.

Add the following below .foregroundStyle(.mint):

.annotation {
  Text(String(format: "%.2f", precipitationValue))
    .font(.caption)
}

You annotate each BarMark with Text. The value is set to the sum of the precipitation for each month.

Bar Chart with Annotations

Refresh the preview in Canvas. Now your chart explicitly shows the values.

Using the Variants Feature in Xcode

At the bottom of Xcode's preview Canvas is a grid icon — it's two rows of three boxes. Click it to activate the variants feature.

You use this feature to preview your SwiftUI view in different color schemes, orientations and font sizes so you can make appropriate adjustments.

Click the grid icon and select Color Scheme Variants

Using Color Scheme Variants

Color scheme variants allow you to preview your chart in both light and dark mode.

Click the grid icon again, and select Orientation Variants to inspect your chart in portrait and landscape orientations.

Showing Orientation Variants

Again, click the grid icon and select Dynamic Type Variants.

Showing Dynamic Type Variants

Using Dynamic Type Variants, you can preview the chart with different font scales. Click on a dynamic type variant to enlarge that variant and inspect it closely.

Now you know:

  • More about the types of variants you can create.
  • Swift Charts provides support for dark mode, orientations, and dynamic type out of the box.
  • It also supports Accessibility out of the box and you can customize the content for VoiceOver.

Look closely at the chart again.

Annotation overlapping the month name

You may have noticed the text overlaps on months that had minimal precipitation. It's particularly evident when looking at the dynamic type variants.

Fixing the Annotation

In this section, you'll address the text overlap issue, and add a label to the axis to make the chart's purpose clear.

There are 3 optional parameters to .annotation{}, position, alignment, and spacing:

  • Use position to place the annotation above, below, over or at the end of the item.
  • Use alignment to control the alignment relative to the annotated item.
  • Finally, use spacing to specify the distance between the item and the annotation.

Change the annotation code to:

.annotation(position: .trailing) {
  Text(String(format: "%.2f in", precipitationValue))
    .font(.caption)
}

You use position with .trailing to place the annotation after the bar. You also added "in" to indicate the unit of the measure.

Another way to show the unit is by adding a label to the x-axis of the chart with .chartXAxisLabel(_:position:alignment:spacing:). Similar to annotation, you can also provide an optional position, alignment and spacing.

Add the following below Chart{}:

.chartXAxisLabel("Inches", position: .leading)

This sets the label to "Inches" and centers it along y-axis. The default for spacing: is .center. Look at the preview to confirm the label is showing.

Precipitation chart with a labeled axis

Next, you'll make your chart more accessible by customizing the VoiceOver content.

Supporting Accessibility

Add the following modifiers to Chart{}, below .annotation{}:

.accessibilityLabel(DateUtils.monthFromInt(month))
.accessibilityValue("Precipitation \(precipitationValue)")

This sets the month name as the accessibility label, and the precipitation value for that month as the accessibility value.

Now, the bar chart is ready for its prime time!

Putting it together

Open PrecipitationTab.swift and replace the contents of body with:

VStack {
  Text("Precipitation for 2018")
  PrecipitationChart(measurements: self.station.measurements)
}

Here, you replace a boring list of precipitation data with a newly minted, shiny chart! Build and run.

Viewing Precipitation Chart

Now you're ready to enable VoiceOver.

You can only test VoiceOver on a physical device. You may think you can use Xcode Accessibility Inspector with the simulator. However, the inspector does not read out the .accessibilityValue. Always test on real hardware.

Note: Take a moment to create a shortcut for VoiceOver by navigating to Settings ▸ Accessibility ▸ Accessibility Shortcut and selecting VoiceOver. This gives you the option to turn VoiceOver on or off by triple-clicking the power button.

Activate VoiceOver by triple-clicking the power button.

Accessibility In Precipitation Chart

You should hear VoiceOver read each bar mark as the month name and the corresponding precipitation value.

Adding a Point Chart

Point charts are useful for showing quantitative data in an uncluttered fashion.

The Great Smoky Mountains contain some of the highest elevations in the eastern United States, and they receive less snow than you might expect.

The scarcity of snow means data may not be present for each month.

To check this out for yourself, run the app and tap on Cherokee station. Select the Snowfall tab and inspect the data.

A point chart is a good candidate to visualize this data.

Find the Charts group in the Project navigator and open SnowfallChart.swift.

Add the following below import SwiftUI:

import Charts

Again, you simply import Charts framework.

Add the following variable to SnowfallChart:

var measurements: [DayInfo]

This will hold the measurements.

Still in the same file, replace the contents of previews with:

// swiftlint:disable force_unwrapping
SnowfallChart(
  measurements: WeatherInformation()!.stations[2].measurements)

Here, you pass the measurements for the preview to display.

Next, replace contents of body with:

// 1
Chart(measurements) { dayInfo in
  // 2
  PointMark(
    x: .value("Day", dayInfo.date),
    y: .value("Inches", dayInfo.snowfall)
  )
}

This code does a few things:

  1. Create a chart by adding a Chart.
  2. Create a point chart by adding a PointMark.
  • Set the date of the snowfall as the value for x.
  • Set the day's total snowfall as the value for y.

To put this in action, open SnowfallTab.swift, and replace the contents of body with the following:

VStack {
  Text("Snowfall for 2018")
  SnowfallChart(measurements: measurementsWithSnowfall)
}
.padding()

A chart is worth a thousand data points!

Build and run.

Point chart showing snowfall with default scales

Tap a weather station and select the Snowfall tab. It only took a few lines of code to add a point chart to visualize snowfall data — nice job!

Now, compare snowfall data between the cities. You’ll notice the scale of the y-axis scales changes dynamically based on the snowfall data for the corresponding station.

It's accurate, but when the scale changes, it becomes harder to make mental comparisons. You can set a fixed y-axis scale for all stations.