 
							- 
							
							Swift Charts:ベクトルプロットと関数プロットプロットで表をより充実させましょう。アプリ内で関数とベクトル化されたプロットを使用して、数学関数や広範なデータセットを表示できる美しい表をレンダリングする方法をご紹介します。空気力学、磁気学、高次元の場の理論などでよく使用される関数を表示する、または大規模かつインタラクティブなヒートマップを作成するなどの課題にも、Swift Chartsなら対応できます。 関連する章- 0:00 - Introduction
- 1:01 - Function plots
- 6:48 - Vectorized plots
- 11:27 - Best practices
 リソース関連ビデオWWDC23WWDC22
- 
							このビデオを検索こんにちは Apolloです Swift Chartsの 新機能について説明します Swift Chartsは SwiftUIを使用して 情報豊かでアクセスしやすい 魅力的な視覚化を実現します このリリースでは 天気の傾向を表示したり 気分やバイタルを記録したり Math Noteで関数をグラフ化する 新しいチャートを提供します そうです Swift Chartsは データ以外のものを視覚化できます アプリ内に数学関数をプロットします Swift Chartsでは プロットAPIもベクトル化されました これによって巨大なデータセットを さらに効率的に視覚化できます このビデオでは Swift Chartsの素晴らしい新機能を それぞれ詳しく説明します まずは関数プロットです これには2つの新しいAPIが 導入されています LinePlotは 単一の関数を視覚化します AreaPlotは 2つの関数の間の領域を塗りつぶします 関数プロットがデータ分析に どのように役立つかをご紹介します アメリカ本土での 大規模太陽光発電プロジェクトについて 調査しました アメリカ地質調査所の データセットを使用しています ヒストグラムを作成して ソーラーパネルの容量密度を可視化しました ForEachをデータポイントに使い BarMarkを各要素に使っています ご覧のとおりです このヒストグラムは容量密度が 正規分布である可能性を 示唆しています 比較のために 新しい関数プロットAPIを使って 正規分布をプロットしてみましょう 正規分布曲線の点を 計算する関数を定義しましたので 新しいLinePlot APIを使って プロットできます これはdoubleを受け取りdoubleを返す クロージャを受け取ります そのため 計算済みの平均値と 標準偏差を使って 関数を呼び出すことができます Swift Chartsでは誰でも データを視覚化できるのが重要です Swift Chartsはデフォルトで グラフをアクセシブルにします Voice Overを使って グラフを説明させることができます 「x軸は容量密度です y軸は確率です 2つのデータ系列があります」 オーディオグラフも 関数プロットで機能します 「完了」 はい できました ちょうどSwiftUIと同じように モディファイアを使って 関数の外観をカスタマイズできます ここで LinePlotは バーのデフォルト色と同じなので 関数プロットの色を 別のforegroundStyleで カスタマイズするとよいでしょう ずっとよくなりました しかし もう少し目立つように 曲線の下の領域を 塗りつぶしましょう それにはLinePlotを AreaPlotに変更するだけです 次にコントラストを上げて AreaPlotを さらにカスタマイズできます 読みやすいように不透明度を使用します 以上で 簡単な数学関数を プロットする方法を説明しました Swift Chartsでは 高度な 関数プロットも簡単に作成できます 例えば AreaPlotは 曲線の下の領域だけでなく 2つの関数に挟まれた領域も 視覚化できます これは タプルを返すことで実現できます yStartと 与えられた入力xに対する yEndのタプルです データの視覚化と異なり 関数は範囲制限のないx値を受け取ります デフォルトではSwift Chartsは 関数をサンプリングすることで 自動的にドメインを推測します しかし グラフ全体の境界を カスタマイズすることができます XスケールとYスケールを設定して 関数の関心のある部分のみを 含めることができます また 関数プロット自体のドメインを 制限することもできます AreaPlotのサンプリングドメインを 制限することで グラフにこの関数の中央部分のみを 含めることができます Swift Chartsはパラメトリック関数の プロットにも対応しています これがパラメトリック関数です ここでxとyは 第3の変数Tによって定義されます プロットしてみましょう Swift Chartsでは パラメトリック関数をグラフ化できます それには 同じLinePlot APIを 使用しますが 値tに対してxとyの両方の値を返します いいですね 次は 区分関数の 扱い方について説明します 区分関数は ドメイン内の特定の値に対して 出力がないことがあります そのような場合は.nanを返して その入力値xに対する数字が 存在しないことを Swift Chartsに通知します それ以外の場合は コードが 特定のx値をトラップすることがあります 例えば xが0のときに 1/xを評価する場合などです 同様に特殊な値は.nanを返して 処理する必要があります これがLineプロットとAreaプロットによる 関数プロットです ここでは数学関数全体が 1つのエンティティとして機能します さらに これらのプロットAPIは 関数以外でも役立ちます より便利かつ効率的に 大規模なデータセットを視覚化できます そこで他のすべてのマークタイプ用に プロットAPIのバリアントも追加しました これらのベクトル化プロットAPIは コレクション全体を並列実行し 広範なデータの視覚化を描画できます 例えば 分類モデルの散布図や Transformer言語モデルで セルフアテンションを視覚化する ヒートマップなどです 話を進める前に Mark APIを使用した グラフの宣言方法を確認しましょう マークは非常に柔軟であり 各データポイントのスタイルを 個別に設定できます 適用するモディファイアの選択や 使用するマークの種類の設定も可能です ただし ほとんどの場合 このレベルのカスタマイズは必要ありません データポイントのコレクション全体に 同種のスタイルを適用するのが一般的です その際 同じ要素プロパティを X、Y、foregroundStyle その他の視覚属性に使用します これに対し RectanglePlotなどの 新しいベクトル化プロットAPIは Swift Chartsで データの大規模なコレクションを より効率的に処理できます ベクトル化プロットの例として ソーラーパネルのデータセットに 戻りましょう すべてのソーラーパネル施設の視覚化を アプリに追加します このグラフのすべての点について 同じようにカスタマイズしたいと思います サイズは容量によって決まり パネルの軸タイプによって色分けされます データセットには 経度と緯度の生のGPS座標がありますが アルベルス図法を適用して 平面上に点を表示したいと思います 計算済みプロパティを拡張機能に追加して 簡単に変換することはできますが ベクトル化プロットを 最大限に利用するため ストアドプロパティとして 追加することにします ストアドプロパティによって Swift Chartsは すべてのデータポイントの x値とy値にアクセスできます すべてのデータポイントに ゲッタを呼び出す代わりに 一定のメモリオフセットを使用します 新しいPointPlot APIは プロットするデータの コレクション全体を取ります プロットのすべての点の x値とy値について 同じラベル付き.value構文を使用できます DataPoint構造体の ストアドプロパティ xおよびyへの KeyPathも使用します SwiftUIを使ったことがある人は KeyPathを使ったことが あるかもしれません KeyPathを使うとSwift Chartsが すべての点のスタイルを設定します データセットを繰り返し処理する 必要はありません ベクトル化プロットのモディファイアも KeyPathを取ります symbolSizeでは 各点のサイズが ソーラーパネルの容量を表すようにします 同様にKeyPathを使用して ソーラーパネルの軸タイプを取得し 各点の色をカスタマイズします 同種の修飾によく使われる その他すべてのモディファイアも KeyPath引数をサポートします Apple Vision Proと 空間コンピューティングで 私のアプリが素晴らしい見栄えになります 左側のベクトル化プロットは アニメーションが滑らかで ダッシュボードのすべてのグラフは 棒グラフをスクラブすると 同時に更新されます ピンチアンドドラッグにより 先ほど 追加したベクトル化プロットが拡大され 各ソーラーパネル施設を 詳しく見ることができ 先ほど作成した正規分布プロットを 一目で把握できます これがベクトル化プロットです ベクトル化されたプロットとマークが どう補完し合うか疑問があるかもしれません プロット全体をカスタマイズするような 大規模なデータセットには ベクトル化プロットを 同じモディファイアと プロパティで使用します データポイントが少ない時は Mark APIを使いますが 個々のマークタイプとモディファイアを使って 各要素をカスタマイズする必要があります zIndexによる複雑なレイヤー化が 必要な場合も同様です ベクトル化プロットを使用する時は Swift Chartsにスタイル変更の 回数を減らさせることができます それには 使用するスタイルごとに データのコレクションをグループ化します レンダリング中に他の計算を 行わないようにすることも有効です 計算済みプロパティを ストアドプロパティに変換するなどです 使用するスタイルがわかっている場合や グラフの境界全体がわかっている場合は それらを指定するとグラフのレンダリングが より効率的になります 最後にスタイルのカスタマイズは 大量のデータポイントで 目立たないようにするのが一般的です それらを完全にスキップして グラフのパフォーマンスを 向上させることができます これがSwift Chartsの新しい ベクトル化プロットと関数プロットです これらの新機能を試して 視覚化をレベルアップしましょう サンプルプロジェクトをダウンロードして 関数プロットの他の例を確認してください インタラクションを追加する方法もあります Swift Chartsを初めて使う方は 以前のセッションを参考にしてください ありがとうございました みなさんの今後の構想が楽しみです 
