Your first chart in Android App with CSV parser

android, UI, chart, CSV 8 mins edit

If you ever needed to add a chart to your Android app you certainly heard about MPAndroidChart by PhilJay. If not, consider using this powerful library. Let me show you how easy it is to start!

header img


The goal is to build a simple app written in Kotlin which displays linear chart with static data. To make it a little bit more interesting we’re going to provide data with .csv file. It is very simple format for storing table-based data in form of text files where values are separated with commas (Comma Separated Values). We’ll use OpenCSV library to parse it.


First add dependencies to gradle files.

allprojects {
    repositories {
        maven { url "" }
dependencies {
    implementation "com.github.PhilJay:MPAndroidChart:v3.0.3"
    implementation "com.opencsv:opencsv:4.1"

Raw Data Set

Find some data, for example from here. I chose food searches on Google set and cut it a little to display comparison of two searches: banana bread and frozen yogurt. File looks like this:


There are 676 records in both datasets. Values are normalised, so value is between 0 and 100, where 0 is lowest number of searches, 100 is the largest, and the rest are calculated proportionally.

Put banana_bread.csv & frozen_yogurt.csv under /app/res/raw directory in your project.

Now let’s make data class with corresponding field, simplest as can be:



data class FoodSearch(
        val id: String,
        val googleTopic: String,
        val week_id: String,
        val value: Int

How to parse it?

Take a look at parser below:



import com.opencsv.CSVReaderBuilder

class Parser {

    companion object {

        fun toDataSet(reader: Reader): List<FoodSearch> {

            val csvReader = CSVReaderBuilder(reader)

            val foodSearches = mutableListOf<FoodSearch>()
            var record = csvReader.readNext()

            while (record != null) {
                foodSearches.add(FoodSearch(record[0], record[1], record[2], record[3].toInt()))
                record = csvReader.readNext()

            return foodSearches

Static method builds list of FoodSearch records based on provided Reader. You can get reader from fileStream, which is provided with activity resources. Looks like this:

val streamBananas = resources.openRawResource(R.raw.banana_bread)
val bananaData = Parser.toDataSet(streamBananas.reader())

Finally our data looks a little bit more friendly. Time to make a chart!

Apply data

Add LineChart view to your layout, for example:

        android:layout_centerInParent="true" />

How to manage data now?

LineChart accepts data as an instance of LineData class. LineData is created from at least one instance of LineDataSet. LineDataSet is created from MutableList of Entry objects and String label. Huh. And Entry is an object representing single point on our Chart (basically is an (x,y) representation). Sounds a little bit overwhelming at first, but is pretty simple. Here are steps to follow:

  1. Parse your data from csv file to list of any data objects representing single point on the chart - DONE!
  2. Map list of data objects to list of Entry objects
  3. Create LineDataSet from list of entries and label, like “Banana Bread”
  4. Use each of sets as an argument to create LineData object. Voila.

private fun getEntriesFromCSV(rawResId: Int, label: String): LineDataSet {

    var data: List<FoodSearch>? = null
    resources.openRawResource(rawResId).use { stream ->
        data = Parser.toDataSet(stream.reader())
    val entries: MutableList<Entry> = ArrayList()

    data?.mapIndexed { index, foodSearch ->
                Entry(index.toFloat(), foodSearch.value.toFloat(), foodSearch)

    return LineDataSet(entries, label)

This function and Parser from previous paragraph creates LineDataSet from csv resource. Now simply call it for each csv file and create LineData:

val bananaDataSet = getEntriesFromCSV(R.raw.banana_bread, "Banana Bread")
val yogurtDataSet = getEntriesFromCSV(R.raw.frozen_yogurt, "Frozen Yogurt") = LineData(

That’s it, chart is set up with data! chart one

Make me beautiful - LineChart properties

Time to add some colors and spices. Chart layout configuration is very flexible. I’ll show you some basic properties, the rest you may find in the documentation. Props are separated between dataset-specific and chart-specific.

Tune up data sets

First add some colors to the resource colors.xml file in order to make banana look a little bit more like banana and yogurt like yogurt.

<color name="banana">#ffe100</color>
<color name="yogurt">#0085c7</color>

We’ll configure each of the LineDataSet object the same way, but with different color. Check out method below with the comments:

private fun configureSetLayout(set: LineDataSet, color: Int) {

    set.color = color                         // color of the line
    set.setDrawFilled(true)                   // fill the space between line and chart bottom
    set.fillColor = color                     // color of the fill
    set.setDrawCircles(false)                 // disable drawing circles over each Entry point
    set.mode = LineDataSet.Mode.CUBIC_BEZIER  // round the line
    set.fillAlpha = 50                        // make fill transparent with alpha (0-255)


Now apply configuration to each dataset:

val bananaColor = resources.getColor(R.color.banana, null)
val yogurtColor = resources.getColor(R.color.yogurt, null)

configureSetLayout(bananaDataSet, bananaColor)
configureSetLayout(yogurtDataSet, yogurtColor)
Tune up chart

You may configure chart behaviour in many ways. Default setting allows the user to scale the chart with pinching and scroll it. Since our dataset contains ~700 records let’s leave the ability to scale the chart along the axis X and only block the ability to scale it along axis Y. Also remove description from right bottom corner and highlighting values by tapping. Like that:

lineChart.description.isEnabled = false

lineChart.isHighlightPerTapEnabled = false
lineChart.isHighlightPerDragEnabled = false
lineChart.isScaleYEnabled = false

Works more intuitive already. Now notice that description above top X axis are float values. They doesn’t say much unfortunately. It would be better if they mark year’s change every 52 weeks! To achieve this use IAxisValueFormatter. It looks like this:

inner class MyAxisFormatter : IAxisValueFormatter {
    override fun getFormattedValue(value: Float, axis: AxisBase?): String {
        return if (value.toInt() % 52 == 0) "${startingYear + value.toInt() / 52}"
        else ""

Means that it will display value only if is divisible by 52. And then maps the value to corresponding year (with starting year set to 2004). We need also proper granularity so there won’t be any grid between years.

lineChart.xAxis.valueFormatter = MyAxisFormatter()
lineChart.xAxis.granularity = 52f

Also who needs Y axis on both sides? Disable one of them:

 lineChart.axisRight.isEnabled = false

Boom! That’s it! Looks nice and presenting the data clearly. Pinch to zoom, swipe right and left to get through all these years and finally check when frozen yogurt beats banana bread in Google searches!
chart two
Oh, looks like every year around summer! Who would know.


Wiki & Issues