Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MPAndroid Chart not displaying any labels for xAxis , what is missing?

I'm implementing a feature for displaying Incomes/Expenses for properties & also provided Filter for 1 Month , 3 Months , 6 Months & 12 Months .

So, I have to display Months labels according to filter selected for example if 3 Month filter selected then need to display March , Feb & Jan but what currently labels are not displaying on XAxis.

Here is my code , please rectify any issue:

private void setChart() {

    ArrayList<BarEntry> incomeEntries = getIncomeEntries();
    ArrayList<BarEntry> expenseEntries = getExpenseEntries();

    BarDataSet set1, set2;

    set1 = new BarDataSet(incomeEntries, "Income");
    set1.setColor(Color.rgb(65, 168, 121));
    set1.setValueTextColor(Color.rgb(55, 70, 73));
    set1.setValueTextSize(10f);

    set2 = new BarDataSet(expenseEntries, "Expense");
    set2.setColors(Color.rgb(241, 107, 72));
    set2.setValueTextColor(Color.rgb(55, 70, 73));
    set2.setValueTextSize(10f);

    ArrayList<IBarDataSet> dataSets = new ArrayList<>();
    dataSets.add(set1);
    dataSets.add(set2);

    BarData data = new BarData(dataSets);
    barChart.setData(data);


    barChart.getDescription().setEnabled(false);
    barChart.setDrawBarShadow(false);
    barChart.setDrawValueAboveBar(true);
    barChart.setMaxVisibleValueCount(10);
    barChart.setPinchZoom(false);
    barChart.setDrawGridBackground(false);
    barChart.animateY(1400, Easing.EaseInOutQuad);
    barChart.animateXY(3000, 3000);

    Legend l = barChart.getLegend();
    l.setWordWrapEnabled(true);
    l.setTextSize(14);
    l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
    l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
    l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
    l.setDrawInside(false);
    l.setForm(Legend.LegendForm.CIRCLE);


    XAxis xAxis = barChart.getXAxis();
    xAxis.setGranularity(1f);
    xAxis.setCenterAxisLabels(true);
    xAxis.setDrawGridLines(false);
    xAxis.setLabelRotationAngle(-45);
    xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
    xAxis.setAxisMaximum(data.getXMax() + 0.25f);

    ArrayList<String> formatter = getFormattter();

    Log.d(TAG,"Labels Received :"+formatter.size()); // Printing 3

    barChart.getXAxis().setValueFormatter(new IndexAxisValueFormatter(formatter));

    barChart.getXAxis().setLabelCount(formatter.size(),true);

    Log.d(TAG,"Labels Count :"+xAxis.getLabelCount()); // Printing 3

    YAxis leftAxis = barChart.getAxisLeft();
    leftAxis.removeAllLimitLines();
    leftAxis.setTypeface(Typeface.DEFAULT);
    leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
    leftAxis.setTextColor(Color.BLACK);
    leftAxis.setDrawGridLines(false);
    leftAxis.setAxisMinValue(0f); // this replaces setStartAtZero(true
    barChart.getAxisRight().setEnabled(false);

    float maxValue = 0, minValue = 0;

    for (int i = 0; i < incomeEntries.size(); i++) {

        if (maxValue < incomeEntries.get(i).getY()) {
            maxValue = incomeEntries.get(i).getY();
        }

        if (maxValue < expenseEntries.get(i).getY()) {
            maxValue = expenseEntries.get(i).getY();
        }

    }

    maxValue = maxValue + 100;
    Log.e(TAG, "==================== MAX VALUE = " + maxValue);

    leftAxis.setAxisMaximum(maxValue);
    leftAxis.setAxisMinimum(minValue);

    leftAxis.setAxisMaxValue(maxValue);
    leftAxis.setStartAtZero(true);

    data.setValueFormatter(new LargeValueFormatter());

    //data
    float groupSpace = 0.25f;
    float barSpace = 0.05f; // x2 dataset
    float barWidth = 0.35f; // x2 dataset


    barChart.getBarData().setBarWidth(barWidth);
    barChart.getXAxis().setAxisMinValue(10f);
    barChart.groupBars(10, groupSpace, barSpace);
    barChart.invalidate();

}

