SwiftUI Scatter Charts
SwiftUI Charts support creating scatter charts. To create a scatter chart, use a `Chart` view and place `PointMark`s or `LineMark`s inside.
import SwiftUI
import Charts
struct SampleScatterChartView: View {
@State private var startIndex: Int = 0
@State private var data: [CGPoint] = []
@State private var task: Task? = nil
var body: some View {
Text("SwiftUI Scatter Chart")
.font(.largeTitle)
Text("Lissajous curves are nice")
VStack {
Grid {
GridRow {
Chart {
ForEach(Array(0 ..< data.count), id: \.self) { index in
let item = data[index]
if index == data.count - 1 {
PointMark(
x: .value("x", Double(index)),
y: .value("y", Double(item.y))
)
}
LineMark(
x: .value("x", Double(index)),
y: .value("y", Double(item.y))
)
}
}
.chartXAxis {
AxisMarks {
AxisGridLine()
AxisTick()
}
}
.chartYAxis {
AxisMarks {
AxisGridLine()
AxisTick()
}
}
.padding(.horizontal, 8)
.padding(.vertical, 8)
.background {
Color.white
}
.clipShape(RoundedRectangle(cornerRadius: 16))
Chart {
ForEach(Array(0 ..< data.count), id: \.self) { index in
let item = data[index]
if index == data.count - 1 {
PointMark(
x: .value("x", Double(item.x)),
y: .value("y", Double(item.y))
)
}
LineMark(
x: .value("x", Double(item.x)),
y: .value("y", Double(item.y))
)
}
}
.chartXAxis {
AxisMarks {
AxisGridLine()
AxisTick()
}
}
.chartYAxis {
AxisMarks {
AxisGridLine()
AxisTick()
}
}
.padding(.horizontal, 8)
.padding(.vertical, 8)
.background {
Color.white
}
.clipShape(RoundedRectangle(cornerRadius: 16))
}
GridRow {
Color.clear
Chart {
ForEach(Array(0 ..< data.count), id: \.self) { index in
let item = data[index]
if index == data.count - 1 {
PointMark(
x: .value("x", Double(item.x)),
y: .value("y", Double(index))
)
}
LineMark(
x: .value("x", Double(item.x)),
y: .value("y", Double(index))
)
}
}
.chartXAxis {
AxisMarks {
AxisGridLine()
AxisTick()
}
}
.chartYAxis {
AxisMarks {
AxisGridLine()
AxisTick()
}
}
.padding(.horizontal, 8)
.padding(.vertical, 8)
.background {
Color.white
}
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}
Spacer()
}
.padding()
.background {
Color(white: 0.9)
}
.onTapGesture { // for testing
loadData()
}
.onAppear {
loadData()
}
}
private func loadData() {
if task != nil {
task?.cancel()
}
task = Task {
let w1 = 0.2
let w2 = 0.3
let phi1 = 0.0
let phi2 = 0.0
for i in 0 ..< 1000 {
do {
try await Task.sleep(nanoseconds: 1_000_000 * 100)
let x = (sin(Double(i) * w1 + phi1) + 1.0) * 0.5
let y = (sin(Double(i) * w2 + phi2) + 1.0) * 0.5
await MainActor.run {
startIndex = i
data.append(CGPoint(x: x, y: y))
if data.count > 50 {
data.remove(at: 0)
}
}
} catch { }
}
}
}
}
#Preview {
SampleScatterChartView()
}