ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Swift Charts: より高いレベルへ
データの視覚化を深く掘り下げます:Swift ChartやSwiftUIが、さまざまなグラフオプションを使用して、複雑なデータセットをAppで表示する仕組みをご確認ください。さまざまな種類のデータをプロットしたり、マークを作成したりして、詳細なグラフを作成する方法を紹介します。また、Swift Chartsの広範なグラフのカスタマイズAPIについても解説します。これにより、グラフのスタイルをご利用のAppにマッチさせることが可能になります。 このセッションを最大限に活用するには、WWDC22の「Swift Chartsの紹介」をまずご確認ください。
リソース
関連ビデオ
Tech Talks
WWDC22
-
ダウンロード
♪ヒップホップ音楽♪ ♪ こんにちは Donghaoです 本セッションでは Swift Chartsによる 優れたデータの視覚化の 実現方法について解説します 言い換えれば Appで グラフを使ってできることの 基準を より高くできればと思います 優れたデータの視覚化により Appはより有益に そしてより魅力的な ものになります Appで優れたグラフを 作成するために 考慮すべきことは たくさんあります もちろん基礎となるデータを 忠実に伝えられ 誰もがアクセス可能な グラフを作りたいですね ですが App内のグラフが 孤立していてはいません Appのユーザー インターフェイスの一部となります ローカリゼーションやダークモード等の OS機能サポートが必要です グラフに対しUIの残りの部分と シームレスにフィットする 適切なレイアウトが必要です 画面サイズ ダイナミックタイプ などのサポートも必要です すべてのプラットフォームで 機能する必要もあり 素晴らしいアニメーションと 最高の見た目も欲しいですね Swift Chartsは こういった 基本的な機能の多くを 自動で処理するので ユーザーは独自のデータの 伝達に関してや最良の グラフの作成 そして 優れたアクセスの実現に 集中することができます Swift Chartsは SwiftUIのような 宣言型構文を使って これらを実現します 少量のコードでグラフに 必要なものを 指定すれば Swift Chartsが 自動的に素晴らしい グラフを作成します Swift Chartsには カスタマイズオプションの セットも豊富なので App独自のスタイルにも 対応することができます このセッションは Swift Chartsを より深く理解していただく ためのものです まずは 宣言型構文の 基本的な 構成要素について説明します つまりマークと マークの構成についてです これはApple製品で グラフを使ったいくつかの例です ご覧のとおり 様々なデータや グラフのタイプ スタイルがあります 予め構成済みの要素を 提供する代わりに Swift Chartsは グラフのタイプごとに 構成を適用していくという考えに 基づいて構築されています 少数の基本的な 構成要素を提供し 様々な方法で それらを組み合わせることで 様々なグラフを 作成することができます ではどのように機能するかを お見せしましょう 例を使って見てみましょう チームメートは皆 パンケーキが大好きなので 多くの種類のパンケーキを 売るフードトラックの 注文を追跡する Appがあります これが過去30日間で 販売されたパンケーキの 数を種類別に分類して 示すグラフです これは棒グラフとして 広く知られています Swift Chartsは 6つの青い長方形を それぞれマークとみなします マークとはデータを表す グラフィック要素です これは過去30日間に 販売された カチャパの数を示す バーマークです このグラフには 6つの バーマークがあり それぞれがパンケーキの スタイルと 対応する売上数を 示しています これがコードでどう 書かれているかを見てみます ここには 「最も売れた商品 カチャパ」など説明的な タイトルを含むSwiftUI ビューと空のグラフがあり ここでのChart型は トップレベルのビューで 単一のグラフを 定義しています 他のビューを追加するのと 同様に SwiftUIベースのApp同様に グラフを追加できます 残りは グラフに 焦点を当てていきましょう グラフにマークを追加します ここにカチャパと その売上数を示す 一本のバーマークがあります これからバーマークが付いた グラフが一つ作成されます スクリーンショットで見ると 残りのグラフが ユーザーインターフェイスに うまくフィットしていて 素晴らしいデフォルトの スタイルになっています 例えば X軸の数値は 整数で表示されています 別の名前と売上の バーマークを追加すると 2本目の棒が表示されます これを繰り返して 棒を追加していきます 実際のAppでは これらのマークはおそらく プログラムで生成されます これを行うには構造体 またはタプルの配列を グラフに提供し ForEachを使って 各要素の値で バーマークを作成します このように ForEachが 唯一のコンテンツの場合 Chartに直接データを 入れることもできます 多くをSwiftUIモディファイアを マークに使用できます 例えば.foregroundStyle モディファイアを使って 棒の色を 設定することができます ここでは名前付きの 色に設定しました これはXcodeで名前付き アセットとして作成できます 誰でもグラフに アクセスできることは 非常に重要です デフォルトでは自動生成の アクセシビリティ要素で VoiceOverユーザーへの アクセスを提供します これは.accessibilityLabelと accessibilityValueモディファイアで カスタマイズが可能です 例えば ここではラベルを パンケーキの名前 そして「を販売」を 売上の数値に 設定します するとVoiceOverユーザー向けの カスタム体験となります VoiceOver:カチャパ 916を販売 インジェラ 850を販売 クレープ 802を販売 このAppは数日にかけて 販売された パンケーキの数も 追跡します ここでは過去30日間で 販売された パンケーキの数を 表示しています グラフで日ごとの 詳細なビューが表示できます このグラフの作り方を 見てみましょう ここに曜日と売上の データ配列があります 曜日は一日の始まりの Date値で表されます バーマークで データを視覚化し Xは曜日 そしてこの 単位パラメーターは Date値で暦日の期間を 表すことを意味しています Yはその日の売上を 示しています すると右のように 数日間に渡る売上を示す 棒グラフが表示されました このデータを視覚化する方法 は棒グラフ以外にもあります 折れ線グラフを 試してみましょう 唯一の変更点は BarMarkをLineMarkに 置き換えることです Swift Chartsでは 宣言型構文を使うと グラフタイプ間の切替が 非常に簡単になります 前のグラフは時間の経過に 伴う総売上高を示しています でもフードトラックは2つの 都市で運営しています 平日 どこへ行くかを 決めるため 2つの都市の売上高を 比較したいと思います この線は月曜から日曜までの 売上を示しています 各線は都市を表します どのように組み立てられているか 見てみましょう ここに2つの都市の データがあるとします ここではタプルの配列で 定義されています それぞれに都市名と 平日の売上が含まれています 次にseriesDataをループする ForEachを使って 前の折れ線グラフを ラップします 2つの都市を 区別するため .foregroundStyle(by:) モディファイアを使って 都市名で2つのラインの スタイルを設定します ご覧のとおり Swift Chartsは自動的に 2色を選択して 2つの都市に色を付けます そして各色の意味を 示す凡例を追加します デフォルトの色は 区別しやすい システムカラーが 選択されます 色覚異常の人にも 読みやすくするため さらに差別化するには ラインにシンボルを 追加することもできます これには.symbol(by:) モディファイアを追加し データには 都市を使用します 最後にラインを 滑らかに見せるために interpolationMethodを使って 曲線にすることもできます 2つ配列の 折れ線グラフでも バーマークに戻って見え方を 確認することができます マークタイプを BarMarkに変更し 棒に関係のない モディファイアを削除すると 積み上げ棒グラフになります 棒が自動的に 積み重なるのは 毎月2つの棒があるからです 積み上げ棒グラフは 2つの都市の合計売上高を 表示するのに最適ですが 2つの都市間の比較には あまり適していません 比較しやすくするために .position(by:)モディファイアを 使ってグループ化した 棒グラフに変換します バーマークとラインマークを 見てきましたが他にも ポイントマークやエリアマーク ルールマーク レクタングルマーク などのマークタイプを サポートしています 組み合わせれば より複雑な グラフが作成できます 例を見てみましょう 毎月の1日の 平均売上高を示す 折れ線グラフから 始めましょう 平均は便利ですが より極端な値によるヒントを 得るため 1日の最小売上と 最大売上も確認したいと 思います これらの値をデータに 追加して始めましょう データ配列内の各要素に 毎日の最小値と 最大値を導入します 次に 最小値と最大値を エリアマークで視覚化します ここでXは月を示していて Yは毎日の最小値から 始まり毎日の 最大値で終了します すると1日の平均値を示す 折れ線グラフが作られて 毎日の最小値と最大値が ラインの周りの領域となって 表示されます この種のデータを 視覚化する方法は ラインとエリアだけ ではありません 簡単に他のマークタイプに 切り替えて より多くのデザインオプションを 探ることができます ここではBarMarkを使います ですが線が棒とうまく フィットしていないようです ラインマークを 2点の高さをもつ レクタングルマークに 変更しましょう するとレクタングルマークは 平均値を示す 棒の内側に 水平線を作成します このマークの幅を 調整することもできます ここでは例えば .6の比率で 幅を設定しています これは棒と長方形の幅が 1か月の幅の 60%になることを 意味することが スクリーンショットから 分かりますね 最後にすべての月における 1日の平均売上を表示する オプションが欲しいですね それにはまず foregroundStyleを 薄いグレーにして目立たなくさせます 次に平均値を示すYで ForEachの外側に ルールマークを追加します これにより水平方向の ルールが追加されます ルールが年平均を示している ことを明確にするために .annotationモディファイアを 使って ルールに注釈を追加すること ができ これにより ルールマークの上部に 前方方向に揃えられた テキストラベルが 追加されます 構成によるグラフ作成 について いくつか例を挙げて 説明しました これらの基本的なマークの 使い方や組み合わせ方には 様々な方法があります 例えば箱ひげ図 複数系列の 折れ線グラフ 人口ピラミッド 範囲プロット ストリームグラフ 多配列散布プロット ヒートマップやベクトルフィールドの プロットなどです これらはSwift Chartsで 作成できる 様々なグラフの ほんの一例です では次のトピックに 移りましょう マークプロパティを使った データのプロット方法です Swift Chartsは量的 名目的 そして時間的の 主要な3タイプのデータを サポートしています 量的データは数値で 販売された製品の数 部屋の温度や株の価格などが 当てはまります Swift ChartsはIntやFloat Doubleのような Swiftの数値タイプを 量的データとして扱います 名目データ または カテゴリデータは 個別のカテゴリまたは グループを表します 例えば人の名前や 大陸 または 製品の種類などです 文字列やカスタム文字列値の 列挙型を 名目データとして 使用できます 時間的データは ある時点 または時間の間隔を表します 例えば 特定の日の期間 またはトランザクションの 正確な時間などです Swift Chartsは日付を 時間データとして扱います グラフは売上高のような 抽象データを マークのプロパティに変換する ことによって機能します X YとForeground Style プロパティを使って データをプロットできる BarMarkを見てみましょう この例ではX属性のある 量的な売上高を Y属性のある名目的データ つまり名前を使って プロットします 結果としてグラフは 横棒で構成され Xには売上高 Yには名前が それぞれ表示されます 名前と売上高を入れ替えると 名前がXで売上高がY そして横棒ではなく 縦棒のグラフになります ご覧のとおり BarMarkの動作は XとYプロパティにプロットされた データによって異なります 棒の向きは 量的プロパティがどこにあるかに 応じて変わります 次にデータのプロットに 3つのプロパティすべてを含む 別のグラフを見てみましょう ここでは時間的データ 平日をX Yに販売高と Foreground Styleで 都市をプロットします するとX軸は平日 Y軸は売上を示し 都市ごとに色分けされた 積み上げ棒グラフになります Swift Chartsには 6つのマークタイプと データをプロットできる 6つのマークプロパティがあります データには3種類あることを 覚えていますね つまり考えられる組合わせは 膨大な数になります これが Swift Chartsが 少数の基礎的要素で 幅広いグラフデザインを サポートできる理由です 例えば Yを売上高とした マークプロパティを使って データをプロットする場合 Swift Chartsは 抽象データを プロパティの適切な値に変換する マッピングを作成します この場合 売上高を 画面空間のY座標に 変換します 売上などの抽象的データから Yポジションのような マークプロパティまでの マッピングを指して 「スケール」という用語を 使います スケールはデータ値を取って プロパティ値を返す 関数と考えることができます 例えば これは売上を 受け取って バーのY位置を返す Yスケールの関数です 「スケール」という名前は 位置プロパティの場合 入力値を 何らかの係数でスケーリング して適切な画面座標に 変換することが多いことに 由来しています マークプロパティで データをプロットする場合 データを変換するための スケールは対応する マークプロパティに作成されます 例えば このグラフには 3つのスケールがあります それぞれが平日をXに 売上をYに変換します そして都市は Foreground Styleに変換します デフォルトではデータから 自動的にスケールを 推測するので設定なしに 優れたグラフが完了します グラフのスケールを 設定するには scaleモディファイアを使います いくつか例を見てみましょう この例では Yスケールは 自動的に ゼロから150であると 推測されています でも現在の売上が どうであっても Yスケールが 常に一貫するように Yスケールを 修正したいと思います Yスケールが常に ゼロで始まり 200で終わるように 変更してみましょう それには.chartYScale モディファイアを使って スケールのドメインを ゼロから200に設定します ご覧のとおり 軸がゼロから 200になりました 同様に 2つの都市の マッピングを変更するには .chartForegroundStyleScale モディファイアを使えば Foreground Styleに 適用できます これで 2つの都市に 新しい色がつきました これでマークの作成方法と マークプロパティを使ったデータの プロット方法がわかりました Swift Chartsに含まれる 他の カスタマイズオプションを 詳しく見ていきましょう グラフは軸 場合によっては 凡例 そして プロット領域で 構成されています 軸と凡例は グラフの解釈に役立ちます プロット領域とは 2つの軸の間の領域で マークによってデータを プロットする場所です これはすべてSwift Chartsで カスタマイズが可能です まずは軸と凡例を カスタマイズする方法の 例をいくつか見てみましょう これは月間総売上高を 示すグラフです Swift Chartsは カスタマイズをしなくても 丸められた値を使った 軸をデフォルトで生成します 現在 X軸には四半期ごとの ラベルが表示されています 1文字の月のラベルで 毎月表示するように 変更しましょう まず.chartXAxisモディファイアを 追加します AxisMarksをコンテンツとして X軸をカスタマイズします パラメータのないAxisMarksは デフォルト軸を再作成します 軸の値を変更することから 始めましょう 定期的な暦日での間隔が 必要なので 標準ライブラリの stride関数と同様に stride(by:)を使うことが できます これで毎月のラベルが できました でもスクリーンショットで 見るとデフォルトの ラベルは 密集しすぎて見じます 十分なスペースがないため 一部のラベルが切れています ラベル形式を 1文字に変更してみましょう それには個々の コンポーネントから Axisマークを作成します つまり AxisGridLine AxisTick AxisValueLabelです 月の名前が短くなるよう ラベル形式を設定しましょう これで毎月の名前が 1文字になりました 結果のビルダーへ 渡される値パラメータが 現在の軸の値に 関する情報を提供します これを使用すると Axisマークの存在とスタイルを 条件付きで決定できます 例えば日付としての値が 月の第1四半期かどうかを テストする条件があります そうである場合は 各四半期の最初の月を 別のForeground Styleで 強調表示します そうでない場合は 目盛りとラベルのない グリッド線のみを表示します 今は四半期を 表示しているので 形式を四半期スタイルに 変更しましょう 今行ったカスタマイズでは サブグリッド線が 毎月表示された よりユニークなX軸を示す 四半期データとなります 値に加えて Axisマークには 一般的な外観と スタイルを構成する 他の属性があります Y軸をデフォルトの 後ろ側ではなく グラフの前側に 表示したいとしましょう その場合は positionパラメータをleadingに 設定して前側に移動させます Swift Chartsは軸と 視覚化するデータタイプに基づき Axisマークのプリセット をデフォルト設定します プリセットパラメータで デフォルトを上書きできます ここではY軸が残りの ユーザーインターフェイスと 視覚的に合うように .extendedプリセットを 使用しています グラフによっては軸の表示を したくない場合があります 例えば ここでの 売上高グラフの目的は 見る人に簡単な概要を 伝えることなので 実際のところ 軸は必要ありません .hiddenをChart Axis モディファイアに渡して 軸を非表示にしましょう 凡例の構成は 軸の構成に似ています 例えば 最高の日と場所を 強調するこのグラフでは すでに不透明度で 最高の都市を強調しています 自動生成された凡例は 非表示にしましょう それには.chartLegend モディファイアを追加し パラメータには .hiddenを使用します それではプロット領域に ついてお話しましょう グラフのプロット領域を 構成するには chartPlotStyleモディファイアを 使用します 後ろのクロージャでは 元のプロット領域を取り 変更された プロット領域を返す 関数を書きます いくつか例を見てみましょう 場合によっては 正確なサイズまたは 比率のプロット領域が 必要になることがあります 例えばこの場合 グラフ内の カテゴリの数によって 駆動されるプロット領域の 高さが必要です これにはプロット領域に .frameモディファイアを 適用し変更された プロット領域を返すと プロット領域の高さが 設定されます モディファイアで特殊視覚効果 を実現することもできます このダークモードグラフでは .backgroundモディファイアを 使ってピンクの背景を 追加して 不透明度を.2にして グラフを少し目立たせます 次に1ポイントの同じ色で 境界線を追加すると グラフに独自の 視覚効果が作成されます 前半でスケールに ついて触れました これはXやYなどの プロパティに対し データ値をマップする 関数でしたね Swift Chartsは XとYスケールへの アクセスを可能にする ChartProxyを提供します 特定のデータ値の 位置を取得するには ChartProxyの position(for:)メソッド またはvalue(at:) メソッドを使用して 指定の位置の データ値を取得します すると他のビューを グラフと調整できます 例を見てみましょう インタラクティブな 分析ビューを作りましょう ここを ドラッグジェスチャで グラフから間隔を選択すると 詳細ビューで 行をフィルタリングするために 使用されます .chartOverlayまたは .chartBackgroundモディファイア からproxyオブジェクトが 取得できます この2つのモディファイアは SwiftUIのoverlayと backgroundモディファイア に似ていますが Chart Proxyを 提供してくれます この例を作成するには 前と同様にベースのグラフを 定義することから始めます その後Chart Proxyを 提供する.chartOverlay モディファイアを追加します 中にはオーバーレイビューの ジオメトリにアクセスを 可能にするジオメトリ リーダーがあります 次にSwiftUIのDragGestureに 応答するように 構成された 長方形ビューがあります ドラッグジェスチャが 発生するとまずは グラフの プロット領域内にある 開始と現在の場所の X座標が見つかります これはプロット領域の原点を 差し引くことによって ジェスチャによって提供 される場所から行われます この座標を取得したら Chart Proxyを使用できます 対応する日付値を 見つけるには 最後に現在の日付間隔を 追跡する SwiftUIステートに 設定します 範囲のステートを使用すると 現在選択されている 日付範囲を視覚化するための 長方形マークを定義できます この状態は Appの 他のパーツを 制御するためにも使えます 例えばグラフの 下の詳細ビューの コンテンツをフィルタリング する場合などです これはChart Proxyが どのように機能するかを 説明する簡単な例です これを使うと多くの興味深い 機能を構築できます 例えばこの インタラクティブグラフでは ロリポップのような オーバーレイで 選択した日と売上高が 表示されます このセッションでは マークを作成して グラフを作成する方法 マークプロパティを使って データをプロットする方法 グラフをカスタマイズ する方法を見てきました グラフを使った優れた エクスペリエンスの実現と 効果的なグラフのデザイン 方法の詳細については デザインセッションに アクセスしてください Swift Chartsを使った データの視覚化構築が 好きになると思います ご視聴 ありがとうございました ♪
-
-
3:48 - Top style chart
import SwiftUI import Charts struct TopStyleChart: View { let data = [ (name: "Cachapa", sales: 916), (name: "Injera", sales: 850), (name: "Crêpe", sales: 802), (name: "Jian Bing", sales: 753), (name: "Dosa", sales: 654), (name: "American", sales: 618) ] var body: some View { Chart(data, id: \.name) { BarMark( x: .value("Sales", $0.sales), y: .value("Name", $0.name) ) // Set the foreground style of the bars. .foregroundStyle(.pink) // Customize the accessibility label and value. .accessibilityLabel($0.name) .accessibilityValue("\($0.sales) sold") } } }
-
5:12 - Daily sales chart
struct DailySalesChart: View { var body: some View { Chart { ForEach(dailySales, id: \.day) { // Try change to LineMark. BarMark( x: .value("Day", $0.day, unit: .day), y: .value("Sales", $0.sales) ) } } } let dailySales: [(day: Date, sales: Int)] = [ (day: date(year: 2022, month: 5, day: 8), sales: 168), (day: date(year: 2022, month: 5, day: 9), sales: 117), (day: date(year: 2022, month: 5, day: 10), sales: 106), (day: date(year: 2022, month: 5, day: 11), sales: 119), (day: date(year: 2022, month: 5, day: 12), sales: 109), (day: date(year: 2022, month: 5, day: 13), sales: 104), (day: date(year: 2022, month: 5, day: 14), sales: 196), (day: date(year: 2022, month: 5, day: 15), sales: 172), (day: date(year: 2022, month: 5, day: 16), sales: 122), (day: date(year: 2022, month: 5, day: 17), sales: 115), (day: date(year: 2022, month: 5, day: 18), sales: 138), (day: date(year: 2022, month: 5, day: 19), sales: 110), (day: date(year: 2022, month: 5, day: 20), sales: 106), (day: date(year: 2022, month: 5, day: 21), sales: 187), (day: date(year: 2022, month: 5, day: 22), sales: 187), (day: date(year: 2022, month: 5, day: 23), sales: 119), (day: date(year: 2022, month: 5, day: 24), sales: 160), (day: date(year: 2022, month: 5, day: 25), sales: 144), (day: date(year: 2022, month: 5, day: 26), sales: 152), (day: date(year: 2022, month: 5, day: 27), sales: 148), (day: date(year: 2022, month: 5, day: 28), sales: 240), (day: date(year: 2022, month: 5, day: 29), sales: 242), (day: date(year: 2022, month: 5, day: 30), sales: 173), (day: date(year: 2022, month: 5, day: 31), sales: 143), (day: date(year: 2022, month: 6, day: 1), sales: 137), (day: date(year: 2022, month: 6, day: 2), sales: 123), (day: date(year: 2022, month: 6, day: 3), sales: 146), (day: date(year: 2022, month: 6, day: 4), sales: 214), (day: date(year: 2022, month: 6, day: 5), sales: 250), (day: date(year: 2022, month: 6, day: 6), sales: 146) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: .init(year: year, month: month, day: day)) ?? Date() }
-
6:16 - Sales by location with line mark
struct LocationsChart: View { var body: some View { Chart { ForEach(seriesData, id: \.city) { series in ForEach(series.data, id: \.weekday) { LineMark( x: .value("Weekday", $0.weekday, unit: .day), y: .value("Sales", $0.sales) ) } .foregroundStyle(by: .value("City", series.city)) .symbol(by: .value("City", series.city)) .interpolationMethod(.catmullRom) } } } let seriesData = [ ( city: "Cupertino", data: [ (weekday: date(year: 2022, month: 5, day: 2), sales: 54), (weekday: date(year: 2022, month: 5, day: 3), sales: 42), (weekday: date(year: 2022, month: 5, day: 4), sales: 88), (weekday: date(year: 2022, month: 5, day: 5), sales: 49), (weekday: date(year: 2022, month: 5, day: 6), sales: 42), (weekday: date(year: 2022, month: 5, day: 7), sales: 125), (weekday: date(year: 2022, month: 5, day: 8), sales: 67) ] ), ( city: "San Francisco", data: [ (weekday: date(year: 2022, month: 5, day: 2), sales: 81), (weekday: date(year: 2022, month: 5, day: 3), sales: 90), (weekday: date(year: 2022, month: 5, day: 4), sales: 52), (weekday: date(year: 2022, month: 5, day: 5), sales: 72), (weekday: date(year: 2022, month: 5, day: 6), sales: 84), (weekday: date(year: 2022, month: 5, day: 7), sales: 84), (weekday: date(year: 2022, month: 5, day: 8), sales: 137) ] ) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
7:19 - Sales by location with bar mark
struct LocationsChart: View { var body: some View { Chart { ForEach(seriesData, id: \.city) { series in ForEach(series.data, id: \.weekday) { BarMark( x: .value("Weekday", $0.weekday, unit: .day), y: .value("Sales", $0.sales) ) } .foregroundStyle(by: .value("City", series.city)) .position(by: .value("City", series.city)) } } } let seriesData = [ ( city: "Cupertino", data: [ (weekday: date(year: 2022, month: 5, day: 2), sales: 54), (weekday: date(year: 2022, month: 5, day: 3), sales: 42), (weekday: date(year: 2022, month: 5, day: 4), sales: 88), (weekday: date(year: 2022, month: 5, day: 5), sales: 49), (weekday: date(year: 2022, month: 5, day: 6), sales: 42), (weekday: date(year: 2022, month: 5, day: 7), sales: 125), (weekday: date(year: 2022, month: 5, day: 8), sales: 67) ] ), ( city: "San Francisco", data: [ (weekday: date(year: 2022, month: 5, day: 2), sales: 81), (weekday: date(year: 2022, month: 5, day: 3), sales: 90), (weekday: date(year: 2022, month: 5, day: 4), sales: 52), (weekday: date(year: 2022, month: 5, day: 5), sales: 72), (weekday: date(year: 2022, month: 5, day: 6), sales: 84), (weekday: date(year: 2022, month: 5, day: 7), sales: 84), (weekday: date(year: 2022, month: 5, day: 8), sales: 137) ] ) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
8:02 - Monthly sales with line and area marks
struct MonthlySalesChart: View { var body: some View { Chart { ForEach(data, id: \.month) { AreaMark( x: .value("Month", $0.month, unit: .month), yStart: .value("Daily Min", $0.dailyMin), yEnd: .value("Daily Max", $0.dailyMax) ) .opacity(0.3) LineMark( x: .value("Month", $0.month, unit: .month), y: .value("Daily Average", $0.dailyAverage) ) } } } let data = [ (month: date(year: 2021, month: 7), sales: 3952, dailyAverage: 127, dailyMin: 95, dailyMax: 194), (month: date(year: 2021, month: 8), sales: 4044, dailyAverage: 130, dailyMin: 96, dailyMax: 189), (month: date(year: 2021, month: 9), sales: 3930, dailyAverage: 131, dailyMin: 101, dailyMax: 184), (month: date(year: 2021, month: 10), sales: 4217, dailyAverage: 136, dailyMin: 96, dailyMax: 193), (month: date(year: 2021, month: 11), sales: 4006, dailyAverage: 134, dailyMin: 104, dailyMax: 202), (month: date(year: 2021, month: 12), sales: 3994, dailyAverage: 129, dailyMin: 96, dailyMax: 190), (month: date(year: 2022, month: 1), sales: 4202, dailyAverage: 136, dailyMin: 96, dailyMax: 203), (month: date(year: 2022, month: 2), sales: 3749, dailyAverage: 134, dailyMin: 98, dailyMax: 200), (month: date(year: 2022, month: 3), sales: 4329, dailyAverage: 140, dailyMin: 104, dailyMax: 218), (month: date(year: 2022, month: 4), sales: 4084, dailyAverage: 136, dailyMin: 93, dailyMax: 221), (month: date(year: 2022, month: 5), sales: 4559, dailyAverage: 147, dailyMin: 104, dailyMax: 242), (month: date(year: 2022, month: 6), sales: 1023, dailyAverage: 170, dailyMin: 120, dailyMax: 250) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
8:46 - Monthly sales with bar and rectangle marks
struct MonthlySalesChart: View { var body: some View { Chart { ForEach(data, id: \.month) { BarMark( x: .value("Month", $0.month, unit: .month), yStart: .value("Daily Min", $0.dailyMin), yEnd: .value("Daily Max", $0.dailyMax), width: .ratio(0.6) ) .opacity(0.3) RectangleMark( x: .value("Month", $0.month, unit: .month), y: .value("Daily Average", $0.dailyAverage), width: .ratio(0.6), height: 2 ) } } } let data = [ (month: date(year: 2021, month: 7), sales: 3952, dailyAverage: 127, dailyMin: 95, dailyMax: 194), (month: date(year: 2021, month: 8), sales: 4044, dailyAverage: 130, dailyMin: 96, dailyMax: 189), (month: date(year: 2021, month: 9), sales: 3930, dailyAverage: 131, dailyMin: 101, dailyMax: 184), (month: date(year: 2021, month: 10), sales: 4217, dailyAverage: 136, dailyMin: 96, dailyMax: 193), (month: date(year: 2021, month: 11), sales: 4006, dailyAverage: 134, dailyMin: 104, dailyMax: 202), (month: date(year: 2021, month: 12), sales: 3994, dailyAverage: 129, dailyMin: 96, dailyMax: 190), (month: date(year: 2022, month: 1), sales: 4202, dailyAverage: 136, dailyMin: 96, dailyMax: 203), (month: date(year: 2022, month: 2), sales: 3749, dailyAverage: 134, dailyMin: 98, dailyMax: 200), (month: date(year: 2022, month: 3), sales: 4329, dailyAverage: 140, dailyMin: 104, dailyMax: 218), (month: date(year: 2022, month: 4), sales: 4084, dailyAverage: 136, dailyMin: 93, dailyMax: 221), (month: date(year: 2022, month: 5), sales: 4559, dailyAverage: 147, dailyMin: 104, dailyMax: 242), (month: date(year: 2022, month: 6), sales: 1023, dailyAverage: 170, dailyMin: 120, dailyMax: 250) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
9:19 - Monthly sales with average line and annotation
struct MonthlySalesChart: View { var body: some View { Chart { ForEach(data, id: \.month) { BarMark( x: .value("Month", $0.month, unit: .month), yStart: .value("Daily Min", $0.dailyMin), yEnd: .value("Daily Max", $0.dailyMax), width: .ratio(0.6) ) .opacity(0.3) RectangleMark( x: .value("Month", $0.month, unit: .month), y: .value("Daily Average", $0.dailyAverage), width: .ratio(0.6), height: 2 ) } .foregroundStyle(.gray.opacity(0.5)) RuleMark( y: .value("Average", averageValue) ) .lineStyle(StrokeStyle(lineWidth: 3)) .annotation(position: .top, alignment: .leading) { Text("Average: \(averageValue, format: .number)") .font(.headline) .foregroundStyle(.blue) } } } let data = [ (month: date(year: 2021, month: 7), sales: 3952, dailyAverage: 127, dailyMin: 95, dailyMax: 194), (month: date(year: 2021, month: 8), sales: 4044, dailyAverage: 130, dailyMin: 96, dailyMax: 189), (month: date(year: 2021, month: 9), sales: 3930, dailyAverage: 131, dailyMin: 101, dailyMax: 184), (month: date(year: 2021, month: 10), sales: 4217, dailyAverage: 136, dailyMin: 96, dailyMax: 193), (month: date(year: 2021, month: 11), sales: 4006, dailyAverage: 134, dailyMin: 104, dailyMax: 202), (month: date(year: 2021, month: 12), sales: 3994, dailyAverage: 129, dailyMin: 96, dailyMax: 190), (month: date(year: 2022, month: 1), sales: 4202, dailyAverage: 136, dailyMin: 96, dailyMax: 203), (month: date(year: 2022, month: 2), sales: 3749, dailyAverage: 134, dailyMin: 98, dailyMax: 200), (month: date(year: 2022, month: 3), sales: 4329, dailyAverage: 140, dailyMin: 104, dailyMax: 218), (month: date(year: 2022, month: 4), sales: 4084, dailyAverage: 136, dailyMin: 93, dailyMax: 221), (month: date(year: 2022, month: 5), sales: 4559, dailyAverage: 147, dailyMin: 104, dailyMax: 242), (month: date(year: 2022, month: 6), sales: 1023, dailyAverage: 170, dailyMin: 120, dailyMax: 250) ] let averageValue = 137 } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
13:54 - Chart with custom scales for Y and foreground style
struct LocationsChart: View { var body: some View { Chart { ForEach(seriesData, id: \.city) { series in ForEach(series.data, id: \.weekday) { LineMark( x: .value("Weekday", $0.weekday, unit: .day), y: .value("Sales", $0.sales) ) } .foregroundStyle(by: .value("City", series.city)) .symbol(by: .value("City", series.city)) .interpolationMethod(.catmullRom) } } .chartYScale(domain: 0 ... 200) .chartForegroundStyleScale([ "San Francisco": .orange, "Cupertino": .pink ]) } let seriesData = [ ( city: "Cupertino", data: [ (weekday: date(year: 2022, month: 5, day: 2), sales: 54), (weekday: date(year: 2022, month: 5, day: 3), sales: 42), (weekday: date(year: 2022, month: 5, day: 4), sales: 88), (weekday: date(year: 2022, month: 5, day: 5), sales: 49), (weekday: date(year: 2022, month: 5, day: 6), sales: 42), (weekday: date(year: 2022, month: 5, day: 7), sales: 125), (weekday: date(year: 2022, month: 5, day: 8), sales: 67) ] ), ( city: "San Francisco", data: [ (weekday: date(year: 2022, month: 5, day: 2), sales: 81), (weekday: date(year: 2022, month: 5, day: 3), sales: 90), (weekday: date(year: 2022, month: 5, day: 4), sales: 52), (weekday: date(year: 2022, month: 5, day: 5), sales: 72), (weekday: date(year: 2022, month: 5, day: 6), sales: 84), (weekday: date(year: 2022, month: 5, day: 7), sales: 84), (weekday: date(year: 2022, month: 5, day: 8), sales: 137) ] ) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
15:16 - Chart with custom X axis
struct MonthlySalesChart: View { var body: some View { Chart(data, id: \.month) { BarMark( x: .value("Month", $0.month, unit: .month), y: .value("Sales", $0.sales) ) } .chartXAxis { AxisMarks( values: .stride(by: .month) ) { value in AxisGridLine() AxisTick() AxisValueLabel( format: .dateTime.month(.narrow) ) } } } let data = [ (month: date(year: 2021, month: 7), sales: 3952), (month: date(year: 2021, month: 8), sales: 4044), (month: date(year: 2021, month: 9), sales: 3930), (month: date(year: 2021, month: 10), sales: 4217), (month: date(year: 2021, month: 11), sales: 4006), (month: date(year: 2021, month: 12), sales: 3994), (month: date(year: 2022, month: 1), sales: 4202), (month: date(year: 2022, month: 2), sales: 3749), (month: date(year: 2022, month: 3), sales: 4329), (month: date(year: 2022, month: 4), sales: 4084), (month: date(year: 2022, month: 5), sales: 4559), (month: date(year: 2022, month: 6), sales: 1023) ] let averageValue = 137 } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
16:17 - Chart with custom X axis and conditional content for axis marks
struct MonthlySalesChart: View { var body: some View { Chart(data, id: \.month) { BarMark( x: .value("Month", $0.month, unit: .month), y: .value("Sales", $0.sales) ) } .chartXAxis { AxisMarks(values: .stride(by: .month)) { value in if value.as(Date.self)!.isFirstMonthOfQuarter { AxisGridLine().foregroundStyle(.black) AxisTick().foregroundStyle(.black) AxisValueLabel( format: .dateTime.month(.narrow) ) } else { AxisGridLine() } } } } let data = [ (month: date(year: 2021, month: 7), sales: 3952), (month: date(year: 2021, month: 8), sales: 4044), (month: date(year: 2021, month: 9), sales: 3930), (month: date(year: 2021, month: 10), sales: 4217), (month: date(year: 2021, month: 11), sales: 4006), (month: date(year: 2021, month: 12), sales: 3994), (month: date(year: 2022, month: 1), sales: 4202), (month: date(year: 2022, month: 2), sales: 3749), (month: date(year: 2022, month: 3), sales: 4329), (month: date(year: 2022, month: 4), sales: 4084), (month: date(year: 2022, month: 5), sales: 4559), (month: date(year: 2022, month: 6), sales: 1023) ] let averageValue = 137 } extension Date { var isFirstMonthOfQuarter: Bool { Calendar.current.component(.month, from: self) % 3 == 1 } } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
17:00 - Chart with custom Y axis
struct MonthlySalesChart: View { var body: some View { Chart(data, id: \.month) { BarMark( x: .value("Month", $0.month, unit: .month), y: .value("Sales", $0.sales) ) } .chartYAxis { AxisMarks( preset: .extended, position: .leading) } } let data = [ (month: date(year: 2021, month: 7), sales: 3952), (month: date(year: 2021, month: 8), sales: 4044), (month: date(year: 2021, month: 9), sales: 3930), (month: date(year: 2021, month: 10), sales: 4217), (month: date(year: 2021, month: 11), sales: 4006), (month: date(year: 2021, month: 12), sales: 3994), (month: date(year: 2022, month: 1), sales: 4202), (month: date(year: 2022, month: 2), sales: 3749), (month: date(year: 2022, month: 3), sales: 4329), (month: date(year: 2022, month: 4), sales: 4084), (month: date(year: 2022, month: 5), sales: 4559), (month: date(year: 2022, month: 6), sales: 1023) ] let averageValue = 137 } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
18:26 - Chart with plot area style
struct TopStyleChart: View { var body: some View { Chart(data, id: \.name) { BarMark( x: .value("Sales", $0.sales), y: .value("Name", $0.name) ) // Set the foreground style of the bars. .foregroundStyle(.pink) // Customize the accessibility label and value. .accessibilityLabel($0.name) .accessibilityValue("\($0.sales) sold") } .chartPlotStyle { plotArea in plotArea.frame(height: 60 * 6) .background(.pink.opacity(0.2)) .border(.pink, width: 1) } } let data = [ (name: "Cachapa", sales: 916), (name: "Injera", sales: 850), (name: "Crêpe", sales: 802), (name: "Jian Bing", sales: 753), (name: "Dosa", sales: 654), (name: "American", sales: 618) ] }
-
20:03 - Chart with brushing interaction
struct InteractiveBrushingChart: View { @State var range: (Date, Date)? = nil var body: some View { Chart { ForEach(data, id: \.day) { LineMark( x: .value("Month", $0.day, unit: .day), y: .value("Sales", $0.sales) ) .interpolationMethod(.catmullRom) .symbol(Circle().strokeBorder(lineWidth: 2)) } if let (start, end) = range { RectangleMark( xStart: .value("Selection Start", start), xEnd: .value("Selection End", end) ) .foregroundStyle(.gray.opacity(0.2)) } } .chartOverlay { proxy in GeometryReader { nthGeoItem in Rectangle().fill(.clear).contentShape(Rectangle()) .gesture(DragGesture() .onChanged { value in // Find the x-coordinates in the chart’s plot area. let xStart = value.startLocation.x - nthGeoItem[proxy.plotAreaFrame].origin.x let xCurrent = value.location.x - nthGeoItem[proxy.plotAreaFrame].origin.x // Find the date values at the x-coordinates. if let dateStart: Date = proxy.value(atX: xStart), let dateCurrent: Date = proxy.value(atX: xCurrent) { range = (dateStart, dateCurrent) } } .onEnded { _ in range = nil } // Clear the state on gesture end. ) } } } let data: [(day: Date, sales: Int)] = [ (day: date(year: 2022, month: 5, day: 8), sales: 168), (day: date(year: 2022, month: 5, day: 9), sales: 117), (day: date(year: 2022, month: 5, day: 10), sales: 106), (day: date(year: 2022, month: 5, day: 11), sales: 119), (day: date(year: 2022, month: 5, day: 12), sales: 109), (day: date(year: 2022, month: 5, day: 13), sales: 104), (day: date(year: 2022, month: 5, day: 14), sales: 196), (day: date(year: 2022, month: 5, day: 15), sales: 172), (day: date(year: 2022, month: 5, day: 16), sales: 122), (day: date(year: 2022, month: 5, day: 17), sales: 115), (day: date(year: 2022, month: 5, day: 18), sales: 138), (day: date(year: 2022, month: 5, day: 19), sales: 110), (day: date(year: 2022, month: 5, day: 20), sales: 106), (day: date(year: 2022, month: 5, day: 21), sales: 187), (day: date(year: 2022, month: 5, day: 22), sales: 187), (day: date(year: 2022, month: 5, day: 23), sales: 119), (day: date(year: 2022, month: 5, day: 24), sales: 160), (day: date(year: 2022, month: 5, day: 25), sales: 144), (day: date(year: 2022, month: 5, day: 26), sales: 152), (day: date(year: 2022, month: 5, day: 27), sales: 148), (day: date(year: 2022, month: 5, day: 28), sales: 240), (day: date(year: 2022, month: 5, day: 29), sales: 242), (day: date(year: 2022, month: 5, day: 30), sales: 173), (day: date(year: 2022, month: 5, day: 31), sales: 143), (day: date(year: 2022, month: 6, day: 1), sales: 137), (day: date(year: 2022, month: 6, day: 2), sales: 123), (day: date(year: 2022, month: 6, day: 3), sales: 146), (day: date(year: 2022, month: 6, day: 4), sales: 214), (day: date(year: 2022, month: 6, day: 5), sales: 250), (day: date(year: 2022, month: 6, day: 6), sales: 146) ] } func date(year: Int, month: Int, day: Int = 1) -> Date { Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date() }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。