Reading time: 3 min

This recipe shows how to add a style SwiftUI Charts using Apple's new Charts Framework. You can change the colors, line styles and visibility of all parts of the chart, including its plot area, marks and axes.

The end result looks like this:

Screenshot%202022-06-20%20at%2018.16.59

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

Sample data & bar chart

Let's start off by creating a simple structure that represents driving distance of European capitals from the city of Osijek. This is the data we'll be plotting in a bar chart.

struct Distance: Hashable {
  let city: String
  let distance: Int
}

let data: [Distance] = [
  Distance(city: "Paris", distance: 1672),
  Distance(city: "Madrid", distance: 2922),
  Distance(city: "London", distance: 1977),
  Distance(city: "Rome", distance: 1171),
  Distance(city: "Berlin", distance: 1110),
  Distance(city: "Athens", distance: 1268)
]

struct StyledChartTest: View {
  var body: some View {
    Chart {
      ForEach(data, id: \.self) { distance in
        BarMark(x: .value("City", distance.city),
                y: .value("Distance", distance.distance))
      }
    }
  }
}
Chart Marks Color

Change the color of chart marks (the bars, in this case) using foregroundStyle on the marks themselves:

Chart {
  ForEach(data, id: \.self) { distance in
    BarMark(x: .value("City", distance.city),
            y: .value("Distance", distance.distance))
    .foregroundStyle(Color.red) // HERE
  }
}
Chart Background Color and Border

Change the background color of the chart and add a border to it with chartPlotStyle. You can apply a variety of modifiers on the ChartPlotContent parameter it provides:

Chart {
  // ... same as before ...
}
.chartPlotStyle { plotContent in
  plotContent
    .background(.green.opacity(0.4))
    .border(Color.blue, width: 2)
}
Axis Marks, Ticks and Labels

You can style the chart axes with chartXAxis and chartYAxis, respectively. Within it, create an AxisMarks instance and then add appropriate structs to modify different parts of the axis:

  • AxisGridLine is the line that runs across the plot area to indicate a reference point along a particular axis.
  • AxisTick is the mark that a chart draws on an axis to indicate a reference point along that axis.
  • AxisValueLabel is the label that describes the value on the axis mark.

Omitting any of the three options above will also remove it from the chart.

Here's some code that shows all of it in action:

Chart {
  // ... same as before ...
}
.chartPlotStyle { plotContent in
  // ... same as before ...
}
.chartXAxis {
  AxisMarks(values: .automatic) { _ in
    AxisGridLine(centered: true, stroke: StrokeStyle(dash: [1, 2, 4]))
      .foregroundStyle(Color.indigo)
    AxisTick(stroke: StrokeStyle(lineWidth: 2))
      .foregroundStyle(Color.mint)
    AxisValueLabel()
  }
}
.chartYAxis {
  AxisMarks(values: .automatic) { _ in
    AxisGridLine(centered: true, stroke: StrokeStyle(dash: [1, 2]))
      .foregroundStyle(Color.cyan)
    AxisTick(centered: true, stroke: StrokeStyle(lineWidth: 2))
      .foregroundStyle(Color.red)
    AxisValueLabel()
  }
}
Value Label Font and Color

Styling value labels is also a different beast. While you can set font and foregroundStyle on AxisValueLabel, they unfortunately have no effect on the label appearance. The correct approach is to construct a custom Text and then style it, just like we did in this recipe:

.chartYAxis {
  AxisMarks(values: .automatic) { value in
    AxisGridLine(centered: true, stroke: StrokeStyle(dash: [1, 2]))
      .foregroundStyle(Color.cyan)
    AxisTick(centered: true, stroke: StrokeStyle(lineWidth: 2))
      .foregroundStyle(Color.red)
    AxisValueLabel() { // construct Text here
      if let intValue = value.as(Int.self) {
        Text("\(intValue) km")
          .font(.system(size: 10)) // style it
          .foregroundColor(.blue)
      }
    }
  }
}

Next Post Previous Post