I've used a CombinedChartView which has chartdata & linedata. The chartdata is grouped but the xAxis labels are not in center.

I tried setting xAxis.centerAxisLabelsEnabled = true but the app crashed at IAxisValueFormatter
Below is the Formatter class :
class MonthChartFormatter: NSObject, IAxisValueFormatter {
var nameValues: [String]! = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return String(describing: nameValues![Int(value)])
}
}
The error I got :
fatal error: Index out of range
The value was somehow -1. I've no idea what went wrong. Without centerAxisLabelsEnabled, it works fine(though xAxis labels not centered).
Below are my datasets:
â–¿ Optional<Array<IChartDataSet>>
â–¿ some : 2 elements
â–¿ 0 : Charts.BarChartDataSet, label: Some, 12 entries:
ChartDataEntry, x: 0.0, y 8449179.0
ChartDataEntry, x: 1.0, y 10049795.0
ChartDataEntry, x: 2.0, y 11931444.0
ChartDataEntry, x: 3.0, y 13332463.0
ChartDataEntry, x: 4.0, y 13331474.0
ChartDataEntry, x: 5.0, y 13331472.0
ChartDataEntry, x: 6.0, y 13331472.0
ChartDataEntry, x: 7.0, y 13331472.0
ChartDataEntry, x: 8.0, y 13331472.0
ChartDataEntry, x: 9.0, y 13331472.0
ChartDataEntry, x: 10.0, y 13331472.0
ChartDataEntry, x: 11.0, y 13331472.0
â–¿ 1 : Charts.BarChartDataSet, label: Some, 12 entries:
ChartDataEntry, x: 0.0, y 9489726.0
ChartDataEntry, x: 1.0, y 11563048.0
ChartDataEntry, x: 2.0, y 3096648.0
ChartDataEntry, x: 3.0, y 35001644.0
ChartDataEntry, x: 4.0, y 17885870.0
ChartDataEntry, x: 5.0, y 13331472.0
ChartDataEntry, x: 6.0, y 13331472.0
ChartDataEntry, x: 7.0, y 13331472.0
ChartDataEntry, x: 8.0, y 13331472.0
ChartDataEntry, x: 9.0, y 13331472.0
ChartDataEntry, x: 10.0, y 13331472.0
ChartDataEntry, x: 11.0, y 13331472.0
What could be the issue? Any help is much appreciated. @liuxuan30 @danielgindi
where do you get fatal error: Index out of range?
BTW, I checked combined chart in ChartsDemo on master; it works fine with centerAxisLabelsEnabled turned on.
@liuxuan30 I got the error from MonthChartFormatter class.
Oh then how would I center the labels?
I checked combined chart in ChartsDemo on master; it works fine with centerAxisLabelsEnabled turned on. Looks like you did not setup correctly; check the demo.
Look carefully about the order of setting up chart data; it matters. Ideally chart.data = data should be the last line of setting up chart
MonthChartFormatter seems your own class? Then you need to debug a little.. no idea
The demo also uses Month, so probably you check your formatter with Demo's
- (NSString *)stringForValue:(double)value
axis:(ChartAxisBase *)axis
{
return months[(int)value % months.count];
}
this is now Demo passes the string to x axis. If you seeing out of range.. maybe time to use mod. I do see you use return String(describing: nameValues![Int(value)]) directly. Smell like classic out of range
@liuxuan30 Thanks a lot for looking into the issue.
This is how I'm setting up the chartView
let xAxis = combinedChartView.xAxis
xAxis.enabled = true
xAxis.labelPosition = .bottom
xAxis.drawAxisLineEnabled = true
xAxis.drawGridLinesEnabled = false
xAxis.granularity = 1
xAxis.avoidFirstLastClippingEnabled = true
xAxis.centerAxisLabelsEnabled = true
let formatter = MonthChartFormatter.init()
xAxis.valueFormatter = formatter
xAxis.labelCount = 12
I just logged the ChartFormatter class and this is what I got :
VALUE *** 0.0
VALUE *** 1.0
VALUE *** 2.0
VALUE *** 3.0
VALUE *** 4.0
VALUE *** 5.0
VALUE *** 6.0
VALUE *** 7.0
VALUE *** 8.0
VALUE *** 9.0
VALUE *** 10.0
VALUE *** 11.0
VALUE *** -1.0
VALUE *** 0.0
VALUE *** 1.0
VALUE *** 2.0
VALUE *** 3.0
VALUE *** 4.0
VALUE *** 5.0
VALUE *** 6.0
VALUE *** 7.0
VALUE *** 8.0
VALUE *** 9.0
VALUE *** 10.0
VALUE *** 11.0
VALUE *** 12.0
VALUE *** 0.0
VALUE *** 1.0
VALUE *** 2.0
VALUE *** 3.0
VALUE *** 4.0
VALUE *** 5.0
VALUE *** 6.0
VALUE *** 7.0
VALUE *** 8.0
VALUE *** 9.0
VALUE *** 10.0
I've no idea why is this getting called so many times when centerAxisLabelsEnabled turned on.
I tried with months[(int)value % months.count]. Same problem.
@liuxuan30 I think the entries array is generating a **value of -1**from somewhere.
Because from AxisBase.getFormattedLabel(Int) -> String, when I print out the entries its coming as :
â–¿ 14 elements
- 0 : -1.0
- 1 : 0.0
- 2 : 1.0
- 3 : 2.0
- 4 : 3.0
- 5 : 4.0
- 6 : 5.0
- 7 : 6.0
- 8 : 7.0
- 9 : 8.0
- 10 : 9.0
- 11 : 10.0
- 12 : 11.0
- 13 : 12.0
Phew. Found the issue. My bad. I was not setting the axisMinimum & axisMaximum & granularity set to 1. It works. Thanks a lot
Just want to share my experience, I solved this issue using a dynamic granularity, make chart adjust while zooming
Important do not force labelCount
First I have many datasets, so I group datasets values using
let groupSpace = 0.4
let barSpace = 0.03
let barWidth = 0.2
data.barWidth = barWidth
chart.xAxis.axisMinimum = 0.0
chart.xAxis.axisMaximum = 0.0 + data.groupWidth(groupSpace: groupSpace, barSpace: barSpace) * Double(labels.count)
data.groupBars(fromX: 0.0, groupSpace: groupSpace, barSpace: barSpace)
Adjust granularity base on how many columns you want to see
chart.xAxis.granularity = chart.xAxis.axisMaximum / Double(labels.count)
Then set data
chart.data = data
Then I use a custom Formatter to calculate label to be shown
class CustomLabelsAxisValueFormatter : NSObject, IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let count = self.labels.count
guard let axis = axis, count > 0 else {
return ""
}
let factor = axis.axisMaximum / Double(count)
let index = Int((value / factor).rounded())
if index >= 0 && index < count {
return self.labels[index]
}
return ""
}
}
Set the custom formatter
let formatter = CustomLabelsAxisValueFormatter()
formatter.labels = xVals
chart.xAxis.valueFormatter = formatter
Try and let me know. Happy coding!
@samueleperricone computing granularity worked. Cheers :)
computing granularity as done by @codingspark worked for me.
chart.xAxis.granularity = chart.xAxis.axisMaximum / Double(labels.count)
Most helpful comment
Just want to share my experience, I solved this issue using a dynamic granularity, make chart adjust while zooming
Important do not force labelCount
First I have many datasets, so I group datasets values using
Adjust granularity base on how many columns you want to see
chart.xAxis.granularity = chart.xAxis.axisMaximum / Double(labels.count)Then set data
chart.data = dataThen I use a custom Formatter to calculate label to be shown
Set the custom formatter
Try and let me know. Happy coding!