ハイライト
Swift Charts において、iOS 26、macOS 26、visionOS 26 で
Chart3DとSurfacePlotが追加されました。PointMarkにz軸を与えるだけで、回転可能な 3D 散布図が描画できます。
主要内容
ペンギンのデータセットには、くちばしの長さ、ひれの長さ、体重の 3 つの次元があります。3 種類(Chinstrap、Gentoo、Adélie)の違いを把握するには、これまでは 2D 散布図を 3 枚描く必要がありました。ひれの長さ対体重、くちばしの長さ対体重、くちばしの長さ対ひれの長さ、といった具合です。1 枚の図に示せるのは 2 つの属性の関係だけなので、開発者は頭の中で 3 枚の図を組み合わせて、全体像を把握する必要がありました。この「分割表示による分析」はコストが高く、特にデータそのものが 3 次元である場合、2D への投影によって重要なクラスタの形状が失われてしまいます。
iOS 26、macOS 26、visionOS 26 では、Swift Charts に 3D 表示のサポートが追加されました。Chart を Chart3D に変更し、PointMark に Z 値を加えるだけで、3 枚の 2D 図が 1 枚の回転可能な 3D 散布図に集約されます。3 種類が即座に 3 つの塊に分かれ、側面から見れば任意の 2 変量関係に戻ることもできます。新たに導入された SurfacePlot は、LinePlot の 3D 版です。(Double, Double) -> Double というクロージャを受け取り、XZ 平面上でサンプリングして連続的な曲面を生成します。散布図の上に重ねて線形回帰を可視化するのにぴったりです。
詳細
2D から 3D への移行は、API の変更がほとんどありません。変更点は 3 箇所だけです。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に追加される 3 つ目のパラメータzの型もPlottableValueであり、foregroundStyle(by:)と組み合わせることで Species ごとに自動的に配色できます。chartXScale/chartYScale/chartZScaleはいずれもdomainとrangeを受け取ります。domainはデータの範囲、rangeはグラフ内の正規化座標(ここではいずれも-0.5...0.5)であり、3 軸の幾何学的な比率を揃えることができます。
SurfacePlot は 3D 専用の新しい 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
}
}
ポイント:
- 3 つの文字列引数
"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(遠くが小さく近くが大きく、没入感が高まります)の 2 種類があります。
SurfacePlot の着色には、専用のセマンティックスタイルもあります(09:38、09:47)。.foregroundStyle(.heightBased) は曲面の高さに応じて色付けし、.foregroundStyle(.normalBased) は曲面の法線方向に応じて色付けします。また、LinearGradient や EllipticalGradient を渡すこともできます。
重要ポイント
-
何をするか:
Chart3Dを使って、複数の 2D 散布図を 1 枚の回転可能な図に統合します。- なぜ価値があるか:ユーザーはこれまで頭の中で複数の 2D 図を組み合わせる必要がありましたが、3D 回転によってクラスタの実際の形状を直接見ることができます。生物、物理、センサーなど、本来 3 次元であるデータにとって特に価値があります。
- どう始めるか:既存の
ChartをChart3Dに変更し、PointMarkにzを追加し、3 軸すべてに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 は visionOS 上でジェスチャーによる回転をネイティブにサポートしています。
- どう始めるか:visionOS の SwiftUI ビュー内でそのまま
Chart3Dを使い、投影を.perspectiveに設定して、遠近関係が深度を認識するのに役立つようにします。
-
何をするか:使用場面に応じて
.orthographicと.perspectiveを使い分けます。- なぜ価値があるか:正投影はサイズの横断的な比較に便利です(遠近で大きさが変わらない)。透視投影は深度の手がかりを提供します。混在させるとユーザーが混乱します。
- どう始めるか:ダッシュボードや、側面から 2D 表示に戻す必要があるグラフには
.orthographicを選びます。没入感や空間的な関係を強調したい展示には.perspectiveを選び、chart3DCameraProjectionで切り替えます。
関連セッション
- 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