MPAndroidChart icon indicating copy to clipboard operation
MPAndroidChart copied to clipboard

Issue with setVisibleXRangeMaximum and setVisibleXRangeMinimum in MPAndroidChart with RecyclerView — Only 6 X-Axis Labels Displaying

Open riyapateluex opened this issue 11 months ago • 0 comments

Hello, I'm using MPAndroidChart with a RecyclerView to display a dynamic graph. I'm trying to control the number of visible X-axis labels by using the setVisibleXRangeMaximum and setVisibleXRangeMinimum methods, but I’m encountering an issue where only 6 X-axis labels are showing up, regardless of the range settings.

Here’s what I’ve tried so far:

I have a dataset with more than 6 entries. I have set both setVisibleXRangeMaximum and setVisibleXRangeMinimum to larger values, expecting more X-axis labels to show up. I've ensured that the chart is large enough to accommodate the labels. However, despite setting the visible range, only 6 labels are being displayed on the X-axis. Here’s the relevant part of the code:

fun setLineChart( chart: LineChart, values: java.util.ArrayList<GraphData>, type: Int ) { val yVals = java.util.ArrayList<Entry>() val yValsWithoutGaps = java.util.ArrayList<Entry>() if (values.size > 0) { for (i in values.indices) { //if(values.get(i).getyValue()>0)

            if (values[i].yAxisVal1.toFloat() > 0F) {
                yVals.add(Entry(i.toFloat(), values[i].yAxisVal1.toFloat()))
                yValsWithoutGaps.add(Entry(i.toFloat(), values[i].yAxisVal1.toFloat()))
            } else {
                yVals.add(Entry(i.toFloat(), 0f))
            }
        }
    }


    val set1 = LineDataSet(yValsWithoutGaps, "")
    chart.description.isEnabled = false
    chart.setPinchZoom(false)
    chart.isDoubleTapToZoomEnabled = false
    chart.setDrawGridBackground(false)
    chart.legend.isEnabled = false

    set1.lineWidth = 3f
    set1.circleRadius = 5f
    set1.label = "Jun"
    set1.mode = LineDataSet.Mode.CUBIC_BEZIER
    set1.circleHoleRadius = 0f
    set1.color = Color.parseColor("#E6A3FD")
    set1.setCircleColor(Color.parseColor("#1A2857"))
    set1.setDrawCircleHole(false)
    set1.highLightColor = Color.parseColor("#E6A3FD")
    set1.setDrawValues(false)
    set1.setDrawHighlightIndicators(false)

    val set2 = LineDataSet(yVals, "")
    chart.description.isEnabled = false
    chart.setPinchZoom(false)
    chart.isDoubleTapToZoomEnabled = false
    chart.setDrawGridBackground(false)
    chart.legend.isEnabled = false

    set2.lineWidth = 3f
    set2.circleRadius = 0f

// set1.label = "Jun" set2.mode = LineDataSet.Mode.CUBIC_BEZIER set2.circleHoleRadius = 0f set2.color = Color.parseColor("#00FFFFFF") set2.setCircleColor(Color.parseColor("#00FFFFFF")) set2.highLightColor = Color.parseColor("#00FFFFFF") set2.setDrawValues(false) set2.setDrawCircles(false) set2.setDrawHighlightIndicators(false)

    val lineData = LineData(set2, set1)
    chart.data = lineData
    chart.invalidate()
    (lineData.getDataSetByIndex(0) as LineDataSet).circleHoleColor = Color.parseColor("#1A2857")
    chart.description.isEnabled = false
    chart.setDrawGridBackground(false)
    chart.setClipValuesToContent(false)
    chart.isHighlightPerTapEnabled = true
    chart.setDrawMarkers(true)
    

    val mv = XYMarkerView(context, DateAxisValueFormatter(values, type = type))
    mv.chartView = chart // For bounds control
    chart.marker = mv //

    chart.xAxis.granularity = 1f
    chart.xAxis.isGranularityEnabled = true
    chart.xAxis.labelRotationAngle = 0f
    chart.xAxis.axisMinimum = 0f
    chart.xAxis.axisMaximum = values.size.toFloat()

    chart.xAxis.setDrawGridLines(false)
    chart.xAxis.setDrawAxisLine(true)
    chart.xAxis.valueFormatter = DateAxisValueFormatter(values, type = type)
    chart.xAxis.isEnabled = true
    chart.xAxis.textSize = 12f
    chart.xAxis.spaceMin = 1f
    chart.xAxis.spaceMax = 1f

    chart.xAxis.textColor = Color.parseColor("#484848")
    chart.xAxis.position = XAxis.XAxisPosition.BOTTOM
    chart.setXAxisRenderer(
        CustomXAxisRenderer(
            chart.viewPortHandler,
            chart.xAxis,
            chart.getTransformer(YAxis.AxisDependency.LEFT)
        )
    )

    setYAxisLableStyle(chart.axisLeft, chart.axisRight)
    chart.isDoubleTapToZoomEnabled = false
    chart.minOffset = 0f
    chart.setExtraOffsets(0f, 10f, 20f, 30f)
    chart.contentRect[0f, 0f, 0f] = chart.height.toFloat()
    chart.setTouchEnabled(true)
    chart.isDragEnabled = true
    chart.setScaleEnabled(false)
    chart.isClickable = true
    if (values.size > 6) {
        chart.setVisibleXRangeMaximum(7f)
        chart.setVisibleXRangeMinimum(7f)
    } else {
        chart.setVisibleXRangeMaximum(values.size.toFloat())
        chart.setVisibleXRangeMinimum(values.size.toFloat())
    }


    if (type != 2) {
        if (values.size > 7) {
            chart.moveViewToX((values.size - 7).toFloat());
        } else {
            chart.moveViewToX(0f);
        }
    } else {
        chart.moveViewToX(0f);
    }
    chart.invalidate()

}


