1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JetpackCompose Vico(v2.0.0)を使ったグラフ描画の実装サンプル

Last updated at Posted at 2025-02-02

はじめに

業務でvicoというグラフ描画ライブラリを使ったので、簡単な実装サンプルを共有します。

Vicoとは

vicoとはグラフを描画するために使用するライブラリです。

Androidでグラフを実装する場合、公式には提供されていないため、ライブラリを頼る必要が、いくつか調べた中で
vicoは複雑なグラフも描画できる、良さそうってことで選択しました。

以下のVico を選択した理由です。

  • AndroidView と Jetpack Compose の両方に対応
  • メンテナンスが頻繁に行われている
  • 公式ドキュメントやサンプルアプリが充実

ちなみにiOSでは、Swift ChartsというApple純正のものが提供されています。

公式ドキュメント:
https://www.patrykandpatrick.com/vico/guide/stable

サンプルアプリもあるので、どんなグラフが描画できるのか簡単にイメージできます。
サンプルアプリ↓

ほぼメンテナンスが止まってしまっているのが 残念で、JetpackCompose に対応していないものもありますが、vico 意外にもいくつかライブラリがあったので載せておきます。

  • MPAndroidChart

    • 老舗。今はメンテ止まってしまっている
  • charts

    • composeにも対応しているが、これもメンテが止まっている
  • YCharts

    • こちらもcomposeに対応しているが、2年前にメンテが止まっている

Vicoの実装

1. 準備

公式ドキュメントのgetting startedに従い
version catalogに依存関係を定義します。
(version catalogを使わない方法も記載があります。)

注意:
Vico 2系のStable版が2025年1月20日にリリース されました。1系とはクラス構造が大きく異なり、 Breaking Change が発生しているため、移行には注意が必要そうです。今回は2系で動く実装サンプルです。

[versions]
vico = "2.0.1"
 
[libraries]
vico-compose = { group = "com.patrykandpatrick.vico", name = "compose", version.ref = "vico" }
 
vico-compose-m2 = { group = "com.patrykandpatrick.vico", name = "compose-m2", version.ref = "vico" }
 
vico-compose-m3 = { group = "com.patrykandpatrick.vico", name = "compose-m3", version.ref = "vico" }
 
vico-views = { group = "com.patrykandpatrick.vico", name = "views", version.ref = "vico" }

2. グラフの作成(棒グラフ)

サンプルを参考に、シンプルな 棒グラフ を作成します。

@Composable
fun VicoBarGraph(
    modifier: Modifier = Modifier
) {
    CartesianChartHost(
        chart =
        rememberCartesianChart(
            rememberColumnCartesianLayer(),
            startAxis = VerticalAxis.rememberStart(),
            bottomAxis = HorizontalAxis.rememberBottom(),
        ),
        model = CartesianChartModel(
            ColumnCartesianLayerModel.build { series(1, 2, 4, 8, 3, 10, 4, 7, 2, 6, 4, 8) }
        ),
    )
}

@Preview
@Composable
fun PreVicoBarGraph() {
    VicoBarGraph()
}

出力されるグラフ

3. グラフのカスタマイズ

(1) Y軸のカスタマイズ

y軸のカスタマイズはstartAxisにVerticalAxis渡すことでさまざまなカスタマイズができるようです。

startAxis = VerticalAxis.rememberStart() // rememberStartにさまざまな設定値を渡せる

①y軸のラベルのスタイルを調整
labelにTextComponentを渡す

startAxis = VerticalAxis.rememberStart(
    // y軸の目盛ラベルのスタイルを調整
    label = rememberTextComponent(
        color = Color.Red, // 目盛ラベルの色
        textSize = 12.sp, // フォントサイズ
    ),
)

出力結果:
他にも通常のTextコンポーネントの同じような設定(lineHeight、textAlignment)も調整が可能。

②y軸のスタイルを調整

lineにLineComponentを渡す

startAxis = VerticalAxis.rememberStart(
    // y軸のスタイルを調整
    line = rememberLineComponent(
        fill = fill(Color.Blue), // y軸の色
    ),
)

出力結果:
他にもy軸の太さなども変更可能。

スクリーンショット 2025-02-02 14.00.06.png

③y軸の補助線のスタイルを調整

guidelineにLineComponentを渡す

startAxis = VerticalAxis.rememberStart(
    // 補助線のスタイルを調整
    guideline = rememberLineComponent(
        fill = fill(Color.Blue)
    ),
)

出力結果:
他にも、補助線を実線や点線にすることなどもできます。

スクリーンショット 2025-02-02 14.04.24.png

④y軸の目盛線のスタイルを調整

tickにLineComponentを渡す

startAxis = VerticalAxis.rememberStart(
    // y軸の目盛のスタイルを調整、数字の横に出る線
    tick = rememberLineComponent(
        fill = fill(Color.Green),                
    ),                            
)

出力結果:
少しわかりづらいですが、y軸の目盛の線が変わっています。

スクリーンショット 2025-02-02 14.16.37.png

(2) x軸をカスタマイズ

x軸も同じようにy軸とほぼ同じでbottomAxisにHorizontalAxisを渡すことでさまざまなカスタマイズができるようです。

bottomAxis = HorizontalAxis.rememberBottom(), // rememberBottomにさまざまな設定値を渡せる

