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

[Charts 3.0] Issue with centerAxisLabelsEnabled #1566

Closed
sree127 opened this issue Sep 27, 2016 · 12 comments
Closed

[Charts 3.0] Issue with centerAxisLabelsEnabled #1566

sree127 opened this issue Sep 27, 2016 · 12 comments

Comments

@sree127
Copy link

sree127 commented Sep 27, 2016

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

screen shot 2016-09-27 at 2 06 10 pm

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

@liuxuan30
Copy link
Member

where do you get fatal error: Index out of range?

@liuxuan30
Copy link
Member

liuxuan30 commented Sep 27, 2016

BTW, I checked combined chart in ChartsDemo on master; it works fine with centerAxisLabelsEnabled turned on.

@sree127
Copy link
Author

sree127 commented Sep 27, 2016

@liuxuan30 I got the error from MonthChartFormatter class.

Oh then how would I center the labels?

@liuxuan30
Copy link
Member

liuxuan30 commented Sep 27, 2016

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

@liuxuan30
Copy link
Member

liuxuan30 commented Sep 27, 2016

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

@liuxuan30
Copy link
Member

liuxuan30 commented Sep 27, 2016

- (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

@sree127
Copy link
Author

sree127 commented Sep 27, 2016

@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.

@sree127
Copy link
Author

sree127 commented Sep 27, 2016

@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

@sree127
Copy link
Author

sree127 commented Sep 27, 2016

Phew. Found the issue. My bad. I was not setting the axisMinimum & axisMaximum & granularity set to 1. It works. Thanks a lot

@codingspark
Copy link

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!

@sree127
Copy link
Author

sree127 commented Feb 7, 2017

@samueleperricone computing granularity worked. Cheers :)

@pranavkth
Copy link

pranavkth commented Apr 8, 2019

computing granularity as done by @codingspark worked for me.

chart.xAxis.granularity = chart.xAxis.axisMaximum / Double(labels.count)

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

4 participants