How to use SwiftUI Charts

The ability to visually present data allows developers to create more intuitive and engaging applications. Swift Charts, a powerful and easy-to-use library, takes data visualization in iOS development to a new level. Today, we’ll focus on creating a bar chart representing the iPhone’s market share across various regions using SwiftUI and Swift Charts. Here’s a …

Continue Reading…

Written by

J.C. Yee

Published on

02 Aug 2023

The ability to visually present data allows developers to create more intuitive and engaging applications. Swift Charts, a powerful and easy-to-use library, takes data visualization in iOS development to a new level.

Today, we’ll focus on creating a bar chart representing the iPhone’s market share across various regions using SwiftUI and Swift Charts. Here’s a step-by-step guide:

1. Data Definition

In Swift, a struct is a custom data type that allows us to compose several pieces of data together. In this case, the iPhone struct combines the region and shares of the iPhone’s market share in each region.

struct iPhone: Identifiable, Equatable {
    
    let region: String
    let shares: Double
    
    var id: String { region }
    
    ...
    
}

Dummy data for testing

Finally, dummyData is a static array of iPhone instances representing our dataset. ‘Static’ here means that this property belongs to the type itself rather than any one instance of the type. We’re using this array to populate our chart.

struct iPhone: Identifiable, Equatable {
    
   ...
    
    static var dummyData: [iPhone] = [
        .init(region: "Worldwide", shares: 27.6),
        .init(region: "North America", shares: 54.76),
        .init(region: "South America", shares: 14.33),
        .init(region: "Asia", shares: 15.94),
        .init(region: "Europe", shares: 35.84),
        .init(region: "Oceania", shares: 55.55),
        .init(region: "Africa", shares: 14.18),
    ]
    
}

Each iPhone instance in sampleData represents the market share in a specific region. This sample data is utilized in BarMarkChart view to generate a bar for each region, thus creating our bar chart.

Step 2: Add our Data Source

In this step, We need to introduce two elements: our data source and a method to identify the leading market.

The line let data = iPhone.sampleData is how we initialize our data source for the chart. The next line is leadingMarket a computed property that identify the leading market. Using this we’ll be able to highlight the leading market in our chart later on.

struct BarMarkChart: View {
    
    let data = iPhone.dummyData
    
    var leadingMarket: iPhone? {
        data.max { $0.shares < $1.shares }
    }
    // ...
}

Step 3: Chart Composition

At the top of the view, import the Charts framework:

import Charts

In the body of our BarMarkChart view, we create the chart and iterate through our data array to form each bar:

struct BarMarkChart: View {
    
    ...
    
    var body: some View {
        Chart {
                ForEach(data) { datum in
                    BarMark(x: .value("iPhone Market Share", datum.shares),
                            y: .value("Region", datum.region))
                    // ...
                }
            }
            
            // ...
    }
}

Each BarMark is a representation of the market share (datum.shares) of the iPhone in a specific region (datum.region).

if you try to run your project at this point, you will see similar view to the image below

Step 4: Styling and Annotations

Then, we use a conditional statement to adjust the opacity of each bar depending on whether it represents the leading market or not. Furthermore, we annotate each bar with the corresponding market share percentage:

struct BarMarkChart: View {

    // ...
    
    var body: some View {
        Chart {
            ForEach(data) { datum in
                  BarMark(x: .value("iPhone Market Share", datum.shares),
                          y: .value("Region", datum.region))
                  .foregroundStyle(by: .value("Region", datum.region))
                  .opacity(leadingMarket == datum ? 1 : 0.2)
                  .annotation(position: .overlay) {
                      Text(String(datum.shares) + "%")
                          .font(.caption2)
                          .fontWeight(.semibold)
                  }
              }
          }
      }
}

Run the app, or check your canvas preview. Your view now look similar to this image below

Step 5: Final Chart Adjustments

Finally, we hide the x-axis and legend, set the aspect ratio, and add some padding to our chart for a cleaner, more focused visualization:

var body: some View {            
    Chart {
       ForEach(data) { datum in
            // ...
        }
    }
    .chartXAxis(.hidden)
    .chartLegend(.hidden)
    .aspectRatio(contentMode: .fit)
    .padding()

}

Run the app, or check your canvas preview. Your view now look similar to this image below

Good to know

Back in Step 1: Data Definition you may notice The Identifiable and Equatable protocols add on our iPhone model. Here’s why:

Identifiable The Identifiable protocol is used to uniquely identify each instance of a type. This is particularly crucial when working with SwiftUI, as it needs to understand how to differentiate each item in a collection (like an array) when iterating over it in a ForEach loop. Here, we have var id: String { region } to return the region as the unique ID, as each region is unique in our context.

Equatable The Equatable protocol allows the Swift compiler to compare instances of a type for equality, using the == and != operators. This is helpful for us to highlight the leading market in the chart (by comparing shares of the instances).

var leadingMarket: iPhone? { data.max { $0.shares < $1.shares } }

And thats it! We have successfully created an interactive and visually appealing bar chart using SwiftUI and Swift Charts. These libraries offer immense flexibility and control over data visualization, making the process of crafting unique, informative graphics a breeze.

Table of contents
    0 Shares
    Share
    Tweet
    Pin
    Share
    Buffer