Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
riyapateluex opened this issue Jan 30, 2025 · 0 comments

Comments

@riyapateluex
Copy link

riyapateluex commented Jan 30, 2025

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,
type: Int
) {
val yVals = java.util.ArrayList()
val yValsWithoutGaps = java.util.ArrayList()
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, 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(R.id.marker_text)
private val rvRoot: RelativeLayout = findViewById(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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant