📊

【SwiftUI】Chartライブラリ比較

2023/10/31に公開

概要

SwiftUIを使ってChart表示を行う良さそうなライブラリがないか探した際のメモになります。
最終的に ChartsSwiftUICharts を比較した内容になりましたが、何かの参考になればと思います。

確認環境

$ sw_vers
ProductName: macOS
ProductVersion: 13.4.1
ProductVersionExtra: (c)
BuildVersion: 22F770820d
# XCode: Version 14.3.1 (14E300c)

1. 標準のChart SwiftUI View

Chart | Apple Developer Documentation

参考URL

SwiftUIで純正のChartが扱えるようになったみたいですが、iOS16以降との事で、今回の調査ではiOS16未満も対象にしてたのでスキップしてます。いずれは試してみたいと思います。

2. Charts

概要

MPAndroidChartのSwift実装版。ドキュメントはAndroid版のものを参照との事です。
MPAndroidChart Documentation - Weeklycoding

パッケージインストール (SPM)

早速試してみたいと思います。Package.swift に以下を追加します。

dependencies: [
    .package(url: "https://github.com/danielgindi/Charts.git", .upToNextMajor(from: "5.0.0"))
],
targets: [
    .target(
        name: "...",
        dependencies: [
            .product(name: "DGCharts", package: "Charts")
        ]),
]

※ 5.0からSwift Chart との競合を避けるため DGCharts という名前になったらしいです。

シンプルな実装 (BarChart)

SwiftUIの場合 UIViewRepresentable を使用します。

import DGCharts
import SwiftUI

struct SampleBarChartView: UIViewRepresentable {
    func makeUIView(context: Context) -> BarChartView {
        return BarChartView()
    }

    func updateUIView(_ uiView: BarChartView, context: Context) {
        let dataSet = BarChartDataSet(entries: [
            BarChartDataEntry(x: 1, y: 10),
            BarChartDataEntry(x: 2, y: 20),
            BarChartDataEntry(x: 3, y: 30)
        ])
        uiView.data = BarChartData(dataSet: dataSet)
    }
}

struct DGCharts: View {
    var body: some View {
        SampleBarChartView()
    }
}

struct DGCharts_Previews: PreviewProvider {
    static var previews: some View {
        DGCharts()
    }
}

↓ Preview結果

image1.png

次にデータ用のstructを用意して参照するようにしてみたいと思います。

struct SampleData を追加し、参照する様に修正します。

struct SampleData {
    var year: Int
    var month: Double
    var value: Double

    static func dataEntities() -> [BarChartDataEntry] {
        return allData.map { BarChartDataEntry(x: $0.month, y: $0.value) }
    }

    static var allData: [SampleData] =
        [
            SampleData(year: 2019, month: 0, value: 86),
            SampleData(year: 2019, month: 1, value: 15),
            SampleData(year: 2019, month: 2, value: 50),
            SampleData(year: 2019, month: 3, value: 62),
            SampleData(year: 2019, month: 4, value: 20),
            SampleData(year: 2019, month: 5, value: 19),
            SampleData(year: 2019, month: 6, value: 71),
            SampleData(year: 2019, month: 7, value: 52),
            SampleData(year: 2019, month: 8, value: 33),
            SampleData(year: 2019, month: 9, value: 75),
            SampleData(year: 2019, month: 10, value: 20),
            SampleData(year: 2019, month: 11, value: 90)
        ]
}

struct SampleBarChartView: UIViewRepresentable {
    func makeUIView(context: Context) -> BarChartView {
        return BarChartView()
    }

    func updateUIView(_ uiView: BarChartView, context: Context) {
        let dataSet = BarChartDataSet(entries: SampleData.dataEntities())
        uiView.data = BarChartData(dataSet: dataSet)
    }
}

↓Preview結果 比較的簡単に表示できました。

image2.png

LineChart

次にシンプルなLineChartを表示させてみたいと思います。

import DGCharts
import SwiftUI

struct SimpleLineChartView: UIViewRepresentable {
    func makeUIView(context: Context) -> LineChartView {
        return LineChartView()
    }

    func updateUIView(_ uiView: LineChartView, context: Context) {
        let dataSet = LineChartDataSet(entries: [
            ChartDataEntry(x: 1.0, y: 1.0),
            ChartDataEntry(x: 2.0, y: 1.5),
            ChartDataEntry(x: 3.0, y: 2.0),
        ])
        uiView.data = LineChartData(dataSet: dataSet)
    }
}

struct DGChartsLineChartSimple: View {
    var body: some View {
        SimpleLineChartView()
    }
}

struct DGChartsLineChartSimple_Previews: PreviewProvider {
    static var previews: some View {
        DGChartsLineChartSimple()
    }
}

↓Preview結果

image3.png

線の色を変える

次に線の色を変えてみます。

dataSet.setColor(.black)
dataSet.setCircleColor(.black) // ピボットの丸の色も変えたい場合はこちらも設定

image4.png

線の幅を変える

