MPAndroidChart x axis - android

I try to display some charts in my android app. I use MPAndroidChart library. But somehow my chart is always compress on the x-axis. The value seems to have all the x value 0.
In the data set this is not the case. I can not figure out what I am doing wrong.
val chart = binding.statsGraph
chart.description.isEnabled = false
chart.setDrawGridBackground(false)
chart.setDrawBarShadow(false)
chart.isHighlightFullBarEnabled = false
chart.setBackgroundColor(Color.WHITE)
chart.setDrawGridBackground(false)
chart.setDrawBarShadow(false)
chart.setHighlightFullBarEnabled(false)
// draw bars behind lines
chart.setDrawOrder(
arrayOf(
CombinedChart.DrawOrder.BAR,
CombinedChart.DrawOrder.BUBBLE,
CombinedChart.DrawOrder.CANDLE,
CombinedChart.DrawOrder.LINE,
CombinedChart.DrawOrder.SCATTER
)
)
val legend = chart.getLegend()
legend.isWordWrapEnabled = true
legend.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER
legend.orientation = Legend.LegendOrientation.HORIZONTAL
legend.setDrawInside(false)
val rightAxis = chart.getAxisRight()
rightAxis.setDrawGridLines(false)
rightAxis.axisMinimum = 0f // this replaces setStartAtZero(true)
val leftAxis = chart.getAxisLeft()
leftAxis.setDrawGridLines(false)
leftAxis.axisMinimum = 0f // this replaces setStartAtZero(true)
val xAxis = chart.getXAxis()
xAxis.position = XAxis.XAxisPosition.BOTH_SIDED
xAxis.axisMinimum = 0f
xAxis.granularity = 1f
class MyValueFormatter : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return value.toInt().toString()
}
}
xAxis.valueFormatter = MyValueFormatter()
val data = CombinedData()
data.setData(test())
xAxis.axisMaximum = data.xMax + 0.25f
chart.setData(data)
chart.invalidate()

You have to make sure that your layout and its parent layout has a "match_parent" width.

Related

I have a line chart that I want to use to show temperature, but I want to show icons and time in x axis