①x軸の項目ラベルのスタイルを調整

labelにTextComponentを渡す

bottomAxis = HorizontalAxis.rememberBottom(
    // x軸の項目ラベルのスタイルを調整
    label = rememberTextComponent(
        color = Color.Red, // 項目ラベルの色
        textSize = 12.sp, // フォントサイズ
    ),
)

出力結果:
スクリーンショット 2025-02-02 14.25.58.png

②x軸のスタイルを調整

lineにLineComponentを渡す

bottomAxis = HorizontalAxis.rememberBottom(
    // x軸のスタイルを調整
    line = rememberLineComponent(
        fill = fill(Color.Red)
    ),
)

出力結果:
スクリーンショット 2025-02-02 14.30.11.png

③補助線のスタイルを調整

guidelineにLineComponentを渡す。

bottomAxis = HorizontalAxis.rememberBottom(
    // 補助線のスタイルを調整
    guideline = rememberLineComponent(
        fill = fill(Color.Red),
        shape = dashedShape(), // 点線にする
    ),
)

出力結果:
スクリーンショット 2025-02-02 14.32.32.png

④x軸のラベル名を任意の文字列に変更

valueFormatterに任意の文字列を渡す。

val xAxisLabels = listOf("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L")

bottomAxis = HorizontalAxis.rememberBottom(
    // x軸のラベル名の文字列を調整
    valueFormatter = { _, x, _ ->
        xAxisLabels[x.toInt() % xAxisLabels.size]
    }
)

出力結果:

スクリーンショット 2025-02-02 14.38.50.png

⑤x軸のラベル名の表示パターン調整

itemPlacerにHorizontalAxis.ItemPlacerを渡す

bottomAxis = HorizontalAxis.rememberBottom(
    itemPlacer = HorizontalAxis.ItemPlacer.aligned(
        spacing = { 5 }, // x軸のラベルを何個ごとに表示するか
        offset = { 1 }, // x軸のラベルのどこから表示を始めるか
    ),
)

出力結果:

スクリーンショット 2025-02-02 14.43.43.png

4. 棒線をカスタマイズ

①棒線のスタイルを調整

columnProviderにColumnCartesianLayerを渡すことで調整が可能

rememberColumnCartesianLayer(
    columnProvider = ColumnCartesianLayer.ColumnProvider.series(
        rememberLineComponent(
            fill = fill(Color.Red), // 棒線の色
            thickness = 8.dp, // 棒線の太さ
            shape = CorneredShape.rounded(
                topLeftPercent = 40, // 棒線の角丸
                topRightPercent = 40 // 棒線の角丸
            ),
        )
    ),
),

スクリーンショット 2025-02-02 14.52.47.png

②棒線の表示間隔を調整

columnCollectionSpacingに値をセット

rememberColumnCartesianLayer(
    columnCollectionSpacing = 5.dp, // 各棒線の間のスペース
),

スクリーンショット 2025-02-02 14.56.37.png

5. グラフのスクロール

グラフをスクロール可能にするには VicoScrollState を設定します。

CartesianChartHost(
    model = cartesianChartModel,
    scrollState = rememberVicoScrollState(
        scrollEnabled = true , // スクロール可能か
        initialScroll = Scroll.Absolute.Start, // スクロール可能な場合に初期表示をどこから開始するか
    ),
)

スクロール動作:

注意点

アニメーション

グラフをアニメーションさせるにはCartesianChartModelProducerから、LaunchedEffectを使ってデータを渡すような実装にする必要があります。しかし、そうすると、プレビューでグラフが確認できなくなるので、以下のようにプレビューとビルド時の処理を分けました。

@Composable
fun VicoBarGraph(
    modifier: Modifier = Modifier
) {
    val isPreview = LocalInspectionMode.current

    val data = listOf(1, 2, 4, 8, 3, 10, 4, 7, 2, 6, 4, 8, 9, 10, 11, 12)

    val chart = rememberCartesianChart(
        rememberColumnCartesianLayer(),
        startAxis = VerticalAxis.rememberStart(),
        bottomAxis = HorizontalAxis.rememberBottom()
    )

    if (isPreview) {
        // プレビューでグラフを確認するためにはCartesianChartModelを使う必要がある
        val cartesianChartModel = remember {
            CartesianChartModel(
                ColumnCartesianLayerModel.build { series(*data.toTypedArray()) }
            )
        }
        CartesianChartHost(
            chart = chart,
            model = cartesianChartModel
        )
    } else {
        // modelProducerを使うと、プレビューではグラフが確認できなくなるが、
        // グラフのアニメーションをさせるために必要なので、分ける
        val modelProducer = remember { CartesianChartModelProducer() }
        LaunchedEffect(Unit) {
            modelProducer.runTransaction {
                columnSeries { series(*data.toTypedArray()) }
            }
        }
        CartesianChartHost(
            chart = chart,
            modelProducer = modelProducer,
        )
    }
}

以上です。

所感

Vicoはグラフの描画自体は比較的簡単に実装可能 です。
しかし、カスタマイズに関しては 公式ドキュメントだけでは分かりにくい部分もあり、サンプルコードを直接読んで試行錯誤する必要がありました。xy軸の細かい設定や、複数のグラフを組みわ合わせることもできるような部分は単純にすごいと思いました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?