Swift Charts Tutorial: Getting Started

Learn how to use Swift Charts to transform data into elegant and accessible graphs. By Vidhur Voora.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Adding Drill-Down Functionality

You need to provide an option to switch between two types of charts.

Add the following in WeeklyTemperatureChart:

enum TemperatureChartType {
  case bar
  case line
}

You added TemperatureChartType to determine the type of chart that will show temperature data.

Next, add the following below TemperatureChartType:

@State var chartType: TemperatureChartType = .bar

The chartType holds the current selection of the type of temperature chart to view.

Adding Chart Type Picker

Replace // TODO: Chart will be added here in weeklyTemperatureView with:

return VStack {
  // 1
  Picker("Chart Type", selection: $chartType.animation(.easeInOut)) {
    Text("Bar").tag(TemperatureChartType.bar)
    Text("Line").tag(TemperatureChartType.line)
  }
  .pickerStyle(.segmented)

  // 2
  List(1..<6) { week in
    VStack {
      // TODO: Add chart here
    }
    .frame(
      height: 200.0
    )
  }
  .listStyle(.plain)
}

With this, you've added:

  1. A Picker with the options to select a bar chart or a line Chart. The selection is stored in chartType.
  2. A List to show the weekly temperature data and within it you create a VStack as a list item for each week of that month. You'll add a chart to it soon.

Adding Multiple Marks

Replace // TODO: Add chart here with:

// 1
Chart(measurementsBy(month: month, week: week)) { dayInfo in
  switch chartType {
    // 2
  case .bar:
    BarMark(
      x: .value("Day", dayInfo.date),
      yStart: .value("Low", dayInfo.temp(type: .low)),
      yEnd: .value("High", dayInfo.temp(type: .high)),
      width: 10
    )
    .foregroundStyle(
      Gradient(
        colors: [
          colorForHighestTemperature,
          colorForLowestTemperature
        ]
      )
    )

    // 3
  case .line:
    LineMark(
      x: .value("Day", dayInfo.date),
      y: .value("Temperature", dayInfo.temp(type: .avg))
    )
    .foregroundStyle(colorForAverageTemperature)
    .symbol(.circle)
    .interpolationMethod(.catmullRom)
  }
}
// 4
.chartXAxis {
  AxisMarks(values: .stride(by: .day))
}
.chartYAxisLabel("ºF")
.chartForegroundStyleScale([
  TemperatureTypes.avg.rawValue: colorForAverageTemperature,
  TemperatureTypes.low.rawValue: colorForLowestTemperature,
  TemperatureTypes.high.rawValue: colorForHighestTemperature
])

This code is the bulk of your chart logic, and it creates two different chart styles to show the same data!

Here's a section-by-section explanation:

  1. You create a Chart and pass to it weather measurements for each day of the week for a given month.
  2. Next, you add a BarMark for the bar visualization and set the date as the value for the x-axis, and you also:
    1. Provide a range for the y-axis using yStart to the lowest and yEnd to the highest temperature of the day.
    2. Control the mark's width by setting the width.
    3. Set a nice Gradient color to visualize the range of lowest to highest temperature.
  3. Show the average temperature of the day with a LineMark, similar to the monthly temperature chart. Note that you specify the type of symbol the chart should use for each point using .symbol(.circle).
  4. Customize the x-axis by:
    1. Setting AxisMark stride to a day.
    2. Adding ºF as a label for the unit of the y-axis.
    3. Adding a legend to the chart by passing an array of KeyValue pairs to .chartForegroundStyleScale. Each pair represents a measurement on the chart, and the color it should use in the legend — the chart colors are not affected by this.
  1. Provide a range for the y-axis using yStart to the lowest and yEnd to the highest temperature of the day.
  2. Control the mark's width by setting the width.
  3. Set a nice Gradient color to visualize the range of lowest to highest temperature.
  1. Setting AxisMark stride to a day.
  2. Adding ºF as a label for the unit of the y-axis.
  3. Adding a legend to the chart by passing an array of KeyValue pairs to .chartForegroundStyleScale. Each pair represents a measurement on the chart, and the color it should use in the legend — the chart colors are not affected by this.

Notice in BarMark that the temperature is a range from high to low. Whereas in the LineMark it's just the average temperature.

Can you show high, low and average in one visual? Yes, you can, and you’ll do that next. :]

Visualizing Multiple Data Points

Add the following to the end of case .bar:, right above case .line:

RectangleMark(
  x: .value("Day", dayInfo.date),
  y: .value("Temperature", dayInfo.temp(type: .avg)),
  width: 5,
  height: 5
)
.foregroundStyle(colorForAverageTemperature)

You can combine multiple marks to provide better visualization of the data!

Here you create a RectangleMark to show the average temperature of the day.

The BarMark combined with RectangleMark now shows high, low and average temperature for that day.

Add the following to case .line: below .interpolationMethod(.catmullRom):

AreaMark(
  x: .value("Day", dayInfo.date),
  yStart: .value("Low", dayInfo.temp(type: .low)),
  yEnd: .value("High", dayInfo.temp(type: .high))
)
.foregroundStyle(
  Gradient(
    colors: [
      colorForHighestTemperature,
      colorForLowestTemperature
    ]
  )
)

This adds an AreaMark to show the lowest and highest temperature of the day. The LineMark, combined with AreaMark, showcases the daily high, low and average temperatures with different visualizations.

One last step: You have the charts done but still need to enable a drill-down experience so the user can navigate freely between monthly and weekly charts.

Open MonthlyTemperatureChart.swift, and replace the contents of body with below:

NavigationView {
  monthlyAvgTemperatureView
}
.navigationTitle("Monthly Temperature")

This little chunk of code embeds monthlyAvgTemperatureView in a NavigationView and sets a title for the navigation.

Finally, in monthlyAvgTemperatureView, enclose the VStack in List within a NavigationLink as shown below:

List(0..<12) { month in
  let destination = WeeklyTemperatureChart(
    measurements: measurements, month: month)
  NavigationLink(destination: destination) {
    // VStack code
  }
}

Here, you make each VStack behave as a navigation link to present the associated details.

Build and run.

Bar and Line charts showing weekly temperature data

Select a weather station and tap the Temperature tab then select a chart from the monthly temperature view.

Use the picker to switch between Bar and Line to see the combined marks in action.

Wow, this is quite an accomplishment! Now it's elegant and easy to look at temperatures over time and understand what the weather was like.

Where to Go From Here?

Download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.

In this tutorial you’ve learned how to:

  • Create different types of charts, such as bar, line and point.
  • Create and customize marks, unit labels and their properties.
  • Customize the chart style, color, axes style and position, and the overall plot area.
  • Combine marks to better visualize the data.
  • Build multiple styles of charts from the same data and enable the user to toggle between them.
  • Enable drill-down functionality so the user can jump between summary data and detailed visualizations.

To learn more about charts, check out these WWDC videos:

I hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below.