Swift Charts Framework for iOS16+
A cheet sheet of useful constructs
A basic stock chart:
// a line chart using CandleStick structure
Chart(list) { candleStick in
LineMark(x: .value("tick", candleStick.timestamp ),
y: .value("Price", candleStick.close))
.foregroundStyle(.green)
} // chart
Set the range of the X & Y Axis with:
.chartYScale(domain: priceMin...priceMax)
.chartXScale(domain: tickMin...tickMax)
Set the chart background color:
15 .chartBackground { chartProxy in
16 Color.red.opacity(0.1)
17 }
18 .frame(height:200)
Set the plotting area frame via:
.chartPlotStyle { plotArea in
plotArea
.frame(width: 400, height: 150)
.background(Color(.secondarySystemBackground))
}
——
15 .chartPlotStyle { plotArea in
16 plotArea
17 .background(.orange.opacity(0.1))
18 .border(.orange, width: 2)
19 }
20 .frame(height:200)
The basics of an Axis Label
// .chartXAxis {
// AxisMarks(values: .stride(by: .day)) { value in
// AxisGridLine()
// AxisTick()
// AxisValueLabel()
// }
// }
Hide the Y axis & Legend
//.chartXAxis(.hidden)
.chartYAxis(.hidden)
.chartLegend(.hidden)
.padding()
Move Y Axis to left edge:
22 // Place the y-axis on the leading side of the chart
23 .chartYAxis {
24 AxisMarks(position: .leading)
25 }
Move the chart legend:
5 // Position the Legend
16 .chartLegend(position: .overlay, alignment: .top)
17
————
15 // Position the Legend
16 .chartLegend(position: .trailing, alignment: .center, spacing: 10)
17
Round the Line with interpolationMethod .catmullRom :
5 Chart {
6 ForEach(stepData, id: \.period) { steps in
7 ForEach(steps.data) {
8 LineMark(
9 x: .value("Week Day", $0.shortDay),
10 y: .value("Step Count", $0.steps)
11 )
12 .foregroundStyle(by: .value("Week", steps.period))
13 // Use curved line to join points
14 .interpolationMethod(.catmullRom)
15 .accessibilityLabel("\($0.weekdayString)")
16 .accessibilityValue("\($0.steps) Steps")
17 }
18 }
19 }
Changing line colors with chartForegroundStyleScale:
5 Chart {
6 ForEach(stepData, id: \.period) { steps in
7 ForEach(steps.data) {
8 LineMark(
9 x: .value("Week Day", $0.shortDay),
10 y: .value("Step Count", $0.steps)
11 )
12 .foregroundStyle(by: .value("Week", steps.period))
13 .interpolationMethod(.catmullRom)
14 .symbol(by: .value("Week", steps.period))
15 .symbolSize(30)
16 .accessibilityLabel("\($0.weekdayString)")
17 .accessibilityValue("\($0.steps) Steps")
18 }
19 }
20 }
21 // Set color for each data in the chart
22 .chartForegroundStyleScale([
23 "Current Week" : Color(hue: 0.33, saturation: 0.81, brightness: 0.76),
24 "Previous Week": Color(hue: 0.69, saturation: 0.19, brightness: 0.79)
25 ])
26 .chartLegend(position: .overlay, alignment: .top)
Changing the Line Style with .lineStyle & StrokeStyle() :
9 Chart {
10 ForEach(previousWeek) {
11 LineMark(
12 x: .value("Week Day", $0.shortDay),
13 y: .value("Step Count", $0.steps)
14 )
15 .interpolationMethod(.catmullRom)
16 .foregroundStyle(prevColor)
17 .foregroundStyle(by: .value("Week", "Previous Week"))
18 .lineStyle(StrokeStyle(lineWidth: 3, dash: [5, 10]))
19 .symbol() {
20 Rectangle()
21 .fill(prevColor)
22 .frame(width: 8, height: 8)
23 }
24 .symbolSize(30)
25 .accessibilityLabel("\($0.weekdayString)")
26 .accessibilityValue("\($0.steps) Steps")
27 }
Examples from: https://swdevnotes.com/swift/2022/customise-a-line-chart-with-swiftui-charts-in-ios-16/
https://github.com/calleric/swift/blob/main/LineAreaChartView.swift
1struct ChartView1: View {
2 var body: some View {
3 VStack {
4 GroupBox ( "Line Chart - Daily Step Count") {
5 Chart {
6 ForEach(stepData, id: \.period) { steps in
7 ForEach(steps.data) {
8 LineMark(
9 x: .value("Week Day", $0.shortDay),
10 y: .value("Step Count", $0.steps)
11 )
12 .foregroundStyle(by: .value("Week", steps.period))
13 .accessibilityLabel("\($0.weekdayString)")
14 .accessibilityValue("\($0.steps) Steps")
15 }
16 }
17 }
18 .frame(height:400)
19 }
20 .padding()
// Add a style to the GroupBox
21 .groupBoxStyle(YellowGroupBoxStyle())
22 .padding()
23
1struct YellowGroupBoxStyle: GroupBoxStyle {
2 func makeBody(configuration: Configuration) -> some View {
3 configuration.content
4 .padding(.top, 30)
5 .padding(20)
6 .background(Color(hue: 0.10, saturation: 0.10, brightness: 0.98))
7 .cornerRadius(20)
8 .overlay(
9 configuration.label.padding(10),
10 alignment: .topLeading
11 )
12 }
13}
———
Combine multiple style charts on same plot :
1struct ChartView9: View {
2
3 var body: some View {
4
5 let prevColor = Color(hue: 0.69, saturation: 0.19, brightness: 0.79)
6 let curColor = Color(hue: 0.33, saturation: 0.81, brightness: 0.76)
7 let curGradient = LinearGradient(
8 gradient: Gradient (
9 colors: [
10 curColor.opacity(0.5),
11 curColor.opacity(0.2),
12 curColor.opacity(0.05),
13 ]
14 ),
15 startPoint: .top,
16 endPoint: .bottom
17 )
18
19 VStack() {
20 GroupBox ( "Line Chart - Combine LIne and Area chart") {
21 Chart {
22 ForEach(previousWeek) {
23 LineMark(
24 x: .value("Week Day", $0.shortDay),
25 y: .value("Step Count", $0.steps)
26 )
27 .interpolationMethod(.catmullRom)
28 .foregroundStyle(prevColor)
29 .foregroundStyle(by: .value("Week", "Previous Week"))
30 .lineStyle(StrokeStyle(lineWidth: 3, dash: [5, 10]))
31 .symbol() {
32 Rectangle()
33 .fill(prevColor)
34 .frame(width: 8, height: 8)
35 }
36 .symbolSize(30)
37 .accessibilityLabel("\($0.weekdayString)")
38 .accessibilityValue("\($0.steps) Steps")
39 }
40
41 ForEach(currentWeek) {
42 LineMark(
43 x: .value("Week Day", $0.shortDay),
44 y: .value("Step Count", $0.steps)
45 )
46 .interpolationMethod(.catmullRom)
47 .foregroundStyle(curColor)
48 .foregroundStyle(by: .value("Week", "Current Week"))
49 .lineStyle(StrokeStyle(lineWidth: 3))
50 .symbol() {
51 Circle()
52 .fill(curColor)
53 .frame(width: 10)
54 }
55 .symbolSize(30)
56 .accessibilityLabel("\($0.weekdayString)")
57 .accessibilityValue("\($0.steps) Steps")
58
59 AreaMark(
60 x: .value("Week Day", $0.shortDay),
61 y: .value("Step Count", $0.steps)
62 )
63 .interpolationMethod(.catmullRom)
64 .foregroundStyle(curGradient)
65 .foregroundStyle(by: .value("Week", "Current Week"))
66 .accessibilityLabel("\($0.weekdayString)")
67 .accessibilityValue("\($0.steps) Steps")
68
69 }
70 }
71 // Set the Y axis scale
72 .chartYScale(domain: 0...30000)
73
74 .chartForegroundStyleScale([
75 "Current Week" : curColor,
76 "Previous Week": prevColor
77 ])
78 .chartLegend(position: .overlay, alignment: .top)
79 .chartPlotStyle { plotArea in
80 plotArea
81 .background(Color(hue: 0.12, saturation: 0.10, brightness: 0.92))
82 }
83 .chartYAxis() {
84 AxisMarks(position: .leading)
85 }
86 .frame(height:400)
87 }
88 .groupBoxStyle(YellowGroupBoxStyle())
89 Spacer()
90 }
91 .padding()
92 }
93}
——
From: How FAST is Swift Charts? Can it handle a sound visualizer? - SwiftUI - iOS 16 https://www.youtube.com/watch?v=8kX1CX-ujlA
https://github.com/vNakamura/SwiftChartsAudioVisualizer
Using an array index as the X value with Chart(Array(data.enumerated()), id: \.0) { index, magnitude in
@State var data: [Float] = Array(repeating: 0, count: Constants.barAmount).map { _ in Float.random(in: 1 ... Constants.magnitudeLimit) }
var body: some View {
VStack {
Spacer()
VStack {
Chart(Array(data.enumerated()), id: \.0) { index, magnitude in
BarMark(
x: .value("Frequency", String(index)),
y: .value("Magnitude", magnitude)
)
.foregroundStyle(
Color(hue: 0.3 - Double((magnitude / Constants.magnitudeLimit) / 5),
saturation: 1,
brightness: 1,
opacity: 0.7
)
)
}
.onReceive(timer, perform: updateData)
.... [more code] ....