Custom bar chart for android – tutorial

author avatar

Đorđe Stanišić

September 5, 2022

5 min read

In our Skenit app, used for gym management, we wanted to improve user experience by providing them with statistics that show monthly users per gym, the number of users per training type, financial reports for every month, etc. By doing this we would give our users more insight into the gyms they own, their employees, their business growth, and income.

One of the best ways to represent this data to users is through data visualization. Data visualization offers an easy approach to observing and analyzing trends, outliers, and patterns in data by utilizing visual components like charts, graphs, and maps. Data visualization is essential to analyze massive amounts of information and allow you to make data-driven decisions that can improve your business even more. 

Using MPAndroidChart for data visualization

For this task, I have chosen MPAndroidChart which allows us to create different kinds of data visualization. This library is easy to use and charts are highly customizable, the library is well documented and there is a vast amount of implementation examples online.

In this tutorial, we will give an example of a bar chart that shows income per month, as shown on the image.

Preparation

1. Import this library into build.gradle (Module: app):

dependencies {
     implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
 }

2. Import this library into build.gradle (Project: …):

repositories {
    maven { url 'https://jitpack.io' }
}

3. Go to fragment.xml and declare the BarChart view in the layout:


<com.github.mikephil.charting.charts.BarChart
       android:id="@+id/bar_chart
       android:layout_height="150dp"/>

Be sure to add layout_height or you won’t be able to see anything because the chart will be collapsed.

The style/look of the chart has to be made programmatically, inside of a fragment or activity.

Stylize bar chart

1. Make a function with a parameter of BarChart type. This method will determine the look of a chart and will initialize it. You can make multiple functions for different styles.

private fun initializeBarChart(barChart: BarChart) {}

2. Stylize the chart by adding different parameters. I recommend checking out the documentation for the list of all the parameters you can adjust. You can experiment until you get the look you want. Feel free to copy these parameters if you want the same look we have:

private fun initializeBarChart(barChart: BarChart) {
   barChart.description.isEnabled = false
   barChart.axisRight.isEnabled = false
   barChart.animateY(1500)
   barChart.legend.isEnabled = false
   barChart.setTouchEnabled(false)
   barChart.xAxis.setDrawGridLines(false)
   barChart.xAxis.position = XAxis.XAxisPosition.BOTTOM
   barChart.xAxis.setDrawLabels(true)
   barChart.xAxis.granularity = 1F
   barChart.xAxis.valueFormatter = AxisFormatter()
   barChart.axisLeft.isGranularityEnabled = true
   barChart.axisLeft.axisMinimum = 0F
   barChart.axisLeft.valueFormatter = LargeValueFormatter()
}

Don’t worry if AxisFormatter() and LargeValueFormatter() are red, we will solve that next.

Formatters

1. X and Y-axis inputs can only be numbers, we cannot make January an input for the X-axis. That is why we have to make an axis value formatter, and add it as a value formatter for the X-axis (barChart.xAxis.valueFormatter = AxisFormatter()). Axis formatter will change the number on the X-axis (which represents one X-axis entry) to the corresponding name of the month.

Make an inner class that extends IndexAxisValueFormatter(), and override function getAxisLabel(). This function will take input from X-axis (value) in form of a number, and get a string for it from the list of strings (monthLabels). Variable monthLabels will be populated with month names when we start iterating through our data, later in this article.

val monthLabels: ArrayList = ArrayList()

inner class AxisFormatter : IndexAxisValueFormatter() {
    override fun getAxisLabel(value: Float, axis: AxisBase?): String {
        val indexOfBar = value.toInt()
        return if (indexOfBar - 1 < monthLabels.size) {
            monthLabels[index - 1]
        } else {
            ""
        }
    }
}

2. We also want to show the value of each bar on top of it. Make another inner class that extends ValueFormatter(), that will take the value of each bar and create a string that can be shown on top of every bar:

inner class IntValueFormatter : ValueFormatter() {
    override fun getFormattedValue(value: Float): String {
        return value.toInt().toString()
    }
}

Create bar chart

1. Create a function that will take data and show it in form of a bar chart. This function will take a map of String and Int, where String stands for the name of the month and Int for the income amount for that month:

private fun createIncomePerMonthChart (Map) {}

2. Declare two variables. The first variable (barChartValues) will be the list of all the bar chart entries (containing X and Y-axis values) and the second one (xAxisBarEntry) will just increment after each entry creating X-axis entry values for the first variable (barChartValues).

Function forEach will iterate through data and for each entry it will add a new BarEntry to the list, using data of each month as Y-axis values, and xAxisBarEntry value for X-axis values. It will also store the names of months in the variable monthLabels, and the AxisFormatter that we made earlier will use that variable/list to swap X-axis values with the corresponding month names.

private fun createIncomePerMonthChart (incomePerMonth:  Map) {
    val barChartValues: ArrayList = ArrayList()
    var xAxisBarEntry = 0F

        incomePerMonth.forEach { month ->
                yAxisValues.add(BarEntry(xAxisBarEntry, month.value.toFloat()))
                monthLabels.add(month)
                xAxisBarEntry++
            }
}

3. Now we will pass the data to the BarDataSet (set of bars in this chart). We also have to choose a color for the bars, and in this case, we used the same color for all the bars. We also added value formatter (IntValueFormatter()) to the barDataSet so that we can see numbers on top of the bars:

private fun createChart (incomePerMonth:  Map) {
…
val barDataSet = BarDataSet(barChartValues, "")
barDataSet.color = getColor(requireContext(), R.color.orange)
barDataSet.valueFormatter = IntValueFormatter()

val data = BarData(barDataSet)
binding.bcIncomePerMonthsEUR.data = data
binding.bcIncomePerMonthsEUR.invalidate()
}

4. Initialize the bar chart in onViewCreated method. This will assign the defined style to the view from the layout:

initializeBarChart(binding.barChart)

5. Finally, create the bar chart by providing data to the createChart method. This method should be also called in onViewCreated method below/after the initializeBarChart method:

createChart(data)

Care to share?


Front-end vs. Back-end: What is the difference

All

Front-end vs. Back-end: What is the difference

Terms like front-end and back-end development may be confusing to someone who is new to the world of coding and software engineering. Let’s clear up some of the ambiguity around some of these technical phrases. We’ll explain the differences between the front-end and back-end. Today, we’re addressing the following issues and demystifying the distinctions between […]

Mobile App vs. Website: What is best for your business

Business

Mobile App vs. Website: What is best for your business

As a CEO or business owner, you have probably considered how to attract customers and what strategy to use, such as whether to develop a website or mobile application. There is no definitive answer because the alternative you pick will rely on your business plans, your resources, and any properties you might require. We would […]