Highlight
Swift Charts 新增函数绘图和向量化绘图 API,前者支持直接绘制数学函数曲线,后者可高效渲染大规模数据集。
核心内容
Swift Charts 在 iOS 16 发布时,定位是用 SwiftUI 的方式画数据图表。开发者通过 ForEach 遍历数据,用 BarMark、PointMark 等 Mark 类型构建可视化。这套 API 很灵活,可以为每个数据点单独定制样式。
但实际场景中,很多图表的视觉风格是统一的——所有点用同样的符号大小、颜色映射规则。这种情况下,ForEach 逐个处理就有些”杀鸡用牛刀”。更常见的问题在于科学计算领域:正态分布、参数方程这些数学函数,本身是连续的定义域,无法用离散的数据点精确表达。
今年的更新针对这两类场景:LinePlot 和 AreaPlot 用于绘制数学函数,向量化 Plot API(PointPlot、RectanglePlot 等)用于高效处理大规模数据集。两个方向的设计理念一致——把”整体”当作一个实体来处理,而非逐个元素的循环。
详细内容
函数绘图
LinePlot 和 AreaPlot 是两个新 API,接受一个闭包,输入 x 返回 y(或返回 x、y 的元组)。闭包内可以调用任何数学函数:
Chart {
LinePlot(
x: "Capacity density", y: "Probability"
) { x in
normalDistribution(
x,
mean: mean,
standardDeviation: standardDeviation
)
}
}
关键点:
LinePlot接受 x 和 y 标签,闭包签名为(Double) -> DoublenormalDistribution是自定义函数,预计算了均值和标准差- Swift Charts 自动采样函数生成曲线
若要填充曲线下方的区域,改用 AreaPlot(03:57):
Chart {
AreaPlot(
x: "Capacity density", y: "Probability"
) { x in
normalDistribution(x, ...)
}
.foregroundStyle(.gray)
.opacity(0.2)
}
关键点:
AreaPlot填充曲线下方区域- 用
foregroundStyle设置填充颜色 opacity调整透明度以增强可读性
AreaPlot 也支持绘制两条曲线之间的区域,闭包返回 yStart 和 yEnd 的元组(04:21):
Chart {
AreaPlot(
x: "x", yStart: "cos(x)", yEnd: "sin(x)"
) { x in
(yStart: cos(x / 180 * .pi),
yEnd: sin(x / 180 * .pi))
}
}
关键点:
- 闭包返回
(yStart: Double, yEnd: Double)元组 - 角度需转换为弧度:
x / 180 * .pi - 用于可视化两个函数间的差值或积分区域
函数的定义域默认由 Swift Charts 自动推断,也可手动指定(04:59):
Chart {
AreaPlot(...)
}
.chartXScale(domain: -315...225)
.chartYScale(domain: -5...5)
关键点:
.chartXScale和.chartYScale设置坐标轴范围- 用于放大或缩小函数的特定部分
若只需绘制函数的某一段,可在 Plot 上指定采样域(05:18):
Chart {
AreaPlot(
x: "x", yStart: "cos(x)", yEnd: "sin(x)",
domain: -135...45
) { x in
(yStart: cos(x / 180 * .pi),
yEnd: sin(x / 180 * .pi))
}
}
关键点:
domain参数限制函数的采样范围- 与
.chartXScale分开控制:前者约束采样,后者控制显示范围
Swift Charts 支持参数方程绘图,x 和 y 都用第三个变量 t 表示(05:55):
Chart {
LinePlot(
x: "x", y: "y", t: "t", domain: -.pi ... .pi
) { t in
let x = sqrt(2) * pow(sin(t), 3)
let y = cos(t) * (2 - cos(t) - pow(cos(t), 2))
return (x, y)
}
}
.chartXScale(domain: -3...3)
.chartYScale(domain: -4...2)
关键点:
LinePlot增加t参数和domain- 闭包接受
t,返回(x, y)元组 - 用于绘制心形线、螺旋线等参数曲线
分段函数可能对某些输入无定义,返回 .nan 即可(06:40):
Chart {
LinePlot(x: "x", y: "1 / x") { x in
guard x != 0 else {
return .nan
}
return 1 / x
}
}
关键点:
.nan表示该 x 值无对应的 y 值- 用于处理除零、对数负数等非法输入
- Swift Charts 会跳过这些点,不绘制连线
向量化绘图
向量化 Plot API 用于处理大规模数据集。传统方式是 ForEach + Mark,每个数据点独立处理(07:43):
Chart {
ForEach(model.data) {
RectangleMark(
x: .value("Longitude", $0.x),
y: .value("Latitude", $0.y)
)
.foregroundStyle(by: .value("Axis type", $0.panelAxisType))
.opacity($0.capacityDensity)
}
}
关键点:
ForEach遍历每个数据点- 每个 Mark 独立设置样式属性
- 适合需要差异化定制的场景
若所有点样式统一,可改用 RectanglePlot,用 KeyPath 一次性处理整个集合(08:23):
Chart {
RectanglePlot(
model.data,
x: .value("Longitude", \.x),
y: .value("Latitude", \.y)
)
.foregroundStyle(by: .value("Axis type", \.panelAxisType))
.opacity(\.capacityDensity)
}
关键点:
RectanglePlot接受整个数据集合\.x和\.y是 KeyPath,指向存储属性foregroundStyle和opacity也用 KeyPath 批量设置
PointPlot 同理,用于散点图(09:42):
Chart {
PointPlot(
model.data,
x: .value("Longitude", \.x),
y: .value("Latitude", \.y)
)
}
关键点:
PointPlot是散点图的向量化版本- x 和 y 参数接受 KeyPath 而非闭包
向量化 Plot 的修饰符同样支持 KeyPath(10:26):
Chart {
PointPlot(
model.data,
x: .value("Longitude", \.x),
y: .value("Latitude", \.y)
)
.symbolSize(by: .value("Capacity", \.capacity))
.foregroundStyle(by: .value("Axis type", \.panelAxisType))
}
关键点:
symbolSize用 KeyPath 映射到点的尺寸foregroundStyle用 KeyPath 映射到颜色- 批量应用样式,无需遍历
向量化绘图要求属性是存储属性,而非计算属性。因为计算属性每次调用都需重新计算,存储属性则可用固定内存偏移量访问(09:14)。
Swift Charts 的无障碍支持默认适用于函数绘图。Audio Graph 可自动生成函数曲线的音频描述,VoiceOver 能朗读坐标轴和数据系列信息(03:00)。
核心启发
1. 函数可视化用于数据对比
在数据分析时,若怀疑样本符合某种统计分布,用 LinePlot 叠加理论曲线,直观对比实际分布与理论模型的差异。开始只需定义好分布函数,调用 LinePlot 绘制,用颜色或透明度区分。
2. 向量化 API 处理大规模数据集
散点图或热力图的数据量超过 100 个点时,优先考虑向量化 Plot API。把 ForEach 循环换成 PointPlot 或 RectanglePlot,用 KeyPath 指定属性,渲染效率会明显提升。注意把计算属性改成存储属性。
3. 分段函数用 .nan 处理无定义点
绘制有定义域限制的函数时,在无定义区间返回 .nan。除零、对数负数、分段函数的缺口都能用此方式处理,Swift Charts 会自动断开连线。
关联 Session
- Catch up on accessibility in SwiftUI — SwiftUI 让每个人都能轻松使用无障碍功能
- Bring your Live Activity to Apple Watch — 将实时活动带到 Apple Watch 的智能堆栈
- Bring context to today’s weather — 用 WeatherKit 获取详细天气预报数据
- Get started with HealthKit in visionOS — 在空间画布上创建 HealthKit 体验
评论
GitHub Issues · utterances