what I want to achieve
what I have
I want to show icons on the xAxis above time but line chart takes icon and places them on the value where temperature is shown. I have searched a lot but could not find the answer. Any help would be appreciated. I have tried a lot of things but all in vein.
private fun setTempChart(hour: ArrayList<Hour>, id: String) {
val entries: MutableList<Entry> = ArrayList()
for (i in hour.indices) {
val code = hour[i].condition.code
val icon =
if (hour[i].is_day == 1) requireActivity().setIconDay(code) else requireActivity().setIconNight(
code
)
entries.add(Entry(i.toFloat(), sharedPreference.temp?.let {
hour[i].temp_c.setCurrentTemperature(
it
).toFloat()
}!!))
}
val dataSet = LineDataSet(entries, "")
dataSet.apply {
lineWidth = 0f
setDrawCircles(false)
setDrawCircleHole(false)
isHighlightEnabled = false
valueTextColor = Color.WHITE
setColors(Color.WHITE)
valueTextSize = 12f
mode = LineDataSet.Mode.CUBIC_BEZIER
setDrawFilled(true)
fillColor = Color.WHITE
valueTypeface = typeface
isDrawIconsEnabled
setDrawIcons(true)
valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return String.format(Locale.getDefault(), "%.0f", value)
}
}
}
val lineData = LineData(dataSet)
chart.apply {
description.isEnabled = false
axisLeft.setDrawLabels(false)
axisRight.setDrawLabels(false)
legend.isEnabled = false
axisLeft.setDrawGridLines(false)
axisRight.setDrawGridLines(false)
axisLeft.setDrawAxisLine(false)
axisRight.setDrawAxisLine(false)
setScaleEnabled(false)
data = lineData
setVisibleXRange(8f, 8f)
animateY(1000)
xAxis.apply {
setDrawAxisLine(false)
textColor = Color.WHITE
setDrawGridLines(false)
setDrawLabels(true)
position = XAxis.XAxisPosition.BOTTOM
textSize = 12f
valueFormatter = MyAxisFormatter(hour, id)
isGranularityEnabled = true
granularity = 1f
labelCount = entries.size
}
}
}
I am using MPAndroidChart library
There isn't a nice built-in way to draw icons like that, but you can do it by making a custom extension of the LineChartRenderer and overriding drawExtras. Then you can get your icons from R.drawable.X and draw them on the canvas wherever you want. There is some work to figure out where to put them to line up with the data points, but you can copy the logic from drawCircles to find that.
Example Custom Renderer
inner class MyRenderer(private val context: Context,
private val iconY: Float,
private val iconSizeDp: Float,
chart: LineDataProvider,
animator: ChartAnimator,
viewPortHandler: ViewPortHandler)
: LineChartRenderer(chart, animator, viewPortHandler) {
private var buffer: FloatArray = listOf(0f,0f).toFloatArray()
override fun drawExtras(c: Canvas) {
super.drawExtras(c)
val iconSizePx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
iconSizeDp,
resources.displayMetrics
)
// get the icons you want to draw
val cloudy = ContextCompat.getDrawable(context, R.drawable.cloudy)
val sunny = ContextCompat.getDrawable(context, R.drawable.sunny)
if( cloudy == null || sunny == null ) {
throw RuntimeException("Missing drawables")
}
// Determine icon width in pixels
val w = iconSizePx
val h = iconSizePx
val dataSets = mChart.lineData.dataSets
val phaseY = mAnimator.phaseY
for(dataSet in dataSets) {
mXBounds.set(mChart, dataSet)
val boundsRange = mXBounds.range + mXBounds.min
val transformer = mChart.getTransformer(dataSet.axisDependency)
for(j in mXBounds.min .. boundsRange) {
val e = dataSet.getEntryForIndex(j) ?: break
buffer[0] = e.x
buffer[1] = iconY * phaseY
transformer.pointValuesToPixel(buffer)
if( !mViewPortHandler.isInBoundsRight(buffer[0])) {
break
}
if( !mViewPortHandler.isInBoundsLeft(buffer[0]) ||
!mViewPortHandler.isInBoundsY(buffer[1])) {
continue
}
// Draw the icon centered under the data point, but at a fixed
// vertical position. Here the icon "sits on top" of the
// specified iconY value
val left = (buffer[0]-w/2).roundToInt()
val right = (buffer[0]+w/2).roundToInt()
val top = (buffer[1]-h).roundToInt()
val bottom = (buffer[1]).roundToInt()
// Alternately, use this to center the icon at the
// "iconY" value
//val top = (buffer[1]-h/2).roundToInt()
//val bottom = (buffer[1]+h/2).roundToInt()
// Use whatever logic you want to select which icon
// to use at each position
val icon = if( e.y > 68f ) {
sunny
}
else {
cloudy
}
icon.setBounds(left, top, right, bottom)
icon.draw(c)
}
}
}
}
Using the Custom Renderer
val iconY = 41f
val iconSizeDp = 40f
chart.renderer = MyRenderer(this, iconY, iconSizeDp,
chart, chart.animator, chart.viewPortHandler)
(other formatting)
val chart = findViewById<LineChart>(R.id.chart)
chart.axisRight.isEnabled = false
val yAx = chart.axisLeft
yAx.setDrawLabels(false)
yAx.setDrawGridLines(false)
yAx.setDrawAxisLine(false)
yAx.axisMinimum = 40f
yAx.axisMaximum = 80f
val xAx = chart.xAxis
xAx.setDrawLabels(false)
xAx.position = XAxis.XAxisPosition.BOTTOM
xAx.setDrawGridLines(false)
xAx.setDrawAxisLine(false)
xAx.axisMinimum = 0.5f
xAx.axisMaximum = 5.5f
xAx.granularity = 0.5f
val x = listOf(0,1,2,3,4,5,6)
val y = listOf(60,65,66,70,65,50,55)
val e = x.zip(y).map { Entry(it.first.toFloat(), it.second.toFloat())}
val line = LineDataSet(e, "temp")
line.setDrawValues(true)
line.setDrawCircles(false)
line.circleRadius = 20f // makes the text offset up
line.valueTextSize = 20f
line.color = Color.BLACK
line.lineWidth = 2f
line.setDrawFilled(true)
line.fillColor = Color.BLACK
line.fillAlpha = 50
line.mode = LineDataSet.Mode.CUBIC_BEZIER
line.valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return "%.0f F".format(value)
}
}
chart.data = LineData(line)
chart.description.isEnabled = false
chart.legend.isEnabled = false
Gives the desired effect

