1

I am trying to draw a polygon using MPAndroidChart in AndroidStudio in Kotlin for an Android developpment. I am facing a visual rendering problem.

I am drawing 2 different polygons on 2 different charts. The first one is working perfectly but the second one is creating a visual rendering problem and making my application to crash when I try to zoom or do anything in my chart.

The coordinate for the second polygon should be the following:

polygonTopView = Polygon(
   Pair(92.0, 3.0),
   Pair(100.0, 3.0),
   Pair(102.5, 1.5),
   Pair(102.5, -1.5),
   Pair(100.0, -3.0),
   Pair(92.0, -3.0),
   Pair(92.0, 3.0)
)

The result is the following picture below with the second polygon, for which I have only one line and it crashes whenever I touch it

enter image description here

If I just comment the coordinate Pair(100.0, -3.0), I don't have this problem but of course I want to draw my full polygon. Below is the polygon without the coordinate that generates the error:

enter image description here

Finally if the coordinate Pair(100.0, -3.0) is somewhere above or equal to the last one on the X-axis it works. For example if I put Pair(103.0, -3.0), it will works.

Does anyone can help me with this problem ?

I tried many things but I really don't get the problem

There is not much to say about the code because the problem is relative to the coordinates, but here is my function to draw my polygon:

    private fun drawPolygon(view: View, polygonSideView: Polygon, polygonTopView: Polygon){
    
    chartSideView = view.findViewById(R.id.chartSideView)
    chartSideView.setTouchEnabled(true)
    chartSideView.setPinchZoom(true)

    val entriesSideView = mutableListOf<Entry>()
    for (point in polygonSideView.vertices) {
        entriesSideView.add(Entry(point.first.toFloat(), point.second.toFloat()))
    }

    val dataSetSideView = LineDataSet(entriesSideView, "CG limit Side view")
    dataSetSideView.color = ColorTemplate.COLORFUL_COLORS[0]
    dataSetSideView.lineWidth = 1f // set the line width to 2 pixels
    dataSetSideView.fillColor = ColorTemplate.COLORFUL_COLORS[0]
    dataSetSideView.setDrawFilled(true)
    
    val lineDataSetsSideView = mutableListOf<ILineDataSet>()
    lineDataSetsSideView.add(dataSetSideView)

    val lineDataSideView = LineData(lineDataSetsSideView)
    chartSideView.data = lineDataSideView
    chartSideView.description.isEnabled = false
    chartSideView.legend.isEnabled = true
    chartSideView.axisRight.isEnabled = false
    chartSideView.axisLeft.axisMinimum = 1500f
    chartSideView.axisLeft.axisMaximum = 2600f
    //chartSideView.xAxis.labelRotationAngle = -45f
    chartSideView.xAxis.granularity = 1f
    chartSideView.xAxis.isGranularityEnabled = true
    chartSideView.xAxis.axisMinimum = 91f
    chartSideView.xAxis.axisMaximum = 103f


    chartSideView.invalidate()
    // end of sideview



    // chartview 2
    //chartTopView = view?.findViewById(R.id.chartTopView) ?: throw IllegalStateException("View is null")
    chartTopView = view.findViewById(R.id.chartTopView)
    chartTopView.setTouchEnabled(true)
    chartTopView.setPinchZoom(true)

    val entriesTopView = mutableListOf<Entry>()
    for (point in polygonTopView.vertices) {
        entriesTopView.add(Entry(point.first.toFloat(), point.second.toFloat()))
    }
    //entriesTopView.add(Entry(polygonTopView.vertices[0].first.toFloat(), polygonTopView.vertices[0].second.toFloat()))


    val dataSetTopView = LineDataSet(entriesTopView, "CG limit Top view")
    dataSetTopView.color = ColorTemplate.COLORFUL_COLORS[0]
    dataSetTopView.lineWidth = 2f // set the line width to 2 pixels
    dataSetTopView.fillColor = ColorTemplate.COLORFUL_COLORS[0]
    dataSetTopView.setDrawFilled(true)

    val lineDataSetsTopView = mutableListOf<ILineDataSet>()
    lineDataSetsTopView.add(dataSetTopView)

    val lineDataTopView = LineData(lineDataSetsTopView)

    chartTopView.data = lineDataTopView
    chartTopView.description.isEnabled = false
    chartTopView.legend.isEnabled = true
    chartTopView.axisRight.isEnabled = false
    chartTopView.axisLeft.axisMinimum = -4f
    chartTopView.axisLeft.axisMaximum = 4f
    //chartTopView.xAxis.labelRotationAngle = -45f
    chartTopView.xAxis.granularity = 1f
    chartTopView.xAxis.isGranularityEnabled = true
    chartTopView.xAxis.axisMinimum = 91f
    chartTopView.xAxis.axisMaximum = 103f

    chartTopView.invalidate()
}
col625
  • 13
  • 5
  • If the app crashes, please include the complete stack trace from the Logcat in your question. You should also include enough code for someone else to be able to replicate your issue - there is very little anyone can do with the amount of information you've included here. – Tyler V Apr 30 '23 at 22:10
  • @TylerV There is no much to say about my code because the problem is related to the coordinates but I have edited my post to add my function that draw the polygon and I have nothing as crash message, the application just close – col625 Apr 30 '23 at 23:32
  • There is always a crash message if it crashes, look in the Logcat tab in Android Studio (bottom of the screen). I'll see if i can replicate it from what you posted – Tyler V May 01 '23 at 00:24

