I am using a chart library called MPAndroidChart and it responds to most of my needs. However, I need to customize some parts.
I want to draw some indicator lines for labels on xAxis like this :
As I dug in, I could write a CustomAxisRenderer but it seems I need to copy most of the super class codes.
I want the min value to be drawn exactly on xAxis. This min value could be 0 or any other number as well.
How can this be done? Is it even possible to do it?
Any help or hint would be appreciated.
I solved the first issue:
internal class IndicatorAxisRenderer(
viewPortHandler: ViewPortHandler,
xAxis: XAxis,
trans: Transformer
) : XAxisRenderer(viewPortHandler, xAxis, trans) {
private var indicatorWidth = 1f
private var indicatorHeight = 1f
private fun getXLabelPositions(): FloatArray {
var i = 0
val positions = FloatArray(mXAxis.mEntryCount * 2)
val centeringEnabled = mXAxis.isCenterAxisLabelsEnabled
while (i < positions.size) {
if (centeringEnabled) {
positions[i] = mXAxis.mCenteredEntries[i / 2]
} else {
positions[i] = mXAxis.mEntries[i / 2]
}
positions[i + 1] = 0f
i += 2
}
mTrans.pointValuesToPixel(positions)
return positions
}
override fun renderAxisLine(c: Canvas?) {
super.renderAxisLine(c)
val positions = getXLabelPositions()
var i = 0
while (i < positions.size) {
val x = positions[i]
if (mViewPortHandler.isInBoundsX(x)) {
val y = mViewPortHandler.contentBottom()
c?.drawLine(
x, y,
x, y + indicatorHeight,
mAxisLinePaint
)
}
i += 2
}
}
fun setIndicatorSize(width: Float, height: Float) {
this.indicatorWidth = width
this.indicatorHeight = height
}
}
This code renders indicator lines on top of the xAxis.
Related
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
For example, I have a data set like following:
val dataSetX = {101, 205, 210, 445, 505}
val dataSetY = {50, 100, 150, 200, 250}
The labels on the xAxis of the chart will be 101, 205, 295, 445, 505.
But I want them to be 100,200,300,400,500, without changing the data.
What do I do?
To be able to render custom labels independent from the Data Entry List you need to implement a custom XAxisRenderer and override the function fun drawLabels(c: Canvas?, pos: Float, anchor: MPPointF?) which is called when the labels are ready to be drawn on the Canvas. The default implementation uses the mXAxis.mEntryCount and mXAxis.mEntries to render the labels in the xAxis which are calculated internally by the library. What you can do is to modify the superclass implementation by overriding it without calling the super.drawLabels(c, pos, anchor) method and make the adjustments needed to handle your custom labels. Below i will describe how you can achieve this.
1.) First declare your CustomXAxisRenderer which extends from XAxisRenderer like the below example:
class CustomXAxisRenderer(viewPortHandler: ViewPortHandler?, xAxis: XAxis?, trans: Transformer?, renderXArray : Array<Float>, formatter: ValueFormatter)
: XAxisRenderer(viewPortHandler, xAxis, trans) {
private val xArray : Array<Float>
private val xValueFormatter: ValueFormatter
init {
xArray = renderXArray
xValueFormatter = formatter
}
override fun drawLabels(c: Canvas?, pos: Float, anchor: MPPointF?) {
//don't call the super class to draw the default x points
//super.drawLabels(c, pos, anchor)
val labelRotationAngleDegrees = mXAxis.labelRotationAngle
val centeringEnabled = false//mXAxis.isCenterAxisLabelsEnabled
val positions = FloatArray(xArray.size * 2)
for(i in positions.indices step 2){
// only fill x values
if (centeringEnabled) {
positions[i.toInt()] = mXAxis.mCenteredEntries[(i / 2).toInt()]
} else {
positions[i.toInt()] = xArray[(i / 2).toInt()]
}
}
mTrans.pointValuesToPixel(positions)
for(i in positions.indices step 2){
var x = positions[i]
if (mViewPortHandler.isInBoundsX(x)) {
val label = xValueFormatter.getAxisLabel(xArray[i / 2], mXAxis)
if (mXAxis.isAvoidFirstLastClippingEnabled) {
// avoid clipping of the last
if (i / 2 == xArray.size - 1 && xArray.size > 1) {
val width = Utils.calcTextWidth(mAxisLabelPaint, label).toFloat()
if (width > mViewPortHandler.offsetRight() * 2 && x + width > mViewPortHandler.chartWidth)
x -= width / 2
// avoid clipping of the first
} else if (i == 0) {
val width = Utils.calcTextWidth(mAxisLabelPaint, label).toFloat()
x += width / 2
}
}
drawLabel(c, label, x, pos, anchor, labelRotationAngleDegrees)
}
}
}
}
2.)Then you can use it like the below:
//prepare an Array of the x points to render independent of the x points in the Data Entry List
//below values must be between AxisMinimum and AxisMaximum
val renderXArray = arrayOf<Float>(0f, 150f, 250f, 350f, 400f, 433f, 505f)
//and set a custom XAxisRenderer
chart.setXAxisRenderer(CustomXAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(YAxis.AxisDependency.LEFT), renderXArray, object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return value.toInt().toString()
}
}))
In case you need to return a specific Label-String based on the value you can use the ValueFormatter like the below:
chart.setXAxisRenderer(CustomXAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(YAxis.AxisDependency.LEFT), renderXArray, object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return when (value) {
0f -> "A"
150f -> "B"
250f -> "C"
350f -> "D"
400f -> "E"
433f -> "F"
505f -> "G"
else -> ""
}
}
}))
Full Example:
chart = findViewById<LineChart>(R.id.chart)
//set xAxis properties
val xAxis = chart.xAxis
xAxis.setDrawLabels(true)
xAxis.setDrawAxisLine(true)
xAxis.setDrawGridLines(true)
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.axisLineWidth = 1.5f
//set xAxis Min/Max and Granularity
xAxis.setAxisMinimum(0f)
xAxis.setAxisMaximum(505f)
xAxis.setGranularity(1f)
xAxis.setGranularityEnabled(true)
//set axisLeft properties
val axisLeft = chart.axisLeft
axisLeft.setDrawLabels(true)
axisLeft.setDrawGridLines(true)
axisLeft.setDrawZeroLine(true)
axisLeft.axisLineWidth = 1.5f
axisLeft.setDrawTopYLabelEntry(true)
//set axisRight properties
val axisRight = chart.axisRight
axisRight.setDrawLabels(false)
axisRight.setDrawGridLines(false)
axisRight.setDrawZeroLine(false)
axisRight.setDrawAxisLine(false)
//prepare the Entry points
val values: ArrayList<Entry> = ArrayList()
values.add(Entry(101f, 50f))
values.add(Entry(205f, 100f))
values.add(Entry(210f, 150f))
values.add(Entry(445f, 200f))
values.add(Entry(505f, 250f))
//set the LineDataSet
val set1 = LineDataSet(values, "")
set1.setDrawCircles(true);
set1.setDrawValues(true);
//prepare LineData and set them to LineChart
val dataSets: ArrayList<ILineDataSet> = ArrayList()
dataSets.add(set1)
val data = LineData(dataSets)
chart.setData(data)
chart.getDescription().setEnabled(false);
chart.legend.isEnabled = false
//prepare an Array of the x points to render independent of the x points in the Data Entry List
//below values must be between AxisMinimum and AxisMaximum
val renderXArray = arrayOf<Float>(0f, 150f, 250f, 350f, 400f, 433f, 505f)
//and set a custom XAxisRenderer
chart.setXAxisRenderer(CustomXAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(YAxis.AxisDependency.LEFT), renderXArray, object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return value.toInt().toString()
}
}))
Value Result:
Label Result:
Note: This was tested with version 'com.github.PhilJay:MPAndroidChart:v3.1.0'
I'm trying to draw the label lines as in picture using MPAndroidChart with a pie chart. I can't figure out how to
decouple the lines from the chart
draw that little circle at the beginning of the line.
Thank you.
This is by no means easy to achieve. To decouple the lines from the chart, you can use valueLinePart1OffsetPercentage and play with line part lengths. But to get the chart to draw dots at the end of lines, you need a custom renderer. Here's one:
class CustomPieChartRenderer(pieChart: PieChart, val circleRadius: Float)
: PieChartRenderer(pieChart, pieChart.animator, pieChart.viewPortHandler) {
override fun drawValues(c: Canvas) {
super.drawValues(c)
val center = mChart.centerCircleBox
val radius = mChart.radius
var rotationAngle = mChart.rotationAngle
val drawAngles = mChart.drawAngles
val absoluteAngles = mChart.absoluteAngles
val phaseX = mAnimator.phaseX
val phaseY = mAnimator.phaseY
val roundedRadius = (radius - radius * mChart.holeRadius / 100f) / 2f
val holeRadiusPercent = mChart.holeRadius / 100f
var labelRadiusOffset = radius / 10f * 3.6f
if (mChart.isDrawHoleEnabled) {
labelRadiusOffset = (radius - radius * holeRadiusPercent) / 2f
if (!mChart.isDrawSlicesUnderHoleEnabled && mChart.isDrawRoundedSlicesEnabled) {
rotationAngle += roundedRadius * 360 / (Math.PI * 2 * radius).toFloat()
}
}
val labelRadius = radius - labelRadiusOffset
val dataSets = mChart.data.dataSets
var angle: Float
var xIndex = 0
c.save()
for (i in dataSets.indices) {
val dataSet = dataSets[i]
val sliceSpace = getSliceSpace(dataSet)
for (j in 0 until dataSet.entryCount) {
angle = if (xIndex == 0) 0f else absoluteAngles[xIndex - 1] * phaseX
val sliceAngle = drawAngles[xIndex]
val sliceSpaceMiddleAngle = sliceSpace / (Utils.FDEG2RAD * labelRadius)
angle += (sliceAngle - sliceSpaceMiddleAngle / 2f) / 2f
if (dataSet.valueLineColor != ColorTemplate.COLOR_NONE) {
val transformedAngle = rotationAngle + angle * phaseY
val sliceXBase = cos(transformedAngle * Utils.FDEG2RAD.toDouble()).toFloat()
val sliceYBase = sin(transformedAngle * Utils.FDEG2RAD.toDouble()).toFloat()
val valueLinePart1OffsetPercentage = dataSet.valueLinePart1OffsetPercentage / 100f
val line1Radius = if (mChart.isDrawHoleEnabled) {
(radius - radius * holeRadiusPercent) * valueLinePart1OffsetPercentage + radius * holeRadiusPercent
} else {
radius * valueLinePart1OffsetPercentage
}
val px = line1Radius * sliceXBase + center.x
val py = line1Radius * sliceYBase + center.y
if (dataSet.isUsingSliceColorAsValueLineColor) {
mRenderPaint.color = dataSet.getColor(j)
}
c.drawCircle(px, py, circleRadius, mRenderPaint)
}
xIndex++
}
}
MPPointF.recycleInstance(center)
c.restore()
}
}
This custom renderer extends the default pie chart renderer. I basically just copied the code from PieChartRenderer.drawValues method, converted it to Kotlin, and removed everything that wasn't needed. I only kept the logic needed to determine the position of the points at the end of lines.
I tried to reproduce the image you showed:
val chart: PieChart = view.findViewById(R.id.pie_chart)
chart.setExtraOffsets(40f, 0f, 40f, 0f)
// Custom renderer used to add dots at the end of value lines.
chart.renderer = CustomPieChartRenderer(chart, 10f)
val dataSet = PieDataSet(listOf(
PieEntry(40f),
PieEntry(10f),
PieEntry(10f),
PieEntry(15f),
PieEntry(10f),
PieEntry(5f),
PieEntry(5f),
PieEntry(5f)
), "Pie chart")
// Chart colors
val colors = listOf(
Color.parseColor("#4777c0"),
Color.parseColor("#a374c6"),
Color.parseColor("#4fb3e8"),
Color.parseColor("#99cf43"),
Color.parseColor("#fdc135"),
Color.parseColor("#fd9a47"),
Color.parseColor("#eb6e7a"),
Color.parseColor("#6785c2"))
dataSet.colors = colors
dataSet.setValueTextColors(colors)
// Value lines
dataSet.valueLinePart1Length = 0.6f
dataSet.valueLinePart2Length = 0.3f
dataSet.valueLineWidth = 2f
dataSet.valueLinePart1OffsetPercentage = 115f // Line starts outside of chart
dataSet.isUsingSliceColorAsValueLineColor = true
// Value text appearance
dataSet.yValuePosition = PieDataSet.ValuePosition.OUTSIDE_SLICE
dataSet.valueTextSize = 16f
dataSet.valueTypeface = Typeface.DEFAULT_BOLD
// Value formatting
dataSet.valueFormatter = object : ValueFormatter() {
private val formatter = NumberFormat.getPercentInstance()
override fun getFormattedValue(value: Float) =
formatter.format(value / 100f)
}
chart.setUsePercentValues(true)
dataSet.selectionShift = 3f
// Hole
chart.isDrawHoleEnabled = true
chart.holeRadius = 50f
// Center text
chart.setDrawCenterText(true)
chart.setCenterTextSize(20f)
chart.setCenterTextTypeface(Typeface.DEFAULT_BOLD)
chart.setCenterTextColor(Color.parseColor("#222222"))
chart.centerText = "Center\ntext"
// Disable legend & description
chart.legend.isEnabled = false
chart.description = null
chart.data = PieData(dataSet)
Again, not very straightforward. I hope you like Kotlin! You can move most of that configuration code to a subclass if you need it often. Here's the result:
I'm not a MPAndroidChart expert. In fact, I've used it only once, and that was 2 years ago. But if you do your research, you can find a solution most of the time. Luckily, MPAndroidChart is a very customizable.
following this (Android - Fill the color between two lines using MPAndroidChart) answer I was able to fill with color the space between two lines using AndroidMPChart library.
But now I want to customize the filling color to have:
the areas above the boundarySet filled with blue color;
the areas below the boundarySet filled with green color.
Like in the following screenshot (please note that the blue line is a lineSet, so it could be that it is not a limit line):
I would like to customize the line color of the chart, setting it as the filling:
blue color for the line above the boundarySet;
green color for the line below the boundary set.
Is it possible?
I'm not able to find anything similar in the examples using MPAndroidChart.
Thank you!
you can try to override the drawLinear in LineChartRender
This has worked for me:
dataSet.setFillFormatter(new DefaultFillFormatter() {
#Override
public float getFillLinePosition(ILineDataSet dataSet, LineDataProvider dataProvider) {
return 22500;// its value of midel Y line
}
});
I've done this with this custom chart render) I use colors from line here, but you can use other colors. Change your colors here :drawFilledPath(c, filled, dataSet.colors[index], dataSet.fillAlpha)
class CustomLineChartRender(
lineDataProvider: LineDataProvider,
chartAnimator: ChartAnimator,
port: ViewPortHandler
)
: LineChartRenderer(lineDataProvider, chartAnimator, port) {
override fun drawLinearFill(
c: Canvas?,
dataSet: ILineDataSet?,
trans: Transformer?,
bounds: XBounds?
) {
val filled = mGenerateFilledPathBuffer
val startingIndex = bounds!!.min
val endingIndex = bounds!!.range + bounds!!.min
val indexInterval = 1
var currentStartIndex = 0
var currentEndIndex = indexInterval
var iterations = 0
do {
currentStartIndex = startingIndex + iterations * indexInterval
currentEndIndex = currentStartIndex + indexInterval
currentEndIndex = if (currentEndIndex > endingIndex) endingIndex else currentEndIndex
if (currentStartIndex <= currentEndIndex) {
generateFilledPath(dataSet!!, currentStartIndex, currentEndIndex, filled)
trans!!.pathValueToPixel(filled)
val drawable = dataSet.fillDrawable
if (drawable != null) {
drawFilledPath(c, filled, drawable)
} else {
val index = startingIndex + iterations
drawFilledPath(c, filled, dataSet.colors[index], dataSet.fillAlpha)
}
}
iterations++
} while (currentStartIndex <= currentEndIndex)
}
private fun generateFilledPath(
dataSet: ILineDataSet,
startIndex: Int,
endIndex: Int,
outputPath: Path
) {
val fillMin = dataSet.fillFormatter.getFillLinePosition(dataSet, mChart)
val phaseY = mAnimator.phaseY
val isDrawSteppedEnabled = dataSet.mode == LineDataSet.Mode.STEPPED
outputPath.reset()
val entry = dataSet.getEntryForIndex(startIndex)
outputPath.moveTo(entry.x, fillMin)
outputPath.lineTo(entry.x, entry.y * phaseY)
// create a new path
var currentEntry: Entry? = null
var previousEntry = entry
for (x in startIndex + 1..endIndex) {
currentEntry = dataSet.getEntryForIndex(x)
if (isDrawSteppedEnabled) {
outputPath.lineTo(currentEntry.x, previousEntry!!.y * phaseY)
}
outputPath.lineTo(currentEntry.x, currentEntry.y * phaseY)
previousEntry = currentEntry
}
// close up
if (currentEntry != null) {
outputPath.lineTo(currentEntry.x, fillMin)
}
outputPath.close()
}
}
I am trying to show the data using LineChart, and ran into issues displaying x axis labels. I use data.start and data.end to set the x-axis bounds in my chart. So let's say API returns data for two days only (Thursday and Friday), start will be Monday and end will be Saturday.
Note:X values are ALL unix timestamps.
here's my code:
class MyChart(chart: LineChart?, val data: MyData) {
private val startValue = data.start.toEpochSecond(ZoneOffset.UTC)
init {
chart?.run {
setScaleEnabled(false)
legend.isEnabled = false
description.isEnabled = false
axisRight.run {
setDrawGridLines(true)
setDrawLabels(false)
axisMinimum = 0.1f // hide 0.0 values
}
axisLeft.run {
setDrawGridLines(true)
axisMinimum = 0.1f // hide 0.0 values
}
setupXAxis(xAxis)
Log.e("MPTEST, startValue: ", startValue.toString())
val entries = ArrayList<Entry>()
data.list?.forEachIndexed { _, data ->
val timeInSeconds = data.time.toEpochSecond(ZoneOffset.UTC)
val xIndex = (timeInSeconds - startValue).toFloat()
Log.e("MPTEST, xIndex: ", xIndex.toString())
entries.add(Entry(xIndex, data.value))
}
val data = LineData(LineDataSet(entries, ""))
setData(data)
invalidate()
}}
private fun setupXAxis(xAxis: XAxis?) {
xAxis?.run {
position = XAxis.XAxisPosition.BOTTOM
val startInSeconds = data.start.toEpochSecond(ZoneOffset.UTC)
axisMinimum = (startInSeconds - startValue).toFloat()
Log.e("MPTEST, axisMinimum: ", axisMinimum.toString())
val endInSeconds = data.end.toEpochSecond(ZoneOffset.UTC)
axisMaximum = (endInSeconds - startValue).toFloat()
Log.e("MPTEST, axisMaximum: ", axisMaximum.toString())
setCenterAxisLabels(true)
setDrawGridLines(false)
// I need to fix something here I think
setLabelCount(7, true)
valueFormatter = IndexAxisValueFormatter(data.labels)
}
} }
Here's the logcat output:
E/MPTEST, axisMinimum:: 0.0
E/MPTEST, axisMaximum:: 604799.0
E/MPTEST, startValue:: 1546732800
E/MPTEST, xIndex:: 366180.0
E/MPTEST, xIndex:: 467893.0
That's what I get - https://i.ibb.co/YD2DnhJ/Screen-Shot-2019-01-16-at-7-20-23-AM.png
(as you can see only first x axis label is displayed)
and this is what I am trying to achieve - https://i.ibb.co/M8b9pyP/Screen-Shot-2019-01-16-at-7-24-15-AM.png