Search code examples
javaandroidmpandroidchart

How to correctly add labels on a barchart in MPAndroidChart


I am using MPAndroidChart and I want to create a barchart. Actually this works fine. But the problem are the labels on the different bars. Somehow they just don't match. Only if I have exactly 3 bars, the labels are being displayed correctly. Here you can see a picture: enter image description here

Here is the Java Android code:

import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;

import com.example.drinkserver.databinding.FragmentTestBinding;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;

import java.util.ArrayList;
import java.util.List;


public class FR_Test extends Fragment {


    public FR_Test() {
        // Required empty public constructor
    }



    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }
    private FragmentTestBinding binding;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        binding = FragmentTestBinding.inflate(inflater, container, false);
        /*
        Create barcharts with MP Android Chart
         */

        //Add data points
        ArrayList<BarEntry> dataVals = new ArrayList<>();
        dataVals.add(new BarEntry(1, 3));
        //dataVals.add(new BarEntry(2, 4));
        //dataVals.add(new BarEntry(3, 5));
        //dataVals.add(new BarEntry(4, 3));


        // Create a BarDataSet with the data
        BarDataSet barDataSet = new BarDataSet(dataVals, "");
        barDataSet.setDrawValues(true); 
        barDataSet.setValueTextColor(Color.BLACK); 

        // Customize the appearance of the bars
        barDataSet.setColors(Color.rgb(0, 155, 0)); // Set bar color

        // Create BarData and add your BarDataSet to it
        BarData barData = new BarData(barDataSet);
        barData.setBarWidth(0.6f);

        // Get the XAxis
        XAxis xAxis = binding.barChartRatings.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setDrawAxisLine(true); 
        xAxis.setDrawGridLines(false); 
        xAxis.setTextSize(10f); 
        xAxis.setTypeface(Typeface.DEFAULT_BOLD); 
        
        // Add labels for the bars
        List<String> barLabels = new ArrayList<>();
        barLabels.add("");
        for (int i = 0; i < dataVals.size(); i++) {
            barLabels.add("Bar " + (i + 1));
        }

        // Convert the list to an array
        final String[] barLabelsA = barLabels.toArray(new String[0]);

        // Set the custom labels for the X-axis
        xAxis.setValueFormatter(new IndexAxisValueFormatter(barLabelsA));


        // Get the YAxis (left axis)
        YAxis leftYAxis = binding.barChartRatings.getAxisLeft();
        leftYAxis.setDrawLabels(true); 
        leftYAxis.setDrawGridLines(true); 
        leftYAxis.setAxisMinimum(0f); 
        leftYAxis.setAxisMaximum(5.5f); 
        leftYAxis.setGranularity(1f);
        // Set the number of labels without forcing them to be integers
        leftYAxis.setLabelCount(6, false); 
        leftYAxis.setTextSize(14f);

        // Create a LimitLine for the upper rim
        LimitLine upperRim = new LimitLine(5.5f, "");
        upperRim.setLineColor(Color.BLACK);
        upperRim.setLineWidth(1f);

        // Add the upper rim to the left YAxis
        leftYAxis.addLimitLine(upperRim);

        // Get the YAxis and hide it
        YAxis rightYAxis = binding.barChartRatings.getAxisRight();
        rightYAxis.setDrawLabels(false);
        rightYAxis.setDrawGridLines(false);

        // Add a continuous upper rim to the plot
        binding.barChartRatings.getAxisRight().setDrawTopYLabelEntry(true);
        binding.barChartRatings.getAxisLeft().setDrawTopYLabelEntry(true);

        // Remove the legend
        binding.barChartRatings.getLegend().setEnabled(false);

        // Hide the description label
        binding.barChartRatings.getDescription().setEnabled(false);

        // Set data for the bar chart
        binding.barChartRatings.setData(barData);


        // Invalidate the chart to refresh its appearance
        binding.barChartRatings.invalidate();


        return binding.getRoot();
    }
}

and here the corresponding XML layout file:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@color/colorGrey"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <com.github.mikephil.charting.charts.BarChart
        android:id="@+id/barChartRatings"
        android:layout_width="220dp"
        android:layout_height="220dp"


        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

The List<String> barLabels = new ArrayList<>(); always has the correct number of bar strings. So when only having one datapoint, it has an empty String "" (such that the Bar labels are not being displayed at position 0) and "Bar1". So it is quite strange, why "Bar1" is repeated 3 times. What makes the problem even more strange, is that when having a different numbeer of bars, the behaviour changes altough barLabels always has the correct number of Strings. Do you know what is causing this problem?


Solution

  • You got two problems. When creating the BarEntry object, you must initialise the X value from 0, not 1. Also, you are making a logic error when adding a space to the barLabels variable, you can add the space as follows.

    dataVals.add(new BarEntry(0, 3)); // Bar 1
    dataVals.add(new BarEntry(1, 4)); // Bar 2
    dataVals.add(new BarEntry(2, 5)); // Bar 3
    dataVals.add(new BarEntry(3, 3)); // Bar 4
    //add more bar if you want
    
    // ...
    
           // Add labels for the bars (change your add space character method)
            List<String> barLabels = new ArrayList<>();
            for (int i = 0; i < dataVals.size(); i++) {
                //ADD SPACE HERE
                barLabels.add("Bar " + (i + 1));
            }
    
            // Convert the list to an array
            final String[] barLabelsA = barLabels.toArray(new String[0]);
    
    // ...
    
    

    To centre the labels exactly according to the bars, you can add the following method to your code: (You added this for yAxis but not for xAxis.)

    xAxis.setGranularity(1f);
    

    It worked when I tried it, I hope it works for you.

    barchart view