1 Answers1

0

The issue is that the line chart expects the provided points to be sorted by x-coordinate (increasing). When they are not, there are a number of errors that can occur. There is some background about this requirement in this Github issue and in the docs.

Please be aware that this library does not officially support drawing LineChart data from an Entry list not sorted by the x-position of the entries in ascending manner. Adding entries in an unsorted way may result in correct drawing, but may also lead to unexpected behaviour.

Even in the case that was "working" where you dropped the (100,-3) point, if you zoomed in on the chart and panned around the fill would show up wrong. In this case, when you try to pan or zoom including the (100,-3) point it throws the error below:

Process: com.example.chartdemo, PID: 31183
java.lang.NegativeArraySizeException: -6
    at com.github.mikephil.charting.utils.Transformer.generateTransformedValuesLine(Transformer.java:178)
    at com.github.mikephil.charting.renderer.LineChartRenderer.drawValues(LineChartRenderer.java:549)
    at com.github.mikephil.charting.charts.BarLineChartBase.onDraw(BarLineChartBase.java:278)
    at android.view.View.draw(View.java:22644)

One solution is to split the polygon edges into multiple separate lines, one which goes "over the top" of the polygon and one which forms the base. Both of these should be non-decreasing in X.

val polyUpper = listOf(
    Pair(92.0, -3.0),
    Pair(92.0, 3.0),
    Pair(100.0, 3.0),
    Pair(102.5, 1.5),
    Pair(102.5, -1.5)
)

val polyLower = listOf(
    Pair(92.0, -3.0),
    Pair(100.0, -3.0),
    Pair(102.5, -1.5)
)

val entriesUpper = polyUpper.map { Entry(it.first.toFloat(), it.second.toFloat()) }
val entriesLower = polyLower.map { Entry(it.first.toFloat(), it.second.toFloat()) }

val dataSetUpper = LineDataSet(entriesUpper, "CG limit Side view")
dataSetUpper.color = ColorTemplate.COLORFUL_COLORS[0]
dataSetUpper.lineWidth = 1f // set the line width to 2 pixels
dataSetUpper.fillColor = ColorTemplate.COLORFUL_COLORS[0]
dataSetUpper.setDrawFilled(true)

val dataSetLower = LineDataSet(entriesLower, "")
dataSetLower.color = ColorTemplate.COLORFUL_COLORS[0]
dataSetLower.lineWidth = 1f // set the line width to 2 pixels
dataSetLower.fillColor = ColorTemplate.COLORFUL_COLORS[0]
dataSetLower.setDrawFilled(true)

val lineDataSideView = LineData(listOf(dataSetUpper, dataSetLower))

The result: polygon demo

Notes

  • You'll probably need to fix the legend since it shows two entries now since there are two lines
  • If your polygon does not sit symmetrically around the y = 0 line you will need to change how you do the fill. It only fills from the line to the y = 0 level, so if the polygon is all above y = 0 you'll want to set the fill for the "lower" line to Color.WHITE instead with an alpha of 255. This is described here
  • Applying this approach more generally would require knowing some things about your polygons (e.g. are they always convex?). If you don't care as much about the fill, you could just draw each line segment as its own LineDataSet, which would work with any complexity of polygon.
  • If you want to draw complex filled polygons, MPAndroidChart is probably not the best choice. You might want to look into just drawing it on a canvas manually.
Tyler V
  • 9,694
  • 3
  • 26
  • 52
  • Thank you very much ! That explain the problem and why it is related to my datas I will try some of the solution you suggest but from my point of view the issue can be considered as closed – col625 May 01 '23 at 14:17