Create modern multi barch chart using MPAndroidChart in android

I'm creating multi bar chart using MPAndroidChart library for android, but it's not as per our design requirement,
I can able to create like following image using following code
barChart.description.isEnabled = false
barChart.setPinchZoom(false)
barChart.setDrawBarShadow(false)
barChart.setDrawGridBackground(false)
val mv = MyMarkerView(context, R.layout.view_marker)
mv.chartView = barChart
barChart.marker = mv
val l: Legend = barChart.legend
l.isEnabled = false
barChart.setExtraOffsets(5f, 5f, 5f, 15f)
val xAxis: XAxis = barChart.xAxis
xAxis.granularity = 1f
xAxis.setCenterAxisLabels(true)
xAxis.position = XAxis.XAxisPosition.BOTTOM
val leftAxis: YAxis = barChart.axisLeft
leftAxis.valueFormatter = MyYAxisValueFormatter(barChart)
leftAxis.setDrawGridLines(false)
leftAxis.spaceTop = 35f
leftAxis.axisMinimum = 0f
barChart.axisRight.isEnabled = false
barChart.axisLeft.setDrawGridLines(false)
barChart.xAxis.setDrawGridLines(false)
and set data for bar char as per code below
val values1 = ArrayList<BarEntry>()
val values2 = ArrayList<BarEntry>()
for ((index, value) in dataList.withIndex()) {
values1.add(BarEntry((index).toFloat(), value.y1.toFloat()))
values2.add(BarEntry((index).toFloat(), value.y2.toFloat()))
}
Log.d("data", "sales: ${values1.size} / purchase: ${values2.size}")
val set1 = BarDataSet(values1, "Sales")
val set2 = BarDataSet(values2, "Purchase")
set1.color = colorSales
set2.color = colorPurchase
val data = BarData(set1, set2)
data.setValueFormatter(LargeValueFormatter())
data.setDrawValues(false)
barChart.data = data
val months = arrayOf("APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", "JAN", "FEB", "MAR")
barChart.xAxis.valueFormatter = IndexAxisValueFormatter(months)
val xAxis = barChart.xAxis
xAxis.valueFormatter = IndexAxisValueFormatter(months)
barChart.axisLeft.axisMinimum = 0f
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.granularity = 1f
xAxis.setCenterAxisLabels(true)
xAxis.isGranularityEnabled = true
val barSpace = 0.1f
val groupSpace = 0.3f
val groupCount = 12
data.barWidth = 0.2f
barChart.xAxis.axisMinimum = 0f
barChart.xAxis.axisMaximum = 0 + barChart.barData.getGroupWidth(groupSpace, barSpace) * groupCount
barChart.xAxis.xOffset = -10f
barChart.groupBars(0.7f, groupSpace, barSpace) // perform the "explicit" grouping
barChart.invalidate()
output of above code is chart below
but i want graph like below,
please help me on this if anyone has experience with using MPAndroidChart
You need to make xAxis.isGranularityEnabled = false
From the documentation:
* When true, axis labels are controlled by the granularity property.
* When false, axis values could possibly be repeated.
* This could happen if two adjacent axis values are rounded to same
value.
* If using granularity this could be avoided by having
fewer axis values visible

