In iOS 18 Apple added function plotting to the SwiftUI Charts framework.
Function Plotting
Both the LinePlot
and AreaPlot
charts now accept a function to graph. The function accepts a Double
and returns a Double
. For example:
Chart {
LinePlot(x: "x", y: "y") { x in
x * x
}
}
.chartYAxisLabel("y = x * x")
Another example, with a range applied to the x-axis (you can also apply the domain parameter directly to the LinePlot
method):
Chart {
LinePlot(x: "x", y: "y") { sin($0) }
}
.chartXScale(domain: -15...15)
.chartYAxisLabel("y = sin(x)")
Note: Apple’s documentation mentions that for x values where the function is undefined or infinity you should return Double.nan or Double.infinity:
Chart {
LinePlot(x: "x", y: "y", domain: -5...5) { x in
guard x != 0 else { return .nan }
return 1 / x
}
}
.chartYAxisLabel("y = 1/x")
.clipped()
An area plot of a single function fills the area between the function and zero:
Chart {
AreaPlot(x: "x", y: "y") { sin($0) }
}
.chartXScale(domain: -15...15)
.chartYAxisLabel("y = sin(x)")
If you give an area plot two functions for the starting and ending y value, it fills the area between the two functions:
Chart {
AreaPlot(x: "x", yStart: "x", yEnd: "sin(x)") { x in
(yStart: sin(x), yEnd: sin(x + .pi))
}
}
Where I think function plotting becomes useful is when we’re visualising data that we expect to approximate a function. Adding an area and line plot of the function we can highlight the comparison between this bar chart and the expected results:
Chart {
AreaPlot(x: "x", y: "y") { $0 * $0 }
.foregroundStyle(.gray)
.opacity(0.5)
LinePlot(x: "x", y: "y") { $0 * $0}
ForEach(data) { item in
BarMark(
x: .value("Sample", item.score),
y: .value("Result", item.count)
)
}
}