private ArrayList<String> getFormattter() {

    Log.e(TAG, "GET FORMATTED VALUE");

    switch (chartType) {

        case AppConstants.CHART_TYPE_1_MONTH:
            monthFormatter();
            return oneMonthLabels;

        case AppConstants.CHART_TYPE_3_MONTH:
            threeMonthFormatter();
            return threeMonthLabels;

        case AppConstants.CHART_TYPE_6_MONTH:
            sixMonthFormatter();
            return sixMonthLabels;

        case AppConstants.CHART_TYPE_12_MONTH:
            yearFormatter();
            return yearLabels;
    }
    return null;
}

private void threeMonthFormatter() {

    Log.e(TAG, "threeMonthFormatter , label list size : " + threeMonthLabels.size());
    if (null != threeMonthLabels) {
        threeMonthLabels.clear();
    }

    Calendar calendar = Calendar.getInstance();
    String month = new SimpleDateFormat("MMM").format(calendar.getTime());
    threeMonthLabels.add(month);

    calendar.add(Calendar.MONTH, -1);
    month = new SimpleDateFormat("MMM").format(calendar.getTime());
    threeMonthLabels.add(month);

    calendar.add(Calendar.MONTH, -1);
    month = new SimpleDateFormat("MMM").format(calendar.getTime());
    threeMonthLabels.add(month);

    for (int i = 0; i < threeMonthLabels.size(); i++) {
        Log.e(TAG, "Label : " + threeMonthLabels.get(i));
    }
}

I have attached screen which is achieved as of now.As you can see as per three month Filter , it's displaying bars as per 3 months but there are no labels even monthFormatter create exactly 3 months labels.

Here is another screenshot to display labels received log from Formatter method.

Log From Formatter method enter image description here

Main Screen enter image description here

like image 799
Deep Shah Avatar asked Mar 24 '19 15:03

Deep Shah


1 Answers

These two lines are causing the issue :

barChart.getXAxis().setAxisMinValue(10f);     
barChart.groupBars(10, groupSpace, barSpace);

you are setting the minimum value of x axis to 10, whereas the labels will begin with index 0, So internally IndexOut of bound exception keeps occurring So,

Change To:

barChart.getXAxis().setAxisMinValue(0f);     // Better remove setAxisMinValue(), as it deprecated
barChart.groupBars(0, groupSpace, barSpace);

If you still want to have 10 as the initial spacing, override IAxisValueFormatter (Not recommended)

barChart.getXAxis().setValueFormatter(new IndexAxisValueFormatter(formatter) {

 @Override
        public String getFormattedValue(float value) {
            int x = (int)value / 10
            if(x > = 0 && x < formatter.size())
               return formatter.get(x);
            else
               return "";
        }
});

As you have fixed group space, bar space and width. you will need to heavily customise for multiple dataset.

However I wouldn't go with your solution for such a dynamic graph,

I have re-written your solution to adapt to changing width. (This are the results)

Github Project Link

Apk Link

6 month 3 month

BarChart barChart;
ArrayList<IBarDataSet> dataSets = new ArrayList<>();
float defaultBarWidth = -1;
List<String> xAxisValues = new ArrayList<>(Arrays.asList("Jan", "Feb", "March", "April", "May", "June","July", "August", "September", "October", "November", "December"));


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    barChart = findViewById(R.id.barchart);
    setChart(3);
    RadioGroup radioGroup = findViewById(R.id.radio_group);
    radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup radioGroup, int switchId) {

            switch (switchId) {
                case R.id.one_month:
                    setChart(1);
                    break;
                case R.id.three_month:
                    setChart(3);
                    break;
                case R.id.six_month:
                    setChart(6);
                    break;
                case R.id.tweleve_month:
                    setChart(12);
                    break;
            }
        }
    });
}


