androidandroid-studiokotlinlabelmpandroidchart

How to change xaxis label start position MPAndroidChart


Im having trouble with clipping x axis labels. The problem can be seen in the pictureenter image description here

What I would like to change is that instead of the labels ending at that place, that they instead start at that place so the whole text can be seen. code that im using:

barChart.axisLeft.isEnabled = false
    barChart.setTouchEnabled(false)
    barChart.isDragEnabled = false
    barChart.description = null
    barChart.xAxis.setDrawGridLines(false)
    barChart.xAxis.setCenterAxisLabels(true)
    barChart.xAxis.valueFormatter = IndexAxisValueFormatter(nameArray)
    barChart.xAxis.position = XAxis.XAxisPosition.BOTTOM_INSIDE
    barChart.xAxis.textColor = Color.WHITE
    barChart.axisRight.textColor = Color.WHITE
    barChart.legend.textColor = Color.WHITE

Thanks in advance :)


Solution

  • The axis labels on a bar chart can be difficult to position properly, so for something like this it's often easier to use a custom renderer for the dataset values instead. To do this, you can create a custom renderer that reads the label you want from the BarEntry data field and draws it where you want relative to the bar position.

    The renderer below is a simplified copy of the base HorizontalBarChartRenderer that overrides the drawValues method.

    class MyRenderer(
        chart: HorizontalBarChart
    ) : HorizontalBarChartRenderer(chart, chart.animator, chart.viewPortHandler) {
    
        override fun drawValues(c: Canvas?) {
            val dataSets = mChart.barData.dataSets
            val valueOffsetPlus = Utils.convertDpToPixel(5f)
    
            dataSets.forEachIndexed { i, ds ->
    
                applyValueTextStyle(ds)
                val buffer = mBarBuffers[i]
    
                val maxJ = ceil(buffer.buffer.size*mAnimator.phaseX).toInt()
                for(j in 0 until maxJ step 4) {
    
                    if( !mViewPortHandler.isInBoundsTop(buffer.buffer[j+1]))
                        break
    
                    if( !mViewPortHandler.isInBoundsX(buffer.buffer[j]))
                        continue
    
                    if( !mViewPortHandler.isInBoundsBottom(buffer.buffer[j+1]))
                        continue
    
                    // Read the label from the BarEntry data field
                    val entry = ds.getEntryForIndex(j / 4)
                    val formattedValue = (entry.data as? String).orEmpty()
    
                    // Modify the x, y position here to control where the
                    // text is. The "buffer" array gives the positions of
                    // the current bar (in pixels from top left corner)
                    drawValue(c,
                        formattedValue,
                        buffer.buffer[j] + valueOffsetPlus,
                        buffer.buffer[j+1] + ds.valueTextSize,
                        ds.getValueTextColor(j / 2));
                }
    
            }
        }
    }
    

    Once you have defined a custom renderer, you add it to the chart with your list of labels, and turn off the regular axis labels, like this:

    // set the custom renderer for the chart
    barChart.renderer = MyRenderer(barChart)
    
    // turn off labels on x axis
    barChart.xAxis.setDrawLabels(false)
    

    For this example, I'm using the following data set

    val entries1 = listOf(BarEntry(0f,3f,"Lorem"))
    val dataset1 = BarDataSet(entries1, "Foo").apply { color = Color.GREEN }
    
    val entries2 = listOf(
        BarEntry(1f,4f,"Ipsum"), 
        BarEntry(2f,5f,"Dolorum")
    )
    val dataset2 = BarDataSet(entries2, "Bar").apply { color = Color.LTGRAY }
    
    val entries3 = listOf(BarEntry(3f,6f,"Pescotum"))
    val dataset3 = BarDataSet(entries3, "Baz").apply { color = Color.CYAN }
    
    val sets = listOf(dataset1, dataset2, dataset3)
    sets.forEach { it.valueTextSize = 12f }
    
    barChart.data  = BarData(sets)
    

    Which gives: bar chart demo

    You can also check out this solution for a version (in Java) that draws the labels outside the bars.