- 
							- 
										
										1:43 - Histogram that shows distribution of capacity density Chart { ForEach(bins) { bin in BarMark( x: .value("Capacity density", bin.range), y: .value("Probability", bin.probability) ) } }
- 
										
										2:18 - Visualize function with LinePlot Chart { LinePlot( x: "Capacity density", y: "Probability" ) { x in // (Double) -> Double normalDistribution( x, mean: mean, standardDeviation: standardDeviation ) } }
- 
										
										3:36 - Customize function plot with modifiers Chart { LinePlot( x: "Capacity density", y: "Probability" ) { x in normalDistribution(x, ...) } .foregroundStyle(.gray }
- 
										
										3:57 - Visualize area under a curve with AreaPlot Chart { AreaPlot( x: "Capacity density", y: "Probability" ) { x in normalDistribution(x, ...) } .foregroundStyle(.gray) .opacity(0.2) }
- 
										
										4:21 - Visualize area between curves with AreaPlot Chart { AreaPlot( x: "x", yStart: "cos(x)", yEnd: "sin(x)" ) { x in (yStart: cos(x / 180 * .pi), yEnd: sin(x / 180 * .pi)) } }
- 
										
										4:59 - Specify domain for function plots Chart { AreaPlot( x: "x", yStart: "cos(x)", yEnd: "sin(x)" ) { x in (yStart: cos(x / 180 * .pi), yEnd: sin(x / 180 * .pi)) } } .chartXScale(domain: -315...225) .chartYScale(domain: -5...5)
- 
										
										5:18 - Specify sampling domain for function plots 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)) } } .chartXScale(domain: -315...225) .chartYScale(domain: -5...5)
