Create a Line Chart with SwiftUI Charts in iOS 16

foreword

Apple introduced SwiftUI Charts at WWDC 2022, which makes creating charts in SwiftUI views incredibly easy. Charts are a great way to present visual data in a rich format that is easy to understand. This article shows how to easily create a line chart with far less code than creating the same line chart from scratch before. In addition, it is very easy to customize the look and feel of the chart and make the information in the chart easily accessible.

As shown in previous articles, it is possible to create a line chart without using SwiftUI Charts. However, it is made much easier using the Charts framework, which provides a wealth of charts to explore the most efficient way to use the data in your application.

series of articles

  1. How to create a bar chart in SwiftUI
  2. Horizontal Bar Chart in SwiftUI
  3. Create a Line Chart with SwiftUI Charts in iOS 16
  4. Customize a line chart with SwiftUI chart in iOS16
  5. Using measurement types from the Foudation library in Swift charts

simple line chart

Start with data containing step counts for a week, similar to the one used in Creating a Line Chart in SwiftUI. Define a structure to hold the date and the number of steps for that day, and create an array for the current week.

struct StepCount: Identifiable {
    
    
    let id = UUID()
    let weekday: Date
    let steps: Int
    
    init(day: String, steps: Int) {
    
    
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        
        self.weekday = formatter.date(from: day) ?? Date.distantPast
        self.steps = steps
    }
}


let currentWeek: [StepCount] = [
    StepCount(day: "20220717", steps: 4200),
    StepCount(day: "20220718", steps: 15000),
    StepCount(day: "20220719", steps: 2800),
    StepCount(day: "20220720", steps: 10800),
    StepCount(day: "20220721", steps: 5300),
    StepCount(day: "20220722", steps: 10400),
    StepCount(day: "20220723", steps: 4000)
]

To create a line chart, create a chart with a LineMark for each element in the step count data . Specify the weekdays in LineMarkthe X value and the number of steps in the Y value. Note that you also need to import Chartsthe framework.

This creates a line graph for the step count data. Since there is only one series of data, ForEachit can be omitted and the data can be passed directly to Chartthe initializer . Both sections produce the same line chart.

import SwiftUI
import Charts

struct LineChart1: View {
    
    
    var body: some View {
    
    
        VStack {
    
    
            GroupBox ( "Line Chart - Step Count") {
    
    
                Chart {
    
    
                    ForEach(currentWeek) {
    
    
                        LineMark(
                            x: .value("Week Day", $0.weekday, unit: .day),
                            y: .value("Step Count", $0.steps)
                        )
                    }
                }
            }
            
            GroupBox ( "Line Chart - Step Count") {
    
    
                Chart(currentWeek) {
    
    
                    LineMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                    
                }
            }
        }
    }
}

A line chart created with SwiftUI Charts shows daily steps

A line chart created with SwiftUI Charts shows daily steps

other charts

SwiftUI Charts has many charting options available. These can be generated by changing the chart markers from LineMarkto other types of markers such as BarMarkbar charts.