MPAndroidChart plotting incorrect linear graph

Trying to implement mpandroidchart, but the graph is ending up useless because it is plotting the chart incorrectly.
Below is the snippet of how i try to implement.
fun setGraph(cdata : ArrayList<Entry>){
val lineChart: LineChart = bind.lineChartViewPage
lineChart.setExtraOffsets(0f, 40f, 0f, 40f)
lineChart.setDrawBorders(false)
lineChart.setDrawGridBackground(false)
lineChart.legend.isEnabled = false
lineChart.description.isEnabled = false
lineChart.setTouchEnabled(false)
lineChart.isDragEnabled = false
lineChart.setScaleEnabled(false)
lineChart.setPinchZoom(false)
lineChart.isAutoScaleMinMaxEnabled = false
val lds = LineDataSet(cdata, "my data")
lds.mode = LineDataSet.Mode.LINEAR
lds.setDrawCircleHole(false)
lds.setDrawCircles(false)
lds.color = Color.parseColor("#ffffff")
lds.lineWidth = 1.5f
lds.isHighlightEnabled = false
val lineDataSets: ArrayList<ILineDataSet> = ArrayList<ILineDataSet>()
lineDataSets.add(lds)
lds.setDrawValues(false)
val lineData = LineData(lineDataSets)
val ll1 = LimitLine(2.5F)
ll1.lineWidth = 2f
ll1.lineColor = Color.parseColor("#99ce7aff")
val yAxisRight: YAxis = lineChart.axisRight
yAxisRight.textColor = Color.WHITE
yAxisRight.setDrawZeroLine(false)
yAxisRight.setDrawAxisLine(false)
yAxisRight.setCenterAxisLabels(true)
yAxisRight.setDrawTopYLabelEntry(true)
yAxisRight.setDrawGridLines(false)
yAxisRight.setGranularity(1.0f)
yAxisRight.isGranularityEnabled = true
yAxisRight.setLabelCount(6, true)
yAxisRight.removeAllLimitLines()
yAxisRight.addLimitLine(ll1)
yAxisRight.axisMaximum = 3.0f
yAxisRight.axisMinimum = 0.0f
val xAxis: XAxis = lineChart.xAxis
xAxis.isEnabled = false
xAxis.valueFormatter = null
xAxis.setDrawLabels(false)
xAxis.setDrawGridLines(false)
val yAxisLeft: YAxis = lineChart.axisLeft
yAxisLeft.isEnabled = false
yAxisLeft.setDrawLabels(false)
yAxisLeft.setDrawGridLines(false)
// hide legend
val legend: Legend = lineChart.legend
legend.isEnabled = false
lineChart.data = lineData
lineChart.data.notifyDataChanged()
lineChart.notifyDataSetChanged()
lineChart.invalidate()
}
I tried out some combinations and found a different behavior if i comment out below lines :
yAxisRight.axisMaximum = 3.0f
yAxisRight.axisMinimum = 0.0f
Before commenting lines (incorrect plotting with limit line)
After commenting lines (correct plotting and limit line vanished)
Below is the dataset on which the graph is being plotted. here the max value is 0.8f and min value is 0.1f.
private fun fakeData():ArrayList<Entry>{
val al: ArrayList<Entry> = ArrayList()
al.add(Entry(1F, 0.2F))
al.add(Entry(2F, 0.4F))
al.add(Entry(3F, 0.5F))
al.add(Entry(4F, 0.6F))
al.add(Entry(5F, 0.3F))
al.add(Entry(6F, 0.4F))
al.add(Entry(7F, 0.6F))
al.add(Entry(8F, 0.7F))
al.add(Entry(9F, 0.4F))
al.add(Entry(10F, 0.1F))
al.add(Entry(11F, 0.3F))
al.add(Entry(12F, 0.3F))
al.add(Entry(13F, 0.5F))
al.add(Entry(14F, 0.6F))
al.add(Entry(15F, 0.47F))
al.add(Entry(16F, 0.55F))
al.add(Entry(17F, 0.66F))
al.add(Entry(18F, 0.45F))
al.add(Entry(19F, 0.46F))
al.add(Entry(20F, 0.33F))
al.add(Entry(21F, 0.4F))
al.add(Entry(22F, 0.36F))
al.add(Entry(23F, 0.37F))
al.add(Entry(24F, 0.46F))
al.add(Entry(25F, 0.74F))
al.add(Entry(26F, 0.76F))
al.add(Entry(27F, 0.79F))
al.add(Entry(28F, 0.8F))
return al
}
If i dont set min and max values as below; then the limit line won't show up.
yAxisRight.axisMaximum = 3.0f
yAxisRight.axisMinimum = 0.0f
chart version : com.github.PhilJay:MPAndroidChart:v3.1.0
Please let me know if there is something wrong with this implementation or possible ways to correct this.
UPDATE :
Tried multiple dataset and found that defining custom yaxis min and max value is causing the chart to be drawn incorrectly. I cant understand why?
Had the same issue and the fix is pretty easy, but not straightforward, though, you should set the same max and min values for both y-axises:
axisLeft.apply {
axisMinimum = 0.0f
axisMaximum = 3.0f
}
axisRight.apply {
axisMinimum = 0.0f
axisMaximum = 3.0f
}

