はじめに
SwiftUIのChartsで折れ線グラフを2つ表示させようとした時に苦戦したので記録しておきます。
サンプルアプリ
ダメな例
以下のようにLineMark
にforegroundStyle
をつけることで色を変えることができます。
Chart {
ForEach(temperatures, id: \.day) { temperature in
LineMark(
x: .value("day", temperature.day),
y: .value("max", temperature.max)
)
.foregroundStyle(Color.orange)
}
}
.frame(width: 300, height: 500)
しかし、2つグラフを表示しようとしても、1つしか表示されません。
Chart {
ForEach(temperatures, id: \.day) { temperature in
LineMark(
x: .value("day", temperature.day),
y: .value("max", temperature.max)
)
.foregroundStyle(Color.orange)
LineMark(
x: .value("day", temperature.day),
y: .value("min", temperature.min)
)
.foregroundStyle(Color.cyan)
}
}
.frame(width: 300, height: 500)
正しい実装
import SwiftUI
import Charts
struct Temperature {
let day: Int
let max: Double
let min: Double
}
struct ContentView: View {
@State private var temperatures: [Temperature] = [
.init(day: 1, max: 23, min: 13),
.init(day: 2, max: 25, min: 10),
.init(day: 3, max: 23, min: 11),
.init(day: 4, max: 21, min: 11),
.init(day: 5, max: 18, min: 12),
.init(day: 6, max: 19, min: 13),
.init(day: 7, max: 18, min: 15),
.init(day: 8, max: 22, min: 9),
.init(day: 9, max: 23, min: 10),
.init(day: 10, max: 24, min: 13),
]
var body: some View {
Chart {
ForEach(temperatures, id: \.day) { temperature in
LineMark(
x: .value("day", temperature.day),
y: .value("max", temperature.max)
)
+ .foregroundStyle(by: .value("max", "最高気温"))
LineMark(
x: .value("day", temperature.day),
y: .value("min", temperature.min)
)
+ .foregroundStyle(by: .value("min", "最低気温"))
}
}
+ .chartForegroundStyleScale(["最高気温": Color.orange, "最低気温": Color.cyan])
.frame(width: 300, height: 500)
}
}
解説
割とわかりにくいので解説します。
foregroundStyle(by:)
を使用して、キーを指定します。
.foregroundStyle(by: .value("max", "ここの値がキー1"))
.foregroundStyle(by: .value("min", "ここの値がキー2"))
foregroundStyle(by:)
で指定したキーをchartForegroundStyleScale
で色とセットで渡します。
.chartForegroundStyleScale(["ここの値がキー1": Color.orange, "ここの値がキー2": Color.cyan])
このようにキーと色を紐付けることで2つのグラフが表示されるようになります。
chartForegroundStyleScale
に存在しないキーを渡すとクラッシュします。
おわり
チャート用の機能がいっぱいあるのでちゃんとインプットしていかないと使いこなせなさそうです。