Home > database >  Charts pod: Why are extra entries added to the chart?
Charts pod: Why are extra entries added to the chart?

Time:12-17

I have a pie chart that displays data added to it It looks like this:

class HomeViewController: UIViewController {

    var pieChart = PieChartView()

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        pieChart.delegate = self               
        self.setChart()
    }
    
    func setChart() {
        var entries: [ChartDataEntry] = []
                
        for entry in 0..<(self.cellArr.count) {
            if self.cellArr.count > 0 {
                let dataEntry = PieChartDataEntry(value: Double(self.cellArr[entry].amount), label: String(self.cellArr[entry].type))
                entries.append(dataEntry)
            }
        }
        updateSorting(values: entries)
    }
    
    func updateSorting(values: [ChartDataEntry]){
        let dataSet = PieChartDataSet(entries: values, label: "")
        let data = PieChartData(dataSets: [dataSet])
        
        dataSet.colors = ChartColorTemplates.colorful()
        pieChart.data = data
        pieChart.notifyDataSetChanged()        
    }
}

The problem is in the entries variable, which is located in the setChart function. I need to work with it outside the function, but if I put it in a class -

class HomeViewController: UIViewController {

    var pieChart = PieChartView()
    var entries: [ChartDataEntry] = [] // <------------ !!!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        pieChart.delegate = self               
        self.setChart()
    }
}

Then the chart will start displaying extra values

An illustrative example:

enter image description here enter image description here

In the first screenshot, entries is in a function, in the second it is already behind it

I tried to set breakpoints and look at the for loop, but I still don’t understand why it happens that the array adds old data to new ones with each iteration

CodePudding user response:

Since you're calling setChart from viewWillAppear, you'll be appending to many items in your array (if the view appears/disappears in a single session). You need to clear the variables appropriately, or just overwrite them entirely.


Unrelated, but you can greatly simplify this for loop code:

Start:

func setChart1() {
    var entries: [ChartDataEntry] = []
            
    for entry in 0..<(self.cellArr.count) {
        if self.cellArr.count > 0 {
            let dataEntry = PieChartDataEntry(value: Double(self.cellArr[entry].amount), label: String(self.cellArr[entry].type))
            entries.append(dataEntry)
        }
    }
    updateSorting(values: entries)
}

Remove useless if statement:

func setChart2() {
    var entries: [ChartDataEntry] = []
            
    for entry in 0..<(self.cellArr.count) {
        let dataEntry = PieChartDataEntry(value: Double(self.cellArr[entry].amount), label: String(self.cellArr[entry].type))
        entries.append(dataEntry)
    }
    updateSorting(values: entries)
}

Replace manually constructed range of indices with a simple Array.indices:

func setChart3() {
    var entries: [ChartDataEntry] = []
            
    for entry in self.cellArr.indices { // "entry" is a total misnomer. It's not an entry, it's an index that can be used to get an entry
        let dataEntry = PieChartDataEntry(value: Double(self.cellArr[entry].amount), label: String(self.cellArr[entry].type))
        entries.append(dataEntry)
    }
    updateSorting(values: entries)
}

Realize that you don't even need the indices, you only actually care about the values themselves:

func setChart4() {
    var entries: [ChartDataEntry] = []
            
    for entry in self.cellArr {
        let dataEntry = PieChartDataEntry(value: Double(entry.amount), label: String(entry.type))
        entries.append(dataEntry)
    }
    updateSorting(values: entries)
}

Inline local variable (its name adds no useful information):

func setChart5() {
    var entries: [ChartDataEntry] = []
            
    for entry in self.cellArr {
        entries.append(PieChartDataEntry(value: Double(entry.amount), label: String(entry.type)))
    }
    updateSorting(values: entries)
}

Notice that this is just a map operation:

func setChart6() {
    var entries: [ChartDataEntry] = self.cellArr.map { entry in
        PieChartDataEntry(value: Double(entry.amount), label: String(entry.type)))
    }
    updateSorting(values: entries)
}

entries can now be immutable, and can use type inference:

func setChart7() {
    let entries = self.cellArr.map { PieChartDataEntry(value: Double($0.amount), label: String($0.type))) }
    updateSorting(values: entries)
}

CodePudding user response:

I put the array of entries into a class and cleared it in the setChart7 function

class HomeViewController: UIViewController {

    var pieChart = PieChartView()

    var entries: [ChartDataEntry] = []

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

    self.setChart()
    }

    func setChart7() {
        entries.removeAll()
        let entries = self.cellArr.map { PieChartDataEntry(value: Double($0.amount), label: String($0.type))) }
        updateSorting(values: entries)
    }
}
  • Related