How to remove stronger line in the middle of graph for android MPAndroidChart

My MPAndroidChart displays a stronger line to represent the middle of the graph. How do I avoid that please?
Here is what I have at the moment:
private fun addChart(totals: Totals) {
chart1.apply {
isDragEnabled = true
isScaleXEnabled = false
isScaleYEnabled = true
axisRight.isEnabled = false
axisLeft.setDrawAxisLine(false)
xAxis.isEnabled = false
legend.isEnabled = false
description.text = ""
setTouchEnabled(false)
}
val y: YAxis = chart1.axisLeft
y.axisMaximum = 800f
y.axisMinimum = 0f
y.labelCount = 5
val yValues = ArrayList<Entry>()
for ((index, i) in totals.features!!.withIndex()) {
yValues.add(Entry(index.toFloat(), i.attributes?.confirmedCovidCases!!.toFloat()))
}
val set1 = LineDataSet(yValues, "Data set 1")
set1.color = resources.getColor(R.color.orange)
set1.setDrawCircles(false)
val dataSets = ArrayList<ILineDataSet>()
dataSets.add(set1)
val data = LineData(dataSets)
chart1.data = data
}
Thank you very much.
I try to recreate your chart but did not have the problem
Try to run it on device, because it might your PC/simulator pixel bleeding

MPChart values overriding in Android

I have a MPChart and I am setting the values like this
lineChart.legend.isEnabled = false
lineChart.description.isEnabled = false
val entryList = arrayListOf<Entry>()
val sortedList = stockGraphResponse?.prices?.sortedWith(compareBy {
it?.date
})
for (i in 0 until sortedList?.size!!) {
val item = Utils.replaceCommaInNumber(sortedList[i]?.price!!).toFloat()
entryList.add(Entry(sortedList[i]?.date?.toFloat()!!, item))
}
val lineDataSet = LineDataSet(entryList,"")
lineDataSet.setDrawCircles(false)
lineDataSet.setDrawFilled(true)
val lineData = LineData(lineDataSet)
lineChart.data = lineData
lineChart.setDrawBorders(true)
val xAxis = lineChart.xAxis
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.setValueFormatter(CustomFormatter())
xAxis.setLabelCount(5,true)
val yAxis = lineChart.axisLeft
val yRight = lineChart.axisRight
yRight.isEnabled = false
lineChart.isAutoScaleMinMaxEnabled = true
lineChart.invalidate()
And the result is this graph
I am setting 5 for label count in xAxis and I am getting 5 labels but then the values are being plotted like that and so they are overlapping. I tried using granularity but still the same. How can I streamline this? Any help would be appreciated. Thanks

Categories

Resources