Search code examples
androidandroid-studiographbar-chartmpandroidchart

How to display available and unavailable slots in a horizontal bar graph in android


I am trying to display the available and unavailable slots on a horizontal bar graph, but not able to find a solution to that. The values coming from server are like this:

start_time - 9.30am
end_time - 11.30am
status - available

start_time - 11.30am
end_time - 12.00pm
status - available

start_time - 12.00pm
end_time - 15.00pm
status - not available

[and so on... till 21.00pm]

So I have to represent the available slots with green color and unavailable slots with grey color on a single horizontal bar. Presently, I am using horizontal bar graph of MP Chart Android but it is not giving me the desired result.

Here is the image of what I want to achieve:

Here is the code I am using:

int StockColors[] = new int[]{Color.parseColor("#24E224"), Color.parseColor("#A9A9A9")};

                    ArrayList<BarEntry> entries = new ArrayList<>();
                    entries.add(new BarEntry(0f, arr));
                    BarDataSet bardataset = new BarDataSet(entries, "");
                    bardataset.setColors(StockColors);
                    bardataset.setDrawValues(false);
                    stockChart.getAxisRight().setCenterAxisLabels(true);
                    BarData data = new BarData(bardataset);
                    data.setBarWidth(5f);

                    Legend legend = stockChart.getLegend();

                    LegendEntry legendentry1 = new LegendEntry();
                    legendentry1.label = "Available Slot";
                    legendentry1.formColor = Color.GREEN;

                    LegendEntry legendentry2 = new LegendEntry();
                    legendentry2.label = "UnAvailable Slot";
                    legendentry2.formColor = Color.GRAY;

                    legend.setCustom(Arrays.asList(legendentry1, legendentry2));

                    stockChart.setExtraBottomOffset(20f);
                    stockChart.getLegend().setXEntrySpace(30f);
                    stockChart.getLegend().setYEntrySpace(20f);
                    stockChart.getAxisRight().setDrawGridLines(false);
                    stockChart.getAxisRight().setDrawAxisLine(false);
                    stockChart.getAxisRight().setGranularity(1f);

                    stockChart.setViewPortOffsets(0f, 0f, 0f, 0f);
                    stockChart.setExtraOffsets(0f, 0f, 0f, 0f);

                    stockChart.getAxisLeft().setEnabled(false); //show y-axis at left
                    stockChart.getAxisRight().setEnabled(true); //hide y-axis at right

                    stockChart.setScaleEnabled(false);
                    stockChart.getAxisRight().setEnabled(true);
                    stockChart.getXAxis().setEnabled(false);
                    stockChart.getXAxis().setDrawAxisLine(false);

                    stockChart.setData(data);
                    stockChart.getAxisRight().setTextColor(Color.WHITE);
                    stockChart.getXAxis().setTextColor(Color.WHITE);
                    stockChart.getLegend().setTextColor(Color.WHITE);

                    stockChart.getDescription().setEnabled(false);
                    stockChart.setFitBars(false);
                    stockChart.setTouchEnabled(true);

                    stockChart.setDrawGridBackground(false);
                    stockChart.setDrawBarShadow(false);
                    stockChart.setDrawValueAboveBar(false);
                    stockChart.invalidate();

                    xvalues = new ArrayList<>();
                    xvalues.add("9.00");
                    xvalues.add("10.00");
                    xvalues.add("11.00");
                    xvalues.add("12.00");
                    xvalues.add("13.00");
                    xvalues.add("14.00");
                    xvalues.add("15.00");
                    xvalues.add("16.00");
                    xvalues.add("17.00");
                    xvalues.add("18.00");
                    xvalues.add("19.00");
                    xvalues.add("20.00");
                    xvalues.add("21.00");

                    stockChart.getAxisRight().setLabelCount(xvalues.size()+3, true); // also if i use entries.size() here, then only few labels are visible
                    stockChart.getAxisRight().setDrawLabels(true);

stockChart.getAxisRight().setValueFormatter(new newBarChartXaxisFormatter());


public class newBarChartXaxisFormatter implements IAxisValueFormatter
    {
        @SuppressLint("StringFormatInvalid")
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            int a = (int) (10f + value); // if i use 9f then it starts with 7
            return String.valueOf(a);
        }
    }

This is the current result with the code above: Image of what i am getting with using the above code


Solution

  • The correct way of achieving the above graph is using Stacked Bar graph and HorizontalBarChart component of MpAndroidChart

    sample output image

    Note: I will be linking the project with the sample output shown in the above diagram. Check the comments section for the link. Run HorizontalStackedBarGraph.kt activity to try the solution. The code written below is commented to give you an idea as to how you can implement it in your project.

    Paste the above code in your activity XML

    <com.github.mikephil.charting.charts.HorizontalBarChart
        android:id="@+id/timetable_barchart"
        android:layout_marginBottom="40dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    

    class HorizontalStackedBarGraph : AppCompatActivity() {
    
    val startTime = 9f
    val EXTRA_GRAPH_SIZE = 3
    // In Horizontal graph Bar width will set your graph height.
    val BAR_WIDTH = 0.3F
    // Calculate the time interval and create an array
    val entries = floatArrayOf(2f, 1f, 3f, 3f, 1f, 2f) 
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_horizontal_stacked_bar_graph)
    
        val barChart = findViewById<BarChart>(R.id.timetable_barchart);
        
        // Add the list of values to a single BarEntry
        val timeTableEntries = BarEntry(0f, entries)
        val set1 = BarDataSet(listOf(timeTableEntries), "TimeTable")
        set1.setColors(intArrayOf(R.color.colorAvailableSlot, R.color.colorUnAvailableSlot), this)
        set1.setDrawValues(false)
        val barData = BarData(set1)
        barData.barWidth = BAR_WIDTH
        barChart.data = barData
        barChart.description.isEnabled = false
        
        val legend1= LegendEntry().apply {
            formColor = ContextCompat.getColor(this@HorizontalStackedBarGraph, R.color.colorAvailableSlot)
            label = "Unavailable Slot"
        }
        
        val legend2= LegendEntry().apply {
            formColor = ContextCompat.getColor(this@HorizontalStackedBarGraph, R.color.colorUnAvailableSlot)
            label = "Available Slot"
        }
    
        val valueFormatterForTime = object : ValueFormatter() {
            override fun getFormattedValue(value: Float): String {
                return getString(R.string.time, (startTime + value).toInt())
            }
        }
    
        //Bar graph customization
        barChart.extraBottomOffset = 20f
        barChart.legend.xEntrySpace = 10f
        barChart.legend.setCustom(arrayListOf(legend1, legend2))
        barChart.axisRight.apply {
            setDrawGridLines(false)
            granularity = 1f
            valueFormatter = valueFormatterForTime
            labelCount = entries.size + EXTRA_GRAPH_SIZE
        }
        barChart.axisLeft.isEnabled = false
        barChart.xAxis.isEnabled = false
        barChart.xAxis.axisMinimum = 0f
        barChart.setDrawGridBackground(false)
        barChart.setDrawBarShadow(false)
        barChart.setDrawValueAboveBar(false)
        barChart.invalidate()
        }
    }