※一般公開されているSession/Documentation/Sample Codeページだけを使ってこの記事を執筆しました。
SessionビデオやDocumentationページからの画像を収録しています。
実際のチャートは、Xcode 14でコードを実行することで確認することができます。
新しくリリースされたチャートフレームワークにより、独自のチャートビューを設計したり、サードパーティライブラリを使用する必要がなくなりました。
最も基本的な機能としては、棒グラフ、ラインポイント(折れ線グラフ)、ポイントチャートを表現することができます。
ここでは、1つのデータ点をデータエントリーと呼ぶことにします。
データ構造を設計する
各データエントリーを格納するデータ構造を用意する必要があります。最も単純なものは、名前と値を持つ構造体です。
struct ChartEntry: Identifiable {
var title: String
var value: Double
var color: Color = .green
var id: String {
return title + String(value)
}
}
color
も追加されているので、個々のデータ入力ごとにバー(棒グラフ)/ラインポイント/ポイントの色をカスタマイズすることができます。
また、これを Identifiable
プロトコルに適合させる必要があります。ListやForEachに対して行うのと同じように。
Chart
ビュー要素
最初に、SwiftUIのビューファイル内でチャートフレームワークをインポートしていることを確認してください。import Charts
Chart
ブロックは List
と非常によく似ています。
すべてのデータエントリを含む配列を Chart
ビュー要素のパラメータ内に直接置くことができます。
以下のコードでは、 data
はデータ配列 (データセット。 [ChartEntry]
として定義されます) で、 dataPoint
は各データ (ChartEntry
やその他のカスタム構造体として定義されます) です。
例えば、気温を表示する場合、 data
はすべての天気の気温のエントリを含む配列であり、 dataPoint
は1つの気温のエントリである。
Chart(data) { dataPoint in
// TODO
}
.frame(height: 200)
または、Chart
ビュー要素内に ForEach
を配置することもできます。
Chart {
ForEach(data) { dataPoint in
// TODO
}
}
.frame(height: 200)
ForEach`ブロック内では、各データエントリに表示するビューを作成します。
例えば、棒グラフを表示したい場合は、各データエントリーに棒(バー)のビュー(BarMark)を作成します。
棒グラフ
ビュー要素 BarMark
を使用し、X軸にタイトル、Y軸に値を表示します。
BarMark(
x: .value("タイトル", dataPoint.title),
y: .value("値", dataPoint.value)
)
.foregroundStyle(dataPoint.color)
上記のコードをChartまたはForEachブロック内に配置します。
let data: [ChartEntry] = [
.init(title: "A", value: 5),
.init(title: "B", value: 10),
.init(title: "C", value: 8)
]
Chart(data) { dataPoint in
BarMark(
x: .value("タイトル", dataPoint.title),
y: .value("値", dataPoint.value)
)
.foregroundStyle(dataPoint.color)
}
.frame(height: 200)
そして、棒グラフが表示されます。
同じカテゴリーに複数のバーを追加する。
Chartビューでは、X軸のタイトル(名前)でカテゴリを識別します。
同じX軸の名前を持つ要素が複数ある場合、Chartビューは既存のバーの上にバーを表示します。
let data_test: [ChartEntry] = [
.init(title: "A", value: 5),
.init(title: "A", value: 10, color: .blue),
.init(title: "B", value: 10),
.init(title: "C", value: 8)
]
Chart {
ForEach(data_test) { dataPoint in
BarMark(
x: .value("Category", dataPoint.title),
y: .value("Value", dataPoint.value)
)
.foregroundStyle(dataPoint.color)
}
}
.frame(height: 200)
上記のコード例では、X軸の名前を "A"とし、色を青としたデータエントリーを追加定義しているのがわかります。これで、チャートは次の画像のようになります。
この場合、同じ名前 "A "を持つ2つのデータが統合され、同じ縦線に表示されています。
x軸とy軸を反転させる
x軸にラベル、y軸に値を表示する代わりに、x軸に値を表示することもできます(横線グラフ)。
let data: [ChartEntry] = [
.init(title: "A", value: 5),
.init(title: "B", value: 10),
.init(title: "C", value: 8)
]
Chart(data) { dataPoint in
BarMark(
x: .value("Value", dataPoint.value),
y: .value("Category", dataPoint.title)
)
.foregroundStyle(dataPoint.color)
}
.frame(height: 200)
xパラメータに値、yパラメータにタイトルを入れることができます。
表示されているチャートを更新する
チャートに入力するデータセットに @State
変数を使うこともできる。そうすれば、データを更新したり、別のデータセットを表示したりすることができる。
struct ContentView: View {
static let demoData1: [ChartEntry] = [
.init(title: "A", value: 5),
.init(title: "B", value: 10),
.init(title: "C", value: 8)
]
static let demoData2: [ChartEntry] = [
.init(title: "A", value: 5),
.init(title: "A", value: 10, color: .blue),
.init(title: "B", value: 10),
.init(title: "C", value: 8)
]
@State var data: [ChartEntry] = [
.init(title: "A", value: 5),
.init(title: "B", value: 10),
.init(title: "C", value: 8)
]
@State private var dataSetSelection: Int = 0
var body: some View {
Form {
Picker("Dataset selection", selection: $dataSetSelection) {
Text("Dataset 1")
.tag(0)
Text("Dataset 2")
.tag(1)
}
.onChange(of: dataSetSelection) { newValue in
withAnimation {
if newValue == 0 {
self.data = ContentView.demoData1
} else if newValue == 1 {
self.data = ContentView.demoData2
}
}
}
Chart {
ForEach(data) { dataPoint in
BarMark(
x: .value("Value", dataPoint.value),
y: .value("Category", dataPoint.title)
)
.foregroundStyle(dataPoint.color)
}
}
.frame(height: 200)
}
}
}
データが更新されるとき、withAnimation
ブロック内にコードを置くと、チャートはアニメーションで更新されます。
ラインチャート(折れ線グラフ)
BarMarkを
LineMark`に変更するだけで、ラインチャート(折れ線グラフ)が表示されるようになります。
Chart {
ForEach(data) { dataPoint in
LineMark(
x: .value("Category", dataPoint.title),
y: .value("Value", dataPoint.value)
)
.foregroundStyle(dataPoint.color)
}
}
.frame(height: 200)
注:折れ線グラフの場合、値は通常Y軸に、ラベルは通常X軸に表示されます。
ポイントチャート
BarMark
を PointMark
に変更すると、ポイントチャートが得られます。
Chart {
ForEach(data) { dataPoint in
PointMark(
x: .value("Category", dataPoint.title),
y: .value("Value", dataPoint.value)
)
.foregroundStyle(dataPoint.color)
}
}
.frame(height: 200)
注:ポイントチャートの場合、値は通常Y軸に、ラベルは通常X軸に表示されます。
点で構成される折れ線グラフを表示する
上で説明したように、同じX軸のラベルを持つ複数のデータポイントがある場合、SwiftUIはそれらを結合します。そこで、これを利用して、ポイントを持つ折れ線グラフを表示することができます。
基本的に、ForEachループ内では、LineMark(折れ線グラフに使用)とPointMark(点線グラフに使用)の両方を返すことになります。
Chart {
ForEach(Charts_PointLine.demoData1) { dataPoint in
LineMark(
x: .value("Category", dataPoint.title),
y: .value("Value", dataPoint.value)
)
.foregroundStyle(dataPoint.color)
PointMark(
x: .value("Category", dataPoint.title),
y: .value("Value", dataPoint.value)
)
}
}
.frame(height: 200)
1つのグラフに複数のデータセットを表示する
1つのグラフの中に複数のデータセットを表示することもできます。
まず、データセット(データの集合体)を表す構造体を新規に作成します。
struct DataCollection: Identifiable {
var collectionName: String
var data: [ChartEntry]
var id: String { return collectionName }
}
上記のデータセットオブジェクトには、データセットの名前と、データエントリーが含まれます。
そして、データエントリーを持つデータセットを作成することができます。
static let demoData1: [ChartEntry] = [
.init(title: "Morning", value: 20),
.init(title: "Noon", value: 27),
.init(title: "Evening", value: 21)
]
static let demoData2: [ChartEntry] = [
.init(title: "Morning", value: 13),
.init(title: "Noon", value: 14),
.init(title: "Evening", value: 8)
]
@State var dataCollections: [DataCollection] = [
.init(collectionName: "Kyoto", data: demoData1),
.init(collectionName: "Hokkaido", data: demoData2)
]
各データセットをループするために、すべてのデータセットを含む配列(dataCollections)を Chart
のパラメータに渡します。
Chart
のブロックの中で、一つのデータセット内のすべてのデータエントリー(collection.data)をループするために、 ForEach
を追加します。
Chart(dataCollections) { collection in
ForEach(collection.data) { dataPoint in
PointMark(
x: .value("Category", dataPoint.title),
y: .value("Value", dataPoint.value)
)
.foregroundStyle(by: .value("City", collection.collectionName))
}
}
.frame(height: 200)
チャートに都市の名前を表示するために、.foregroundStyle(by: .value("City", collection.collectionName))
を使って、チャートに都市の名前を表示しました。
SwiftUIは自動的に各データセットに異なる色を選択します。
水平線・垂直線を表示する (RuleMark)
チャートに水平線または垂直線を表示することができます。
例えば、チャート内の全データの平均値を示すのに使用できます。
水平線: RuleMark(y: <#T##PlottableValue<Plottable>#>)
垂直線: RuleMark(s: <#T##PlottableValue<Plottable>#>)
高度なチャートタイプ
他にもいくつかの高度なチャートタイプがあります。
例えば、AreaMark
を使えば、チャート上のある領域をマークすることができます。
例えば、温度範囲をマークすることができます。
struct ChartEntry_minMax: Identifiable {
var title: String
var minY: Int
var maxY: Int
var averageY: Int {
return (minY + maxY) / 2
}
var id: String { return title }
}
struct Charts_AreaMark: View {
@State var data: [ChartEntry_minMax] = [
.init(title: "Today", minY: 15, maxY: 27),
.init(title: "Tomorrow", minY: 17, maxY: 28),
.init(title: "Saturday", minY: 18, maxY: 24),
.init(title: "Sunday", minY: 16, maxY: 25),
.init(title: "Monday", minY: 14, maxY: 26),
.init(title: "Tuesday", minY: 17, maxY: 20),
.init(title: "Wednesday", minY: 17, maxY: 23)
]
var body: some View {
Form {
Chart {
ForEach(data) { dataPoint in
AreaMark(
x: .value("Category", dataPoint.title),
yStart: .value("Lowest temperature", dataPoint.minY),
yEnd: .value("Highest temperature", dataPoint.maxY)
)
.opacity(0.3)
LineMark(
x: .value("Category", dataPoint.title),
y: .value("Average", dataPoint.averageY)
)
}
}
.frame(height: 200)
}
.navigationTitle("Temperature")
}
}
他の種類のチャートについて知りたい方は、WWDCのビデオを見てください。
Enjoy the WWDC!
お読みいただきありがとうございました。
☺️ Twitter @MszPro
🐘 Mastodon @me@mszpro.com
Written by MszPro~
関連記事
・UICollectionViewの行セル、ヘッダー、フッター、またはUITableView内でSwiftUIビューを使用(iOS 16, UIHostingConfiguration)
・iPhone 14 ProのDynamic Islandにウィジェットを追加し、Live Activitiesを開始する(iOS16.1以降)
・iOS 16:秘密値の保存、FaceID認証に基づく個人情報の表示/非表示(LARight)
・iOS16 MapKitの新機能 : 地図から場所を選ぶ、通りを見回す、検索補完
・SwiftUIアプリでバックグラウンドタスクの実行(ネットワーク、プッシュ通知) (BackgroundTasks, URLSession)
・WWDC22、iOS16:iOSアプリに画像からテキストを選択する機能を追加(VisionKit)
・WWDC22、iOS16:数行のコードで作成できるSwiftUIの新機能(26本)
・WWDC22、iOS 16:SwiftUIでChartsフレームワークを使ってチャートを作成する
・WWDC22, iOS 16: WeatherKitで気象データを取得
Github repo
このGitHubリポジトリには、この記事で参照したコードが含まれています。