Create a line chart with SwiftUI Charts in iOS 16
Apple introduced SwiftUI Charts at WWWDC 2022, which makes it incredibly easy to create charts within SwiftUI views. Charts are a great way of presenting visual data in a rich format that is easy to understand. This article shows how to easily create a line chart with so much less code than was previously used to create the same line chart from scratch. It is also so much easier to customise the look and feel of the chart as well as make the information in the chart accessible.
It is possible to create a line chart without using SwiftUI Charts as shown in previous articles. However, the use of Charts framework makes it so much easier by providing a large variety of charts to explore what works best for the data in an App.
Here are previous articles on creating Bar and Line charts from scratch in SwiftUI.
Simple Line chart
Start with data containing step counts for a week similar to data used in Create a line chart in SwiftUI. Define a structure to hold the date and the step count for that day and create an array of these for the current week.
1struct StepCount: Identifiable {
2 let id = UUID()
3 let weekday: Date
4 let steps: Int
5
6 init(day: String, steps: Int) {
7 let formatter = DateFormatter()
8 formatter.dateFormat = "yyyyMMdd"
9
10 self.weekday = formatter.date(from: day) ?? Date.distantPast
11 self.steps = steps
12 }
13}
14
15
16let currentWeek: [StepCount] = [
17 StepCount(day: "20220717", steps: 4200),
18 StepCount(day: "20220718", steps: 15000),
19 StepCount(day: "20220719", steps: 2800),
20 StepCount(day: "20220720", steps: 10800),
21 StepCount(day: "20220721", steps: 5300),
22 StepCount(day: "20220722", steps: 10400),
23 StepCount(day: "20220723", steps: 4000)
24]
To create a Line Chart, create a Chart with a LineMark
for each element in the step
count data. Specify the Weekday for the x value and the step count for the y value
for the LineMark. Note that it is also necessary to import the Charts
framework.
That's it. This creates a line chart for the step count data. As there is only one
series of data, the ForEach
can be left out and the data can be passed directly to
the Chart initializer. Both sections produce the same line chart.
1import SwiftUI
2import Charts
3
4struct LineChart1: View {
5 var body: some View {
6 VStack {
7 GroupBox ( "Line Chart - Step Count") {
8 Chart {
9 ForEach(currentWeek) {
10 LineMark(
11 x: .value("Week Day", $0.weekday, unit: .day),
12 y: .value("Step Count", $0.steps)
13 )
14 }
15 }
16 }
17
18 GroupBox ( "Line Chart - Step Count") {
19 Chart(currentWeek) {
20 LineMark(
21 x: .value("Week Day", $0.weekday, unit: .day),
22 y: .value("Step Count", $0.steps)
23 )
24
25 }
26 }
27 }
28 }
29}
Line charts created with SwiftUI Charts showing daily step counts
Other charts
There are a number of charting options available from SwiftUI Charts. These can be
generated by changing the chart marks from LineMark
to one of the other types of
marks such as BarMark
for a Bar Chart.
1struct OtherCharts: View {
2 var body: some View {
3 VStack {
4 GroupBox ( "Line Chart - Step count") {
5 Chart(currentWeek) {
6 LineMark(
7 x: .value("Week Day", $0.weekday, unit: .day),
8 y: .value("Step Count", $0.steps)
9 )
10 }
11 }
12
13 GroupBox ( "Bar Chart - Step count") {
14 Chart(currentWeek) {
15 BarMark(
16 x: .value("Week Day", $0.weekday, unit: .day),
17 y: .value("Step Count", $0.steps)
18 )
19 }
20 }
21
22 GroupBox ( "Point Chart - Step count") {
23 Chart(currentWeek) {
24 PointMark(
25 x: .value("Week Day", $0.weekday, unit: .day),
26 y: .value("Step Count", $0.steps)
27 )
28 }
29 }
30
31 GroupBox ( "Rectangle Chart - Step count") {
32 Chart(currentWeek) {
33 RectangleMark(
34 x: .value("Week Day", $0.weekday, unit: .day),
35 y: .value("Step Count", $0.steps)
36 )
37 }
38 }
39
40 GroupBox ( "Area Chart - Step count") {
41 Chart(currentWeek) {
42 AreaMark(
43 x: .value("Week Day", $0.weekday, unit: .day),
44 y: .value("Step Count", $0.steps)
45 )
46 }
47 }
48 }
49 }
50}
Other chart types created with SwiftUI Charts showing daily step counts
Make Line Chart Accessible
One advantage of having Charts baked into SwiftUI is that it is easy to make the
charts accessibile using Accessibility modifiers. Add a computed property to
StepCount to return the data as a string, which can be used by accessibilityLabel
.
Then add accessibility label and value for each mark in the chart.
1struct StepCount: Identifiable {
2 let id = UUID()
3 let weekday: Date
4 let steps: Int
5
6 init(day: String, steps: Int) {
7 let formatter = DateFormatter()
8 formatter.dateFormat = "yyyyMMdd"
9
10 self.weekday = formatter.date(from: day) ?? Date.distantPast
11 self.steps = steps
12 }
13
14 var weekdayString: String {
15 let dateFormatter = DateFormatter()
16 dateFormatter.dateFormat = "yyyyMMdd"
17 dateFormatter.dateStyle = .long
18 dateFormatter.timeStyle = .none
19 dateFormatter.locale = Locale(identifier: "en_US")
20 return dateFormatter.string(from: weekday)
21 }
22}
1 GroupBox ( "Line Chart - Daily Step Count") {
2 Chart(currentWeek) {
3 LineMark(
4 x: .value("Week Day", $0.weekday, unit: .day),
5 y: .value("Step Count", $0.steps)
6 )
7 .accessibilityLabel($0.weekdayString)
8 .accessibilityValue("\($0.steps) Steps")
9 }
10 }
Make line chart accessibile in SwiftUI Charts
Add multiple data series to Line Chart
A line chart is a great way to compare two different series of data. Create a second series of step counts for the previous week and add both series to a line chart.
1let previousWeek: [StepCount] = [
2 StepCount(day: "20220710", steps: 15800),
3 StepCount(day: "20220711", steps: 7300),
4 StepCount(day: "20220712", steps: 8200),
5 StepCount(day: "20220713", steps: 25600),
6 StepCount(day: "20220714", steps: 16100),
7 StepCount(day: "20220715", steps: 16500),
8 StepCount(day: "20220716", steps: 3200)
9]
10
11let currentWeek: [StepCount] = [
12 StepCount(day: "20220717", steps: 4200),
13 StepCount(day: "20220718", steps: 15000),
14 StepCount(day: "20220719", steps: 2800),
15 StepCount(day: "20220720", steps: 10800),
16 StepCount(day: "20220721", steps: 5300),
17 StepCount(day: "20220722", steps: 10400),
18 StepCount(day: "20220723", steps: 4000)
19]
20
21let stepData = [
22 (period: "Current Week", data: currentWeek),
23 (period: "Previous Week", data: previousWeek)
24]
The first attempt to add these two series of data does not display as expected.
1struct LineChart2: View {
2 var body: some View {
3 GroupBox ( "Line Chart - Daily Step Count") {
4 Chart {
5 ForEach(stepData, id: \.period) {
6 ForEach($0.data) {
7 LineMark(
8 x: .value("Week Day", $0.weekday, unit: .day),
9 y: .value("Step Count", $0.steps)
10 )
11 .accessibilityLabel($0.weekdayString)
12 .accessibilityValue("\($0.steps) Steps")
13 }
14 }
15 }
16 }
17 }
18}
First attempt to create a line chart in SwiftUI Charts with two series of step count data
Display multiple series of step count based on weekday in Line Chart
The issue with the initial attempt to display multiple sets of data in a line chart is the use of date for the x-axis. The current wee follows on from the previous week so each point is plotted in a linear progression along the x-axis.
It is necessary to use just the weekday as the x-axis values, so that all Sundays are plotted at the same x-coordinate.
Add another computed property to the StepCount to return the short day in a string format for the weekday date.
1struct StepCount: Identifiable {
2
3 . . .
4
5
6 var shortDay: String {
7 let dateFormatter = DateFormatter()
8 dateFormatter.dateFormat = "EEE"
9 return dateFormatter.string(from: weekday)
10 }
11}
This shortDay
is used for the x-value of the LineMarks in the chart. In addition,
the style of the foreground is set to be based on the period of the stepCount array.
The line chart displays the step counts for both weeks using the weekdays for the
x-axis for easy comparison between the weeks.
1struct LineChart3: View {
2 var body: some View {
3 VStack {
4 GroupBox ( "Line Chart - Daily Step Count") {
5 Chart {
6 ForEach(stepData, id: \.period) { steps in
7 ForEach(steps.data) {
8 LineMark(
9 x: .value("Week Day", $0.shortDay),
10 y: .value("Step Count", $0.steps)
11 )
12 .foregroundStyle(by: .value("Week", steps.period))
13 .accessibilityLabel($0.weekdayString)
14 .accessibilityValue("\($0.steps) Steps")
15 }
16 }
17 }
18 .frame(height:400)
19 }
20 .padding()
21
22 Spacer()
23 }
24 }
25}
Line chart in SwiftUI Charts with two series of step count data
Conclusion
There is so much more to explore in SwiftUI Charts. It is clearly better to use this framework rather than building your own charts from scratch.