Build A 3D Scatter Plot With Swift Charts
Swift Charts has always been great for approachable 2D charts. With the WWDC25 updates, it can also render real 3D charts using Chart3D.
This is useful when your data has three numeric dimensions and flattening it into a bunch of 2D charts hides the relationship you are trying to see. A scatter plot is the best first example because it maps cleanly to x, y, and z.
Chart3D is available on iOS 26, iPadOS 26, Mac Catalyst 26, macOS 26, and visionOS 26. It is unavailable on tvOS and watchOS in the current SDK.
The data
Use a tiny penguin data set with three measurements:
import SwiftUI
import Charts
struct Penguin: Identifiable {
let id = UUID()
let species: String
let flipperLength: Double
let weight: Double
let beakLength: Double
}
let penguins = [
Penguin(species: "Adelie", flipperLength: 181, weight: 3.75, beakLength: 39.1),
Penguin(species: "Gentoo", flipperLength: 214, weight: 5.0, beakLength: 46.5),
Penguin(species: "Chinstrap", flipperLength: 195, weight: 3.8, beakLength: 48.7)
]
The three numeric properties will become the three chart axes:
flipperLengthon Xweighton YbeakLengthon Z
The chart
The chart code looks very close to a normal Swift Charts view:
struct PenguinChart3D: View {
@State private var pose: Chart3DPose = .default
var body: some View {
Chart3D(penguins) { penguin in
PointMark(
x: .value("Flipper Length", penguin.flipperLength),
y: .value("Weight", penguin.weight),
z: .value("Beak Length", penguin.beakLength)
)
.foregroundStyle(by: .value("Species", penguin.species))
}
.chart3DPose($pose)
.chartXAxisLabel("Flipper Length (mm)")
.chartYAxisLabel("Weight (kg)")
.chartZAxisLabel("Beak Length (mm)")
}
}
The big change is the z: value on PointMark. That third dimension is what turns this from a normal scatter plot into a 3D scatter plot.
chart3DPose($pose) keeps SwiftUI state synchronized with the chart’s interactive pose. That gives you a place to reset, preserve, or coordinate the camera pose with other UI.
Why not always use 3D?
3D charts are tempting, but they are not automatically better. They work best when the third dimension is genuinely part of the question.
Good fits:
- Clusters in three numeric dimensions.
- A physical shape or surface.
- Data where rotating reveals a relationship that is hidden in 2D.
Weak fits:
- A basic time series.
- A ranking.
- Anything where exact comparison is more important than spatial exploration.
For dashboards, I would still default to 2D unless the third dimension earns its keep. For exploratory tools, scientific data, education, and visionOS experiences, Chart3D opens up some lovely possibilities.
Next: SurfacePlot
Scatter plots use points you already have. SurfacePlot is for rendering a mathematical surface from a function.
Chart3D {
SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
(sin(5 * x) + sin(5 * z)) / 2
}
}
That is a different kind of visualization, but it uses the same core idea: the chart needs values for three axes, and Swift Charts handles the rendering and interaction.
Further reading:
- WWDC25 Swift Charts 3D session: https://developer.apple.com/videos/play/wwdc2025/313/
- Swift Charts documentation: https://developer.apple.com/documentation/Charts