Reading time: 1 min

This recipe shows how to add a Bar Chart to SwiftUI using Apple's new Charts Framework.

The end result looks like this:

Screenshot%202022-06-13%20at%2010.15.56 Screenshot%202022-06-13%20at%2010.16.46

Charts framework is available starting in SwiftUI 4 (iOS 16, macOS 12.4).

Let's start off by creating a simple structure that represents how many calories we ate each day. This is the data we'll be plotting in our bar chart:

struct FoodIntake: Hashable {
  let day: String
  let calories: Int
}

// Sample data
let intakes: [FoodIntake] = [
  FoodIntake(day: "Mon", calories: 1867),
  FoodIntake(day: "Tue", calories: 2242),
  FoodIntake(day: "Wed", calories: 1965),
  FoodIntake(day: "Thu", calories: 1750),
  FoodIntake(day: "Fri", calories: 2323),
  FoodIntake(day: "Sat", calories: 2011),
  FoodIntake(day: "Sun", calories: 2109),
]

// Colors for bar items
let markColors = [Color.pink, .purple, .cyan, .brown, .orange, .blue, .mint]

Use the Chart view to represent the chart, and add a BarMark for each food intake item:

Chart(intakes, id: \.self) { intake in
  BarMark(x: .value("Calories", intake.calories), // X axis mark and value
          y: .value("Day", intake.day)) // Y axis mark and value
    .foregroundStyle(by: .value("Day", intake.day)) // determines that "Day" represents the foreground style
    // adds annotation to the end of each bar
    .annotation(position: .trailing) {
      VStack(spacing: 0) {
        Text("\(intake.calories.formatted())")
        Image(systemName: "fork.knife")
      }
      .font(.caption)
      .foregroundStyle(markColors[intakes.firstIndex(of: intake) ?? -1])
    }
}
// colors each bar and automatically adds legend
.chartForegroundStyleScale(domain: intakes.map { $0.day },
                           range: markColors)
.frame(height: 400)
.padding()

If you want to plot a "vertical" bar chart, simply flip the X and Y values on the bar marks. Don't forged to update the annotation position to top as well:

Chart(intakes, id: \.self) { intake in
  BarMark(x: .value("Day", intake.day),
          y: .value("Calories", intake.calories))
    .foregroundStyle(by: .value("Day", intake.day))
    .annotation(position: .top) {
      VStack(spacing: 0) {
        Text("\(intake.calories.formatted())")
        Image(systemName: "fork.knife")
      }
      .font(.caption)
      .foregroundStyle(markColors[intakes.firstIndex(of: intake) ?? -1])
    }
}

Next Post Previous Post