1

Is there a way with the iOs Charts lib (3.6.0) to scale the Y axis with the nearest hundred, thousands, etc ?

I'm probably missing something but my Y axis doesn't make any sense :

enter image description here

In this exemple, I would like my Y axis to be something like :

75 000
60 000
45 000
30 000
15 000
0
-15 000

I tried using autoScaleMinMaxEnabledbut it doesn't seem to work.

I don't understand how to make the y axis use rounded numbers ?

Thank you for your help

Update :

Here is the code I use, as requested :

class GraphCustomView : LineChartView, ChartViewDelegate {
    //MARK: Variables
    var graphModel: [GraphModel] = []
    
    // Initialize Chart
    public func initializeChart(graphModel: [GraphModel], devise: String, withouthFill: Bool? = true) {
        self.graphModel = [GraphModel]()
        self.graphModel = graphModel
        
        self.delegate = self
        self.chartDescription?.enabled = false
                
        // xAxis
        self.xAxis.enabled = true
        self.xAxis.drawGridLinesEnabled = false
        self.xAxis.labelPosition = .bottom
        self.xAxis.valueFormatter = DateValueFormatter(miniTime: graphModel.first!.miniDate)
        self.xAxis.labelFont = UIFont(name: "Ubuntu", size: 8)!
        self.xAxis.labelRotationAngle = -20
        self.xAxis.granularityEnabled = true
        self.xAxis.granularity = 1
        
        // RightAxis
        self.rightAxis.enabled = false
        self.rightAxis.drawGridLinesEnabled = false
        
        // LeftAxis
        self.leftAxis.drawGridLinesEnabled = true
        self.leftAxis.gridColor = .gray
        self.leftAxis.gridLineDashLengths = [CGFloat(1.5)]
        self.leftAxis.labelFont = UIFont(name: "Ubuntu", size: 8)!
        
        // General chart settings
        self.drawBordersEnabled = false
        self.setScaleEnabled(true)
        
        leftAxis.setLabelCount(7, force: true)
        leftAxis.drawTopYLabelEntryEnabled = true
        leftAxis.drawBottomYLabelEntryEnabled = true
               
        // Legend
        self.leftAxis.labelFont = UIFont(name: "Ubuntu", size: 11)!
        self.xAxis.labelFont = UIFont(name: "Ubuntu", size: 11)!
        
        let l = self.legend
        l.form = .circle
        l.horizontalAlignment = .right
        l.verticalAlignment = .bottom
        l.orientation = .horizontal
        l.drawInside = false
        l.font = UIFont(name: "Ubuntu", size: 8)!
        
        // Overdrawn line
        let minValue = graphModel.first!.minValue
        let maxValue = graphModel.first!.maxValue
        var range: Double = 0.0
        
        if (maxValue - minValue != 0) {
            range = (maxValue - minValue) / 7
        }
        
        if (graphModel.first!.minValue - (range * 2) < graphModel.first!.overdrawn && graphModel.first!.overdrawn < graphModel.first!.minValue) {
            self.leftAxis.axisMinimum = graphModel.first!.overdrawn
        }
                                
        let limit: ChartLimitLine = ChartLimitLine()
        limit.label = "Overdrawn"
        limit.limit = graphModel.first!.overdrawn
        limit.valueTextColor = .red
        limit.lineColor = .red
        limit.lineDashLengths = [10, 5]
        leftAxis.addLimitLine(limit)
        
        // Marker/Tooltip
        let marker = XYMarkerView(color: .darkGray,
                                  font: UIFont(name: "Ubuntu", size: 12)!,
                                  textColor: .white,
                                  insets: UIEdgeInsets(top: 8, left: 8, bottom: 20, right: 8),
                                  xAxisValueFormatter: DateValueFormatter(miniTime: graphModel.first!.miniDate),
                                  yAxisValueFormatter: MarkerValueFormatter(devise: devise))
        marker.chartView = self
        marker.minimumSize = CGSize(width: 80, height: 40)
        self.marker = marker
        
        self.isMultipleTouchEnabled = true
        self.highlightPerTapEnabled = true
        self.highlightPerDragEnabled = true
        
        // Add data to chart
        self.updateChartData()
    }
    
