概要
Swift Charts には6つの mark があります。Mark とは、図を構成する単位のことです。
WWDC では、これらの mark を組み合わせることで様々なグラフを作ることができると言っていました。
(WWDC 2022 Swift Charts: Raise the bar)
今回は、WWDC の動画で例に挙がっていた箱ひげ図を書いてみます。スクリーンショットは載せられないのですが、以下の箱ひげ図とほぼ同じものができます。
(WWDC 2022 Swift Charts: Raise the bar)
コード
Swift Charts を使うには Charts
パッケージを import します。
import Charts
まず、データの準備です。今回は箱ひげ図用の BoxPlotData
と外れ値用の PointData
という2つの struct を定義しました。
struct PointData: Identifiable {
var value: Double
var id = UUID()
}
struct BoxplotData: Identifiable {
var name: String
var maximum: Double
var thirdQuantile: Double
var median: Double
var firstQuantile: Double
var minimum: Double
var outliers: [PointData]
var id = UUID()
}
let type1Data: [BoxplotData] = [
.init(name: "A", maximum: 180, thirdQuantile: 160, median: 150, firstQuantile: 140, minimum: 90, outliers: [.init(value: 190), .init(value: 195), .init(value: 210), .init(value: 80), .init(value: 78)]),
.init(name: "B", maximum: 180, thirdQuantile: 160, median: 150, firstQuantile: 140, minimum: 90, outliers: [.init(value: 190), .init(value: 195), .init(value: 210), .init(value: 80), .init(value: 78)])
]
let type2Data: [BoxplotData] = [
.init(name: "A", maximum: 160, thirdQuantile: 140, median: 130, firstQuantile: 120, minimum: 60, outliers: [.init(value: 170), .init(value: 175), .init(value: 180), .init(value: 60), .init(value: 58)]),
.init(name: "B", maximum: 160, thirdQuantile: 140, median: 130, firstQuantile: 120, minimum: 60, outliers: [.init(value: 170), .init(value: 175), .init(value: 180), .init(value: 60), .init(value: 58)])
]
let allData: [(type: String, data: [BoxplotData])] = [
(type: "Type 1", data: type1Data),
(type: "Type 2", data: type2Data)
]
では、実際に書いていきます。
struct ContentView: View {
var body: some View {
Chart {
ForEach(allData, id: \.type) { typeData in
ForEach(typeData.data, id: \.name) { dat in
// 箱
BarMark(
x: .value("Name", dat.name),
yStart: .value("First Quantile", dat.firstQuantile),
yEnd: .value("Third Quantile", dat.thirdQuantile)
)
// 縦線
RuleMark(
x: .value("Name", dat.name),
yStart: .value("Minimum", dat.minimum),
yEnd: .value("Maximum", dat.maximum)
)
// 最小値の横線
RectangleMark(
x: .value("Name", dat.name),
y: .value("Minimum", dat.minimum),
width: .ratio(0.2),
height: 2
)
// 最大値の横線
RectangleMark(
x: .value("Name", dat.name),
y: .value("Maximum", dat.maximum),
width: .ratio(0.2),
height: 2
)
// 中央値の横線
RectangleMark(
x: .value("Name", dat.name),
y: .value("Median", dat.median),
height: 2
)
.foregroundStyle(.black)
// 外れ値
ForEach(dat.outliers) { outlier in
PointMark(
x: .value("Name", dat.name),
y: .value("Value", outlier.value)
)
.opacity(0.6)
}
}
.foregroundStyle(by: .value("Type", typeData.type))
.position(by: .value("Type", typeData.type))
}
}
.padding(20)
}
}
箱のプロットに BarMark
を使っていますが、これは RectangleMark
に置き換えても同じ結果になります:
RectangleMark(
x: .value("Name", dat.name),
yStart: .value("First Quantile", dat.firstQuantile),
yEnd: .value("Third Quantile", dat.thirdQuantile)
)
まとめ
今回は Bar、Rule、Rectangle、Point の4つの mark を使って箱ひげ図が作れることが分かりました。このように、複数の mark を使って様々なグラフを作ることができそうです。