- 
										
										5:55 - Visualize parametric functions 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)
- 
										
										6:40 - Use Double.nan to represent no value Chart { LinePlot(x: "x", y: "1 / x") { x in guard x != 0 else { return .nan } return 1 / x } } .chartXScale(domain: -10...10) .chartYScale(domain: -10...10)
- 
										
										7:43 - Highly customized Chart Chart { ForEach(model.data) { if $0.capacityDensity > 0.0001 { RectangleMark( x: .value("Longitude", $0.x), y: .value("Latitude", $0.y) ) .foregroundStyle(by: .value("Axis type", $0.axisType)) } else { PointMark( x: .value("Longitude", $0.x), y: .value("Latitude", $0.y) ) .opacity(0.5) } } }
- 
										
										8:00 - Homogeneously styled Chart 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) } }
- 
										
										8:23 - Vectorized plot for homogeneously styled chart Chart { RectanglePlot( model.data, x: .value("Longitude", \.x), y: .value("Latitude", \.y) ) .foregroundStyle(by: .value("Axis type", \.panelAxisType)) .opacity(\.capacityDensity) }
- 
										
										9:42 - Vectorized point plot API Chart { PointPlot( model.data, x: .value("Longitude", \.x), y: .value("Latitude", \.y) ) }
- 
										
										10:26 - Vectorized plot modifiers Chart { PointPlot( model.data, x: .value("Longitude", \.x), y: .value("Latitude", \.y) ) .symbolSize(by: .value("Capacity", \.capacity)) .foregroundStyle( by: .value("Axis type", \.panelAxisType) ) }
 
-