New in SwiftUI 4: Line Chart

DevTechie Inc
Jun 26


Photo by Markus Winkler on Unsplash

Apple’s new Charts framework makes data visualization easy and fun. We have been exploring these new additions one by one and today, we will focus on LineMark, which is used to create LineCharts.

We can create a line chart by plotting nominal value the x position, and quantitative value typically to the y position. Let’s build example by visualizing daily workout sessions for the week.

Our data structure looks like this along with the sample data.

struct Workout: Identifiable {
    let id = UUID()
    let day: String
    let minutes: Int
}extension Workout {
    static let walkWorkout: [Workout] = [
        .init(day: "Mon", minutes: 23),
        .init(day: "Tue", minutes: 35),
        .init(day: "Wed", minutes: 55),
        .init(day: "Thu", minutes: 30),
        .init(day: "Fri", minutes: 15),
        .init(day: "Sat", minutes: 65),
        .init(day: "Sun", minutes: 81),
    ]
}
Once we have data, it’s easy to plot this into a line chart with the help of LineMark. We will plot workout day on X axis and workout minutes on Y axis.

import Charts
import SwiftUIstruct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                }
            }
        }
        .padding()
    }
}
Styling LineChart
We can style line chart a few ways, let’s start with a foreground style.

Let’s color our line chart orange in color:

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                }
                .foregroundStyle(.orange.gradient)
            }
        }
        .padding()
    }
}
Let’s change the thickness of line with the help of lineStyle modifier.

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .lineStyle(.init(lineWidth: 10))
                }
                .foregroundStyle(.orange.gradient)
            }
        }
        .padding()
    }
}
Instead of connected line, let’s draw chart with dashes.

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .lineStyle(.init(lineWidth: 10, dash: [1,3,5]))
                }
                .foregroundStyle(.orange.gradient)
            }
        }
        .padding()
    }
}
We can make our Chart’s line cap rounded as well:

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .lineStyle(.init(lineWidth: 10, lineCap: .round))
                }
                .foregroundStyle(.orange.gradient)
            }
        }
        .padding()
    }
}
Let’s also make line joins round as well:

.lineStyle(.init(lineWidth: 10, lineCap: .round, lineJoin: .round))
We can even change our line to be a gradient color line:

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .lineStyle(.init(lineWidth: 10, lineCap: .round, lineJoin: .round))
                }
                .foregroundStyle(Gradient(colors: [.yellow, .orange, .pink]))
            }
        }
        .padding()
    }
}
Interpolation
interpolationMethod modifier returns a chart content that plots data with the given interpolation method for line marks.

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .lineStyle(.init(lineWidth: 10, lineCap: .round, lineJoin: .round))
                }
                .foregroundStyle(Gradient(colors: [.yellow, .orange, .pink]))
                .interpolationMethod(.cardinal)
            }
        }
        .padding()
    }
}
There are few options we have available to apply.

cardinal:Interpolate data points with cardinal spline.

.interpolationMethod(.cardinal)
catmullRom Interpolate data points with Catmull-Rom spline.

.interpolationMethod(.catmullRom)
linear Interpolate data points linearly.

.interpolationMethod(.linear)
monotone: Interpolate data points with a cubic spline that preserves monotonicity of the data.

.interpolationMethod(.monotone)
stepCenter: Interpolate data points with a step, or piece-wise constant function, where the data point is at the center of the step.

.interpolationMethod(.stepCenter)
stepEnd: Interpolate data points with a step, or piece-wise constant function, where the data point is at the end of the step.

.interpolationMethod(.stepEnd)
stepStart: Interpolate data points with a step, or piece-wise constant function, where the data point is at the start of the step.

.interpolationMethod(.stepStart)
Annotate Line Chart
We can add annotation to our line chart with the help of annotation modifier

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .annotation(position: .leading) {
                            Text("🚶")
                        }
                }
                .foregroundStyle(Gradient(colors: [.yellow, .orange, .pink]))
                .interpolationMethod(.catmullRom)
            }
        }
        .padding()
    }
}
Symbol to mark points
With the help of Symbol modifier, we can mark data points for our line chart.

struct ContentView: View {
    
    @State private var walk = Workout.walkWorkout
    
    var body: some View {
        VStack {
            Text("DevTechie.com")
                .font(.largeTitle)
                .foregroundColor(.primary)
            Chart {
                ForEach(walk) { w in
                    LineMark(x: .value("Day", w.day), y: .value("Mins", w.minutes))
                        .annotation(position: .leading) {
                            Text("🚶")
                        }
                }
                .foregroundStyle(Gradient(colors: [.yellow, .orange, .pink]))
                .interpolationMethod(.catmullRom)
                .symbol(Circle())
            }
        }
        .padding()
    }
}


With that we have reached the end of this article. Thank you once again for reading. Subscribe our newsletter at https://www.devtechie.com