fun setYAxisLableStyle(leftYAxis: YAxis, rightYAxis: YAxis) {

// Log.e("Max",maxValue.toString()) leftYAxis.axisMinimum = 0f // leftYAxis.axisMaximum=maxValue // leftYAxis.setLabelCount(5) leftYAxis.removeAllLimitLines() //leftYAxis.setDrawLabels(true) //leftYAxis.setDrawAxisLine(true) leftYAxis.textSize = 12f // // leftYAxis.granularity=2f

    //leftYAxis.granularity = maxOf(maxValue / 4, 1f)
    leftYAxis.setDrawGridLines(false)
    leftYAxis.setDrawZeroLine(false)
    //leftYAxis.zeroLineWidth=3f

    rightYAxis.isEnabled = false
}

class DateAxisValueFormatter(private val values: ArrayList<GraphData>, val type: Int) : ValueFormatter() { var outputFormatType = "dd\nMMM" var inputFormatType = "yyyy-MM-dd"

override fun getFormattedValue(value: Float): String {
    return try {
        if (type == 1) {
            inputFormatType = Constants.DATE_TIME_FORMAT
            outputFormatType = "hh:mma";
        }
        if (type == 2) {
            outputFormatType = "EEE";
        }
        val inputFormat = SimpleDateFormat(inputFormatType, Locale.getDefault())
        val outputFormat = SimpleDateFormat(outputFormatType, Locale.getDefault())
        val index = value.toInt()
        if (index in values.indices) {
            val dateString = values[index].xAxisVal // Assuming GraphData has xAxixVal as a date string
            val date = inputFormat.parse(dateString)
            outputFormat.format(date) // Format date to "06 Nov"
        } else {
            value.toString() // Fallback to the raw value if out of bounds
        }
    } catch (e: Exception) {
        e.printStackTrace()
        value.toString() // Fallback in case of parsing error
    }
}

override fun getAxisLabel(value: Float, axis: AxisBase?): String {
    return try {
        if (type == 1) {
            inputFormatType = Constants.DATE_TIME_FORMAT
            outputFormatType = "hh:mm\na";
        }
        if (type == 2) {
            outputFormatType = "EEE\n ";
        }
        val inputFormat = SimpleDateFormat(inputFormatType, Locale.getDefault())
        val outputFormat = SimpleDateFormat(outputFormatType, Locale.getDefault())
        val index = value.toInt()
        if (index in values.indices) {
            val dateString = values[index].xAxisVal // Assuming GraphData has xAxixVal as a date string
            val date = inputFormat.parse(dateString)
            outputFormat.format(date) // Format date to "06 Nov"
        } else {
            "" // Fallback to the raw value if out of bounds
        }
    } catch (e: Exception) {
        e.printStackTrace()
        value.toString() // Fallback in case of parsing error
    }
}

}

