Chart in SwiftUI

Charts are not present in every mobile app, but they are quite common in sports, health, and finance applications. In this post, we’ll learn how to:

  • Create a chart (bar and line)
  • Set the unit
  • Improve the visibility of the information on the bars

Create a chart

First create the structure of the data:

struct MoneyData: Identifiable {
    let id = UUID()
    let operation: Int
    let euro: Double
}

Then, add a chart to the View (note the import Charts):

import SwiftUI
import Charts

struct ContentView: View {
    @State var expences: [MoneyData] = [MoneyData]()
    var body: some View {
        VStack {
            Chart(expences, id: \.id) { ex in
                BarMark(
                    x: .value("Operation", ex.operation),
                    y: .value("Money", ex.euro)
                )
            }
            .frame(height: 300)
            .padding()
            .onAppear {
                self.expences = initMoney()
            }
        }
    }
    func initMoney() -> [MoneyData] {
        return [MoneyData(operation: 1, euro: 2.5),
                MoneyData(operation: 2, euro: 6.5), MoneyData(operation: 3, euro: 1.5)
        ]
    }
}

To have:

Next, the chart iterates over the expenses array, displaying the operation on the X-axis and the euros on the Y-axis.

To create a linear chart, use LineMark instead of BarMark:

LineMark(
         x: .value("Operation", ex.operation),
         y: .value("Money", ex.euro)
)

To have:

Note that the last operation has three values but is not displayed. To avoid this behavior, we need to add one value at the beginning and one at the end of the X-axis. Let’s see how to do this:

struct ContentView: View {
    @State var expences: [MoneyData] = [MoneyData]()
    @State var gridValue = [Int]()
    
    var body: some View {
        VStack {
            Chart(expences, id: \.id) { ex in
                LineMark(
                    x: .value("Operation", ex.operation),
                    y: .value("Money", ex.euro)
                )
            }.chartXAxis {
                AxisMarks(values: gridValue)  
            }
            .frame(height: 300)
            .padding()
            .onAppear {
                self.expences = initMoney()
                self.gridValue = Array((expences[0].operation - 1)...(expences[expences.count - 1].operation + 1))
            }
        }
    }
    func initMoney() -> [MoneyData] {
        return [MoneyData(operation: 1, euro: 2.5),
                MoneyData(operation: 2, euro: 6.5), MoneyData(operation: 3, euro: 1.5)
                
        ]
    }
}

First, we add a State variable gridValue, initialized in the onAppear method with an interval for the operation that is larger than the interval in the money data (e.g., [0,3] instead of [1,2]).

This interval is used by applying:

.chartXAxis {
                AxisMarks(values: gridValue)  
            }

Thus, we have:

Unit

Now, let’s see what happens if we use dates on the X-axis.

To use dates, first, adjust the data structure to include dates.

struct RunData: Identifiable {
    let id = UUID()
    let date: Date
    let km: Double
}

Then make some small changes in the code to use this type of data with the chart:

struct ContentView: View {
    @State var races: [RunData] = [RunData]()
    
    var body: some View {
        VStack {
            Chart(races, id: \.id) { run in
                BarMark(
                    x: .value("Date", run.date),
                    y: .value("Km", run.km)
                )
            }
            .frame(height: 300)
            .padding()
            .onAppear {
                self.races = initData()
            }
        }
    }
    func initData() -> [RunData] {
        let dateFormatter = ISO8601DateFormatter()
        dateFormatter.formatOptions = [.withFullDate]
        
        return [RunData(date: dateFormatter.date(from: "2024-05-03") ?? Date.now, km: 15),
                RunData(date: dateFormatter.date(from: "2024-05-05") ?? Date.now, km: 20),
                RunData(date: dateFormatter.date(from: "2024-05-07") ?? Date.now, km: 10)
        ]
    }
}

Simply, we replaced the moneyData with runData and used a different initialization function, just to have:

As you can see, we only have the label for “5 May.” Don’t worry, we have a simpler solution that I showed before. We can add the unit value for the X-axis:

BarMark(
         x: .value("Date", run.date, unit: .day),
         y: .value("Km", run.km)
)

Now we see:

Now you should have the knowledge base to implement charts in your app.

Note: English is not my native language, so I apologize for any errors. I use AI solely to generate the banner of the post; the content is human-generated.

share this post with friends

Picture of Nicola De filippo

Nicola De filippo

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve

Leave a comment

Your email address will not be published. Required fields are marked *

Who I am

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve.

Follow Me Here

Get The Latest Updates

Periodically receive my super contents on coding and programming

join the family;)

Recent Posts