    public func updateChartData() {
        // Creating dataSets
        var dataSets: [LineChartDataSet] = [LineChartDataSet]()
        
        // We need to sort the data in order to add it to the graph
        for graph in self.graphModel {
            graph.chartData.sort(by: { $0.x < $1.x })
            
            let dataSet : LineChartDataSet = LineChartDataSet(entries: graph.chartData, label: graph.name)
            dataSet.circleRadius = 0
            dataSet.colors = graph.color
            dataSet.drawValuesEnabled = false
            dataSet.lineWidth = 2
            dataSet.mode = .cubicBezier

            let leftAxis = self.leftAxis
            leftAxis.drawLimitLinesBehindDataEnabled = true
            dataSet.fillColor = graph.color.first!
            dataSet.drawFilledEnabled = true
            
            // Add to datasets
            dataSets.append(dataSet)
        }
        
        // Styling data
        let data = LineChartData(dataSets: dataSets)
        data.setValueFont(UIFont(name: "Ubuntu", size: 7)!)
        
        // Displaying graph
        self.data = data
    }

Here is the data I used for this specific chart :

[{\"pointDate\":\"2016-11-01T00:00:00\",\"pointValue\":45375.800000000003},{\"pointDate\":\"2016-11-01T00:00:00\",\"pointValue\":45375.800000000003},{\"pointDate\":\"2016-10-31T00:00:00\",\"pointValue\":54755.580000000002},{\"pointDate\":\"2016-10-30T00:00:00\",\"pointValue\":34324.199999999997},{\"pointDate\":\"2016-10-29T00:00:00\",\"pointValue\":43846.059999999998},{\"pointDate\":\"2016-10-28T00:00:00\",\"pointValue\":29243.779999999999},{\"pointDate\":\"2016-10-27T00:00:00\",\"pointValue\":28238.439999999999},{\"pointDate\":\"2016-10-26T00:00:00\",\"pointValue\":-11461.74},{\"pointDate\":\"2016-10-25T00:00:00\",\"pointValue\":-5756.5500000000002},{\"pointDate\":\"2016-10-24T00:00:00\",\"pointValue\":27565.939999999999},{\"pointDate\":\"2016-10-23T00:00:00\",\"pointValue\":40770.910000000003},{\"pointDate\":\"2016-10-22T00:00:00\",\"pointValue\":46875.870000000003},{\"pointDate\":\"2016-10-21T00:00:00\",\"pointValue\":44609.540000000001},{\"pointDate\":\"2016-10-20T00:00:00\",\"pointValue\":43970.769999999997},{\"pointDate\":\"2016-10-19T00:00:00\",\"pointValue\":43262.910000000003},{\"pointDate\":\"2016-10-18T00:00:00\",\"pointValue\":22016.080000000002},{\"pointDate\":\"2016-10-17T00:00:00\",\"pointValue\":45001.940000000002},{\"pointDate\":\"2016-10-16T00:00:00\",\"pointValue\":44443.739999999998},{\"pointDate\":\"2016-10-15T00:00:00\",\"pointValue\":61521.720000000001},{\"pointDate\":\"2016-10-14T00:00:00\",\"pointValue\":31674.16},{\"pointDate\":\"2016-10-13T00:00:00\",\"pointValue\":42767.040000000001},{\"pointDate\":\"2016-10-12T00:00:00\",\"pointValue\":55202.110000000001},{\"pointDate\":\"2016-10-11T00:00:00\",\"pointValue\":76274.100000000006},{\"pointDate\":\"2016-10-10T00:00:00\",\"pointValue\":39097.07},{\"pointDate\":\"2016-10-09T00:00:00\",\"pointValue\":13742.99},{\"pointDate\":\"2016-10-08T00:00:00\",\"pointValue\":9616.2199999999993},{\"pointDate\":\"2016-10-07T00:00:00\",\"pointValue\":1450.6099999999999},{\"pointDate\":\"2016-10-06T00:00:00\",\"pointValue\":5820.5},{\"pointDate\":\"2016-10-05T00:00:00\",\"pointValue\":-9522.75},{\"pointDate\":\"2016-10-04T00:00:00\",\"pointValue\":8317},{\"pointDate\":\"2016-10-03T00:00:00\",\"pointValue\":7923.6499999999996},{\"pointDate\":\"2016-10-02T00:00:00\",\"pointValue\":10249.889999999999},{\"pointDate\":\"2016-10-01T00:00:00\",\"pointValue\":2388.6799999999998},{\"pointDate\":\"2016-09-30T00:00:00\",\"pointValue\":0}]

And the code use to format it a bit :

for point in pointevo.pointEvolution {
    let date = point.pointDate.toDate()
    let timeInSecondes = date?.timeIntervalSince1970
                                    
    if (firstTime) {
        self.miniDate = timeInSecondes!
        firstTime = false
        
        minValue = point.pointValue
        maxValue = point.pointValue
    }
    
    if (point.pointValue < minValue) {
        minValue = point.pointValue
    }
    if (point.pointValue > maxValue) {
        maxValue = point.pointValue
    }
    
    chartData.append(ChartDataEntry(x: (timeInSecondes! - miniDate) / (3600.0 * 24.0), y: point.pointValue))
                        
    if tempPointValue.firstIndex(of: point.pointValue) == nil {
        tempPointValue.append(point.pointValue)
    }
}
belyarv
  • 23
  • 3

1 Answers1

0

EDITED AFTER DISCUSSIONS

As I test your code with your data I found the root of your issue. In your code it's the line:

leftAxis.setLabelCount(7, force: true)

If force parameter is set to true - it override the default calculated labels and force the labels to be exact number of labels you specified and it will spread by equal distance.

If not force it - when there will be not exact number of labels specified, I got 6 lines (and labels). So it's now up to you how to better use it.

Here also examples of results if force parameter is true and false (I set here xaxis and overdraw values to some static values).

force parameter is true

force parameter is false

Below the first one answer for some other situation.

You can use for it IAxisValueFormatter protocol method stringForValue(_ value:, axis:). You can round your value here and place additional symbols, like currencies symbol, like I do. Something like this:

extension ChartController: IAxisValueFormatter {

    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        if axis is XAxis {
            // do something you need for X axis
            return valueTransformedToString
        } else {
            // do something you need for Y axis
            return valueTransformedToString
        }
    }

}
Denis Kozhukhov
  • 1,205
  • 8
  • 16
  • I know about AxisValueFormatter but if I use it the graph won't be correct. For example, in the picture I added, if I change `-11 462` to `-15 000`, when the user will click on the point, the Y axis won't make any sense... Isn't there a way to work with ranges ? – belyarv Jan 06 '21 at 18:05
  • It's interesting case. As I know Chart make it automatically. I just now look at my code (I wrote it a months ago, so don't remember everything) - and it works without any additional steps from my own. I tried to leave only the data setting to datasets - without any additional flags - and my y axis values are very good big whole numbers. Also look at examples and screens on Chart github page - these values are always good. So now it become even more interesting for me to understand how you achieve this, I tried to make it in my tests - and nothing similar :) Can you bring here a code you use? – Denis Kozhukhov Jan 06 '21 at 19:42
  • about AxisValueFormatter you are right, it's not the case for this situation. – Denis Kozhukhov Jan 06 '21 at 19:43
  • I added the code I use as an update to my question. I'm probably doing something wrong... Thank you for your help ! – belyarv Jan 07 '21 at 08:29
  • can you also add data you used? to be make more correct test... will try to use your code and see what happens here – Denis Kozhukhov Jan 07 '21 at 08:55
  • I test your code and data and do some more research and found the root of your issue. I edit my original answer. – Denis Kozhukhov Jan 07 '21 at 10:25
  • wow ok, a small parameter then... Thank you so much !!!! – belyarv Jan 07 '21 at 11:26