Highlight
Swift Charts 在 iOS 26、macOS 26 和 visionOS 26 上新增
Chart3D与SurfacePlot,把PointMark加上z轴即可获得可旋转的 3D 散点图。
核心内容
企鹅数据集里有三个维度:喙长、鳍长、体重。要想看清三个物种(Chinstrap、Gentoo、Adélie)之间的差异,只能画三张 2D 散点图——一张鳍长 vs 体重,一张喙长 vs 体重,一张喙长 vs 鳍长。每张图都只能展示两个属性的关系,开发者要在脑子里把三张图拼起来才能得到一个完整的认知。这种「分屏分析」的成本很高,尤其当数据本身就是三维的时候,2D 投影会丢失关键的聚类形状。
iOS 26、macOS 26 和 visionOS 26 给 Swift Charts 加了 3D 支持。把 Chart 改成 Chart3D,给 PointMark 加一个 Z 值,三张 2D 图就压缩成了一张可旋转的 3D 散点图。三个物种立刻分成三团,从侧面看又能退化回任意一对 2D 关系。新引入的 SurfacePlot 是 LinePlot 的三维版本,接受一个 (Double, Double) -> Double 闭包,在 XZ 平面上采样生成连续曲面,刚好可以叠在散点上做线性回归。
详细内容
把 2D 升到 3D,API 改动小到只有三处:Chart 换成 Chart3D、PointMark 多一个 z 参数、轴标签多一个 chartZAxisLabel(03:28):
struct PenguinChart: View {
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))
}
.chartXAxisLabel("Flipper Length (mm)")
.chartYAxisLabel("Weight (kg)")
.chartZAxisLabel("Beak Length (mm)")
.chartXScale(domain: 160...240, range: -0.5...0.5)
.chartYScale(domain: 2...7, range: -0.5...0.5)
.chartZScale(domain: 30...60, range: -0.5...0.5)
}
}
关键点:
Chart3D直接替换Chart,构造器签名一致,老代码迁移成本低。PointMark增加第三个参数z,类型仍是PlottableValue,配合foregroundStyle(by:)就能按 Species 自动配色。chartXScale/chartYScale/chartZScale都接受domain和range:domain是数据范围,range是图表内归一化坐标(这里都是-0.5...0.5),保证三轴几何比例一致。
SurfacePlot 是三维独有的新 mark,签名形如 SurfacePlot(x:y:z:_:),闭包是 (Double, Double) -> Double,对每个 (x, z) 计算出 y(05:19):
Chart3D {
SurfacePlot(x: "X", y: "Y", z: "Z") { x, z in
(sin(5 * x) + sin(5 * z)) / 2
}
}
关键点:
- 三个字符串参数
"X"/"Y"/"Z"是轴标识,对应chartXScale等修饰符。 - 闭包返回单个 Double,Swift Charts 会在 X-Z 平面上自动采样并构造连续曲面。
- 把任意数学表达式塞进闭包就能得到曲面图,无需手动构造网格。
要把曲面叠在数据上做拟合,可以先训练 MLLinearRegressor,再把它包装成同样的 (Double, Double) -> Double 闭包(06:19):
let linearRegression = LinearRegression(
penguins,
x: \.flipperLength,
y: \.weight,
z: \.beakLength
)
Chart3D {
ForEach(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))
}
SurfacePlot(x: "Flipper Length", y: "Weight", z: "Beak Length") { flipperLength, beakLength in
linearRegression(flipperLength, beakLength)
}
.foregroundStyle(.gray)
}
关键点:
Chart3D内部支持ForEach与多个 mark 混合,散点和曲面共存。LinearRegression通过callAsFunction把模型预测包成普通闭包,喂给SurfacePlot。- 曲面用
.foregroundStyle(.gray)与彩色散点形成对比,避免遮挡数据。
视角和投影通过 Chart3DPose 控制(08:09),azimuth 控制水平旋转、inclination 控制俯仰:
@State var pose = Chart3DPose(
azimuth: .degrees(20),
inclination: .degrees(7)
)
Chart3D(penguins) { penguin in
// ...
}
.chart3DPose($pose)
.chart3DCameraProjection(.perspective)
关键点:
Chart3DPose既能取预设值(.default、.front),也能自定义角度。chart3DPose($pose)接受 Binding,方便随交互更新。chart3DCameraProjection有.orthographic(默认,无远近差异,适合从侧面退化成 2D)和.perspective(远小近大,沉浸感更强)两种。
SurfacePlot 的着色还有专门的语义化样式(09:38、09:47):.foregroundStyle(.heightBased) 按曲面高度上色、.foregroundStyle(.normalBased) 按曲面法线方向上色,也可以传 LinearGradient 或 EllipticalGradient。
核心启发
-
做什么:用
Chart3D把多个 2D 散点图合并为一张可旋转图。- 为什么值得做:用户原本要在脑中拼接多张 2D 图,3D 旋转可以直接看到聚类的真实形状,对生物、物理、传感器这类天然三维的数据尤其值。
- 怎么开始:把现有
Chart改成Chart3D,给PointMark加z,给三个轴都设domain和归一化的range(如-0.5...0.5),先看默认 pose,再用chart3DPose微调到典型数据集的最佳视角。
-
做什么:用
SurfacePlot把模型预测可视化为连续曲面。- 为什么值得做:线性回归、神经网络、物理仿真的输出都是
(Double, Double) -> Double形式,曲面图能让用户直观看到模型与数据的偏差。 - 怎么开始:把模型包装为
callAsFunction(_ x: Double, _ z: Double) -> Double,丢给SurfacePlot闭包,再用.foregroundStyle(.gray)与彩色PointMark一起叠在Chart3D里。
- 为什么值得做:线性回归、神经网络、物理仿真的输出都是
-
做什么:在 visionOS 应用中优先考虑 3D 图表。
- 为什么值得做:Vision Pro 是天然的空间显示设备,2D 图在空间里反而显得平。Swift Charts 3D 在 Vision Pro 上原生支持手势旋转。
- 怎么开始:在 visionOS 的 SwiftUI 视图里直接用
Chart3D,把投影设为.perspective,让远近关系帮助用户感知深度。
-
做什么:根据使用场景选择
.orthographic或.perspective。- 为什么值得做:正交投影方便横向对比尺寸(远近一样大),透视投影提供深度线索。混用会让用户困惑。
- 怎么开始:仪表盘、需要从侧面退化成 2D 阅读的图选
.orthographic;需要沉浸感、强调空间关系的展示选.perspective,通过chart3DCameraProjection切换。
关联 Session
- Build an AppKit app with the new design — 在 AppKit 应用中适配 Liquid Glass 设计系统的实战指引。
- Create icons with Icon Composer — 用 Icon Composer 为 iOS、iPadOS、macOS 制作统一风格图标。
- Elevate the design of your iPad app — iPadOS 上提升应用观感的设计与交互最佳实践。
- Enhance your app’s multilingual experience — 为多语言用户打造无缝体验的本地化方法。
评论
GitHub Issues · utterances