@SuppressLint("ViewConstructor") class XYMarkerView(context: Context?, private val xAxisValueFormatter: IAxisValueFormatter) : MarkerView(context, R.layout.custom_marker_view) { private val tvContent: TextView = findViewById<TextView>(R.id.marker_text) private val rvRoot: RelativeLayout = findViewById<RelativeLayout>(R.id.rlMarkerRoot)

private val format: DecimalFormat = DecimalFormat("###.0")

// runs every time the MarkerView is redrawn, can be used to update the
// content (user-interface)
override fun refreshContent(e: Entry, highlight: Highlight) {
    tvContent.text = java.lang.String.format(
        format.format(e.y.toInt())
    )
    tvContent.text = abs(e.y).toInt().toString()
    if (abs(e.y).toInt() > 0) {
        rvRoot.visibility = VISIBLE
    } else {
        rvRoot.visibility = GONE
    }
    super.refreshContent(e, highlight)
}

override fun getOffset(): MPPointF {
    return MPPointF(-(width / 2).toFloat(), -height.toFloat())
}

}

class CustomXAxisRenderer( viewPortHandler: ViewPortHandler?, xAxis: XAxis?, trans: Transformer? ) : XAxisRenderer(viewPortHandler, xAxis, trans) {

override fun drawLabel(
    c: Canvas,
    formattedLabel: String,
    x: Float,
    y: Float,
    anchor: MPPointF,
    angleDegrees: Float
) {
    // Split the formatted label into multiple lines
    val lines = formattedLabel.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()

    // Get the height of each line
    val lineHeight = mAxisLabelPaint.textSize

    // Calculate the vertical position for each line
    val totalHeight = (lineHeight * lines.size) // Total height of the text
    val startY = y - totalHeight / 2 + 35 // Center vertically

    // Draw each line with adjusted vertical position
    for (i in lines.indices) {
        // Calculate the vertical position for each line
        val lineY = startY + i * lineHeight
        Utils.drawXAxisValue(
            c,
            lines[i],  // The text for the current line
            x,         // X position is the same for all lines (centered)
            lineY,     // Adjusted vertical position
            mAxisLabelPaint,
            anchor,
            angleDegrees
        )
    }
}

}

What I expected: I want the chart to show more than 6 X-axis labels. Specifically, I want it to show 7 labels depending on the visible range.

What happens: The chart only shows 6 X-axis labels, regardless of the values set in setVisibleXRangeMaximum() and setVisibleXRangeMinimum().

Additional information: The dataset contains more than 6 data points. I am using RecyclerView to display multiple charts, but this issue occurs even with a single chart. I have tried adjusting the chart's size, but it doesn’t resolve the issue.

What I have tried: Adjusting the visible range using setVisibleXRangeMaximum() and setVisibleXRangeMinimum(). Setting the X-axis label count using setLabelCount(). Calling chart.invalidate() to force a redraw after data changes.

Question: Why does the chart display only 6 X-axis labels, even though I have set the visible range to be larger? Is there something I'm missing when configuring the X-axis with setVisibleXRangeMaximum() and setVisibleXRangeMinimum()? Any help or guidance on how to resolve this issue would be greatly appreciated. Thanks in advance!

riyapateluex avatar Jan 30 '25 05:01 riyapateluex