Jetpack Compose: Charts and Graphs

In modern Android development, visualizing data effectively is a crucial aspect of creating insightful and engaging applications. Jetpack Compose, Android’s modern UI toolkit, offers powerful and flexible tools to implement charts and graphs. Although Compose does not provide built-in chart components, you can create them from scratch or use existing charting libraries tailored for Compose.

Why Charts and Graphs in Jetpack Compose?

  • Data Visualization: Transform raw data into understandable and actionable insights.
  • Improved User Experience: Engage users with visually appealing and interactive charts.
  • Customization: Create highly customized charts tailored to your application’s design and requirements.

Methods for Implementing Charts and Graphs in Jetpack Compose

There are several approaches to implement charts and graphs in Jetpack Compose. We will cover two primary methods:

  1. Building Charts from Scratch using Canvas
  2. Using Third-Party Charting Libraries

Method 1: Building Charts from Scratch Using Canvas

Jetpack Compose’s Canvas composable allows you to draw custom graphics. This is ideal for creating highly specific and tailored charts.

Step 1: Basic Setup

Create a composable function to hold your chart:


import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun LineChart(data: List) {
    Canvas(modifier = Modifier.fillMaxSize()) {
        // Drawing logic will go here
    }
}

@Preview(showBackground = true)
@Composable
fun LineChartPreview() {
    val sampleData = listOf(
        Pair(0f, 20f),
        Pair(1f, 50f),
        Pair(2f, 30f),
        Pair(3f, 60f),
        Pair(4f, 40f)
    )
    LineChart(data = sampleData)
}
Step 2: Drawing the Line Chart

Implement the drawing logic inside the Canvas composable:


import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

@Composable
fun LineChart(data: List) {
    Canvas(modifier = Modifier.fillMaxSize()) {
        val chartHeight = size.height
        val chartWidth = size.width

        val maxValue = data.maxOf { it.second }
        val points = data.map { dataPoint ->
            Offset(
                x = dataPoint.first / data.size * chartWidth,
                y = chartHeight - (dataPoint.second / maxValue * chartHeight)
            )
        }

        val path = Path().apply {
            moveTo(points.first().x, points.first().y)
            points.forEach { point ->
                lineTo(point.x, point.y)
            }
        }

        drawPath(
            path = path,
            color = Color.Blue,
            style = androidx.compose.ui.graphics.drawscope.Stroke(width = 3.dp.toPx())
        )
    }
}

@Preview(showBackground = true)
@Composable
fun LineChartPreview() {
    val sampleData = listOf(
        Pair(0f, 20f),
        Pair(1f, 50f),
        Pair(2f, 30f),
        Pair(3f, 60f),
        Pair(4f, 40f)
    )
    LineChart(data = sampleData)
}

In this example:

  • The height and width of the canvas are determined.
  • The maximum value in the data is identified to normalize the chart.
  • The points are mapped to the canvas coordinates.
  • A Path is created to draw lines between these points.
  • The drawPath function is used to render the line on the canvas.

Method 2: Using Third-Party Charting Libraries

For more complex charts or ready-made solutions, consider using third-party charting libraries that support Jetpack Compose.

MPAndroidChart

MPAndroidChart is a powerful charting library that can be integrated with Jetpack Compose using AndroidView.

Step 1: Add Dependency

Include the MPAndroidChart dependency in your build.gradle file:


dependencies {
    implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
}
Step 2: Create a Chart Composable

Wrap the ChartView within a Compose AndroidView:


import androidx.compose.runtime.Composable
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.Modifier
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.data.LineData
import android.graphics.Color

@Composable
fun MPAndroidLineChart(data: List) {
    AndroidView(
        factory = { context ->
            LineChart(context).apply {
                val entries = data.map { Entry(it.first, it.second) }
                val dataSet = LineDataSet(entries, "Label").apply {
                    color = Color.BLUE
                    valueTextColor = Color.BLACK
                }

                val lineData = LineData(dataSet)
                this.data = lineData

                description.isEnabled = false
                invalidate()
            }
        },
        update = { chart ->
            val entries = data.map { Entry(it.first, it.second) }
            val dataSet = LineDataSet(entries, "Label").apply {
                color = Color.BLUE
                valueTextColor = Color.BLACK
            }

            val lineData = LineData(dataSet)
            chart.data = lineData

            chart.invalidate()
        },
        modifier = Modifier.fillMaxSize()
    )
}
Step 3: Usage

Use the MPAndroidLineChart composable in your layout:


import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun ChartScreen() {
    val sampleData = listOf(
        Pair(0f, 20f),
        Pair(1f, 50f),
        Pair(2f, 30f),
        Pair(3f, 60f),
        Pair(4f, 40f)
    )
    MPAndroidLineChart(data = sampleData)
}

@Preview(showBackground = true)
@Composable
fun ChartScreenPreview() {
    ChartScreen()
}

This example integrates MPAndroidChart into a Jetpack Compose application, creating a line chart using the provided data.

Conclusion

Creating charts and graphs in Jetpack Compose allows for both highly customized solutions and the integration of powerful third-party libraries. Whether you need detailed control over every aspect of the chart or prefer ready-made solutions, Jetpack Compose provides the flexibility to achieve your data visualization goals. Building charts from scratch with Canvas offers unparalleled customization, while libraries like MPAndroidChart provide ready-to-use, complex chart types. By choosing the right approach, you can create informative and visually appealing charts that enhance the user experience of your Android applications.