private void setChart(int size) {

    List<BarEntry> incomeEntries = getIncomeEntries(size);
    List<BarEntry> expenseEntries = getExpenseEntries(size);
    dataSets = new ArrayList<>();
    BarDataSet set1, set2;

    set1 = new BarDataSet(incomeEntries, "Income");
    set1.setColor(Color.rgb(65, 168, 121));
    set1.setValueTextColor(Color.rgb(55, 70, 73));
    set1.setValueTextSize(10f);

    set2 = new BarDataSet(expenseEntries, "Expense");
    set2.setColors(Color.rgb(241, 107, 72));
    set2.setValueTextColor(Color.rgb(55, 70, 73));
    set2.setValueTextSize(10f);

    dataSets.add(set1);
    dataSets.add(set2);

    BarData data = new BarData(dataSets);
    barChart.setData(data);
    barChart.getAxisLeft().setAxisMinimum(0);

    barChart.getDescription().setEnabled(false);
    barChart.getAxisRight().setAxisMinimum(0);
    barChart.setDrawBarShadow(false);
    barChart.setDrawValueAboveBar(true);
    barChart.setMaxVisibleValueCount(10);
    barChart.setPinchZoom(false);
    barChart.setDrawGridBackground(false);

    Legend l = barChart.getLegend();
    l.setWordWrapEnabled(true);
    l.setTextSize(14);
    l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
    l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
    l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
    l.setDrawInside(false);
    l.setForm(Legend.LegendForm.CIRCLE);

    XAxis xAxis = barChart.getXAxis();
    xAxis.setGranularity(1f);
    xAxis.setCenterAxisLabels(true);
    xAxis.setDrawGridLines(false);
    xAxis.setLabelRotationAngle(-45);
    xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
    xAxis.setAxisMaximum(getExpenseEntries(size).size());

    barChart.getXAxis().setValueFormatter(new IndexAxisValueFormatter(xAxisValues));

    YAxis leftAxis = barChart.getAxisLeft();
    leftAxis.removeAllLimitLines();
    leftAxis.setTypeface(Typeface.DEFAULT);
    leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
    leftAxis.setTextColor(Color.BLACK);
    leftAxis.setDrawGridLines(false);
    barChart.getAxisRight().setEnabled(false);

    setBarWidth(data, size);
    barChart.invalidate();

}

private void setBarWidth(BarData barData, int size) {
    if (dataSets.size() > 1) {
        float barSpace = 0.02f;
        float groupSpace = 0.3f;
        defaultBarWidth = (1 - groupSpace) / dataSets.size() - barSpace;
        if (defaultBarWidth >= 0) {
            barData.setBarWidth(defaultBarWidth);
        } else {
            Toast.makeText(getApplicationContext(), "Default Barwdith " + defaultBarWidth, Toast.LENGTH_SHORT).show();
        }
        int groupCount = getExpenseEntries(size).size();
        if (groupCount != -1) {
            barChart.getXAxis().setAxisMinimum(0);
            barChart.getXAxis().setAxisMaximum(0 + barChart.getBarData().getGroupWidth(groupSpace, barSpace) * groupCount);
            barChart.getXAxis().setCenterAxisLabels(true);
        } else {
            Toast.makeText(getApplicationContext(), "no of bar groups is " + groupCount, Toast.LENGTH_SHORT).show();
        }

        barChart.groupBars(0, groupSpace, barSpace); // perform the "explicit" grouping
        barChart.invalidate();
    }
}

private List<BarEntry> getExpenseEntries(int size) {
    ArrayList<BarEntry> expenseEntries = new ArrayList<>();

    expenseEntries.add(new BarEntry(1,1710));
    expenseEntries.add(new BarEntry(2,2480));
    expenseEntries.add(new BarEntry(3,242));
    expenseEntries.add(new BarEntry(4,2409));
    expenseEntries.add(new BarEntry(5,8100));
    expenseEntries.add(new BarEntry(6,1200));
    expenseEntries.add(new BarEntry(7,6570));
    expenseEntries.add(new BarEntry(8,5455));
    expenseEntries.add(new BarEntry(9,15000));
    expenseEntries.add(new BarEntry(10,11340));
    expenseEntries.add(new BarEntry(11,9100));
    expenseEntries.add(new BarEntry(12,6300));
    return expenseEntries.subList(0, size);
}

private List<BarEntry> getIncomeEntries(int size) {
    ArrayList<BarEntry> incomeEntries = new ArrayList<>();

    incomeEntries.add(new BarEntry(1, 11300));
    incomeEntries.add(new BarEntry(2, 1390));
    incomeEntries.add(new BarEntry(3, 1190));
    incomeEntries.add(new BarEntry(4, 7200));
    incomeEntries.add(new BarEntry(5, 4790));
    incomeEntries.add(new BarEntry(6, 4500));
    incomeEntries.add(new BarEntry(7, 8000));
    incomeEntries.add(new BarEntry(8, 7034));
    incomeEntries.add(new BarEntry(9, 4307));
    incomeEntries.add(new BarEntry(10, 8762));
    incomeEntries.add(new BarEntry(11, 4355));
    incomeEntries.add(new BarEntry(12, 6000));
    return incomeEntries.subList(0, size);
}

Note that the setBarWidth() function is the most important and plays the role of adjusting the width and size of graph bar.

like image 180
Extremis II Avatar answered Sep 28 '22 18:09

Extremis II