Swift Charts Tutorial: Getting Started
Learn how to use Swift Charts to transform data into elegant and accessible graphs. By Vidhur Voora.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Charts Tutorial: Getting Started
35 mins
- Getting Started
- Getting Aquainted with Swift Charts
- Developing Charts
- Creating a Bar Chart
- Adding the Bar Chart
- Tidying up the Bar Chart
- Changing to a Horizontal Bar Chart
- Customizing the Bar Chart
- Using the Variants Feature in Xcode
- Fixing the Annotation
- Supporting Accessibility
- Putting it together
- Adding a Point Chart
- Customizing the Point Chart
- Adding a Line Chart
- Calculating and Creating the Line Chart
- Showing the Line Chart
- Customizing the Line Chart
- Finishing Up the Line Chart
- Combining Marks in a Line Chart
- Adding Drill-Down Functionality
- Adding Chart Type Picker
- Adding Multiple Marks
- Visualizing Multiple Data Points
- Where to Go From Here?
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.
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.
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.
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.
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
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.
Again, click the grid icon and select 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.
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.
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.
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.
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.
Activate VoiceOver by triple-clicking the power button.
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:
- Create a chart by adding a
Chart
. - Create a point chart by adding a
PointMark
.
- Set the date of the snowfall as the
value
forx
. - Set the day's total snowfall as the
value
fory
.
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.
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.