struct OtherCharts: View {
    
    
    var body: some View {
    
    
        VStack {
    
    
            GroupBox ( "Line Chart - Step count") {
    
    
                Chart(currentWeek) {
    
    
                    LineMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            
            GroupBox ( "Bar Chart - Step count") {
    
    
                Chart(currentWeek) {
    
    
                    BarMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            
            GroupBox ( "Point Chart - Step count") {
    
    
                Chart(currentWeek) {
    
    
                    PointMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            
            GroupBox ( "Rectangle Chart - Step count") {
    
    
                Chart(currentWeek) {
    
    
                    RectangleMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            
            GroupBox ( "Area Chart - Step count") {
    
    
                Chart(currentWeek) {
    
    
                    AreaMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
        }
    }
}

Additional chart types created with SwiftUI Charts, showing daily step count

Additional chart types created with SwiftUI Charts, showing daily step count

Make line charts more accessible

One of the nice things about porting charts to SwiftUI is that it's easy to make charts accessible using accessibility modifiers. Add a computed property for StepCount that returns the data as a string that can be accessibilityLabelused . Then add accessibility labels and values ​​for each marker in the chart.

struct StepCount: Identifiable {
    
    
    let id = UUID()
    let weekday: Date
    let steps: Int
    
    init(day: String, steps: Int) {
    
    
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        
        self.weekday = formatter.date(from: day) ?? Date.distantPast
        self.steps = steps
    }
    
    var weekdayString: String {
    
    
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyyMMdd"
        dateFormatter.dateStyle = .long
        dateFormatter.timeStyle = .none
        dateFormatter.locale = Locale(identifier: "en_US")
        return  dateFormatter.string(from: weekday)
    }
}
    GroupBox ( "Line Chart - Daily Step Count") {
    
    
        Chart(currentWeek) {
    
    
            LineMark(
                x: .value("Week Day", $0.weekday, unit: .day),
                y: .value("Step Count", $0.steps)
            )
            .accessibilityLabel($0.weekdayString)
            .accessibilityValue("\($0.steps) Steps")
        }
    }

Making Line Chart Accessible in SwiftUI Charts

Add multiple data series to a line chart

Line charts are a great way to compare two different series of data. Create a second series, the number of steps for the previous week, and add both series to the line chart.

let previousWeek: [StepCount] = [
    StepCount(day: "20220710", steps: 15800),
    StepCount(day: "20220711", steps: 7300),
    StepCount(day: "20220712", steps: 8200),
    StepCount(day: "20220713", steps: 25600),
    StepCount(day: "20220714", steps: 16100),
    StepCount(day: "20220715", steps: 16500),
    StepCount(day: "20220716", steps: 3200)
]

let currentWeek: [StepCount] = [
    StepCount(day: "20220717", steps: 4200),
    StepCount(day: "20220718", steps: 15000),
    StepCount(day: "20220719", steps: 2800),
    StepCount(day: "20220720", steps: 10800),
    StepCount(day: "20220721", steps: 5300),
    StepCount(day: "20220722", steps: 10400),
    StepCount(day: "20220723", steps: 4000)
]

let stepData = [
    (period: "Current Week", data: currentWeek),
    (period: "Previous Week", data: previousWeek)
]

The first attempt to add the data for these two series does not appear as expected.

struct LineChart2: View {
    
    
    var body: some View {
    
    
        GroupBox ( "Line Chart - Daily Step Count") {
    
    
            Chart {
    
    
                ForEach(stepData, id: \.period) {
    
    
                    ForEach($0.data) {
    
    
                        LineMark(
                            x: .value("Week Day", $0.weekday, unit: .day),
                            y: .value("Step Count", $0.steps)
                        )
                        .accessibilityLabel($0.weekdayString)
                        .accessibilityValue("\($0.steps) Steps")
                    }
                }
            }
        }
    }
}

First attempt at creating a line chart with two series of step data in SwiftUI Charts

First attempt at creating a line chart with two series of step data in SwiftUI Charts

Show step series

Display multiple weekday-based step series in a line chart

The problem with initially trying to display multiple sets of data in a line chart was the use of dates for the x-axis. The current week number follows the previous week, so each point is plotted linearly increasing along the x-axis.

It is necessary to use only weekdays as values ​​for the x-axis, so that all weekdays are plotted on the same x-coordinate.

Add another computed property in StepCountto return the short day of the weekday in string format.

struct StepCount: Identifiable {
    
    

    . . .
    
        
    var shortDay: String {
    
    
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "EEE"
        return  dateFormatter.string(from: weekday)
    }
}

This shortDayis used for LineMarksthe x-values ​​of in the chart. Also, the style of the foreground is set to stepCountan array-based cycle. The line chart uses the weekdays on the x-axis to show two-week steps for comparison between weeks.

struct LineChart3: View {
    
    
    var body: some View {
    
    
        VStack {
    
    
            GroupBox ( "Line Chart - Daily Step Count") {
    
    
                Chart {
    
    
                    ForEach(stepData, id: \.period) {
    
     steps in
                        ForEach(steps.data) {
    
    
                            LineMark(
                                x: .value("Week Day", $0.shortDay),
                                y: .value("Step Count", $0.steps)
                            )
                            .foregroundStyle(by: .value("Week", steps.period))
                            .accessibilityLabel($0.weekdayString)
                            .accessibilityValue("\($0.steps) Steps")
                        }
                    }
                }
                .frame(height:400)
            }
            .padding()

            Spacer()
        }
    }
}

Line chart with two series of step count data in SwiftUI Charts

Line chart with two series of step data in SwiftUI Charts

in conclusion

There's still a lot to explore in SwiftUI Charts. Using this framework is obviously better than building your own diagrams from scratch.

Guess you like

Origin blog.csdn.net/qq_36478920/article/details/130411916