次に線の幅を変えてみます。

dataSet.lineWidth = 10
dataSet.circleRadius = 20 // ピボットの丸の大きさも変えたい場合はこちらも設定

image5.png

参考URL

https://youtu.be/csd7pyfEXgw?si=0Qf3vaoXeXr6-kAx
https://github.com/StewartLynch/Charts-BarChart-Complete
UIViewRepresentable を理解して SwiftUI の足りないところを UIKit で補う - Qiita

トラブルシューティング

ビルド時に以下エラーが出る

The package product 'DGCharts' requires minimum platform version 12.0 for the iOS platform, but this target supports 11.0
  • Package.swift に以下を追加する
platforms: [
        .iOS(.v12),
    ],

感想

  • 導入しやすく、カスタマイズ性もありそうな印象
  • 一番スター数が多く、メンテナンスも続いている
  • ドキュメントも豊富

2. SwiftUICharts

概要

SwiftUI を使って書かれた、アクセシビリティをサポートするシンプルな折れ線グラフと棒グラフのライブラリ

パッケージインストール (SPM)

Package.swift に以下追加します。

platforms: [
        .macOS(.v11),
        .iOS(.v14)
],
dependencies: [
    .package(url: "https://github.com/mecid/SwiftUICharts", branch: "main")
],
targets: [
    .target(
        name: "...",
        dependencies: [
            .product(name: "SwiftUICharts", package: "SwiftUICharts")
        ]),
]

シンプルな実装 (BarChart)

import SwiftUI
import SwiftUICharts

let highIntensity = Legend(color: .orange, label: "High Intensity", order: 5)
let buildFitness = Legend(color: .yellow, label: "Build Fitness", order: 4)
let fatBurning = Legend(color: .green, label: "Fat Burning", order: 3)
let warmUp = Legend(color: .blue, label: "Warm Up", order: 2)
let low = Legend(color: .gray, label: "Low", order: 1)

let limit = DataPoint(value: 130, label: "5", legend: fatBurning)

let points: [DataPoint] = [
    .init(value: 70, label: "1", legend: low),
    .init(value: 90, label: "2", legend: warmUp),
    .init(value: 91, label: "3", legend: warmUp),
    .init(value: 92, label: "4", legend: warmUp),
    .init(value: 130, label: "5", legend: fatBurning),
    .init(value: 124, label: "6", legend: fatBurning),
    .init(value: 135, label: "7", legend: fatBurning),
    .init(value: 133, label: "8", legend: fatBurning),
    .init(value: 136, label: "9", legend: fatBurning),
    .init(value: 138, label: "10", legend: fatBurning),
    .init(value: 150, label: "11", legend: buildFitness),
    .init(value: 151, label: "12", legend: buildFitness),
    .init(value: 150, label: "13", legend: buildFitness),
    .init(value: 136, label: "14", legend: fatBurning),
    .init(value: 135, label: "15", legend: fatBurning),
    .init(value: 130, label: "16", legend: fatBurning),
    .init(value: 130, label: "17", legend: fatBurning),
    .init(value: 150, label: "18", legend: buildFitness),
    .init(value: 151, label: "19", legend: buildFitness),
    .init(value: 150, label: "20", legend: buildFitness),
    .init(value: 160, label: "21", legend: highIntensity),
    .init(value: 159, label: "22", legend: highIntensity),
    .init(value: 161, label: "23", legend: highIntensity),
    .init(value: 158, label: "24", legend: highIntensity)
]

struct SwiftUIChartsBarChartSimple: View {
    var body: some View {
        BarChartView(dataPoints: points, limit: limit)
    }
}

struct SwiftUIChartsBarChartSimple_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIChartsBarChartSimple()
    }
}

↓Preview結果

image6.png

ChartのStyle調整

chartStyle を使ってStyleを指定していきます。内部ではこちらenvironment として設定しています。

extension View {
    public func chartStyle(_ style: ChartStyle) -> some View {
        environment(\.chartStyle, style)
    }
}

試しに以下の chartStyle を設定します。

struct SwiftUIChartsBarChartSimple: View {
    var body: some View {
        BarChartView(dataPoints: points, limit: limit)
            .chartStyle(
                BarChartStyle(
                    barMinHeight: 100,
                    showAxis: true,
                    axisLeadingPadding: 10,
                    showLabels: true,
                    labelCount: 20,
                    showLegends: false
                )
            )
    }
}

↓Preview結果

image7.png

感想

  • 比較的新しいライブラリでSwiftUIで実装されている
  • Zoomができない
  • ドキュメントが全然ない
  • DGChartsよりはカスタマイズ性が無いイメージ

その他

今回は見送ったライブラリになります。

https://github.com/AppPear/ChartView
https://github.com/dagronf/DSFSparkline
https://github.com/aunnnn/RHLinePlot
https://github.com/spacenation/swiftui-charts

参考URL

GitHub - Toni77777/awesome-swiftui-libraries: :rocket: Awesome SwiftUI Libraries

Discussion