Hide Line Chart Limit Lines. Swift 2 - swift

I am using the Charts frameworks (danielgindi/Charts).
I have a segment showing 1,2 & 3. Depending on the choice the line graph should display that amount of lines within a line chart.
I have a switch statement, that depending on the number provided within the segment that displays that amount of lines. E.g. within case1, 1 line is shown, case 2, 2 lines are shown etc.. & this works as expected.
When I try to add limit lines within this switch statement and switch from a higher case to a lower e.g. 3 to 2, the 3rd line doesn't disappear & line 1 and 2 seem to have duplications.
Is there anyway of hiding the limit lines within the switch statement?
I have the following code:
func setChart(xValues: [String], valuesLineChart: [[Double]], limitLines: [Double]) {
chartView.descriptionText = ""
chartView.noDataText = "You need to provide data for the chart."
print("valuesLineChart has \(valuesLineChart.count) lines")
var dataSets : [LineChartDataSet] = [LineChartDataSet]()
switch valuesLineChart.count {
case 1 : print("1 within switch")
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(value: valuesLineChart[0][i], xIndex: i))
}
let set1 = LineChartDataSet(yVals: yVals1, label: nil)
dataSets.append(set1)
//limit lines
let limitSet1 = ChartLimitLine(limit: limitLines[0], label: "switch1, limit1")
chartView.rightAxis.addLimitLine(limitSet1)
case 2 :print("2 within switch")
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(value: valuesLineChart[0][i], xIndex: i))
}
var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals2.append(ChartDataEntry(value: valuesLineChart[1][i], xIndex: i))
}
let set1 = LineChartDataSet(yVals: yVals1, label: nil)
let set2 = LineChartDataSet(yVals: yVals2, label: nil)
dataSets.append(set1)
dataSets.append(set2)
//limit lines
let limitSet1 = ChartLimitLine(limit: limitLines[0], label: "")
let limitSet2 = ChartLimitLine(limit: limitLines[1], label: "")
chartView.rightAxis.addLimitLine(limitSet1)
chartView.rightAxis.addLimitLine(limitSet2)
case 3 :print("3 within switch")
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(value: valuesLineChart[0][i], xIndex: i))
}
var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals2.append(ChartDataEntry(value: valuesLineChart[1][i], xIndex: i))
}
var yVals3 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals3.append(ChartDataEntry(value: valuesLineChart[2][i], xIndex: i))
}
let set1 = LineChartDataSet(yVals: yVals1, label: nil)
let set2 = LineChartDataSet(yVals: yVals2, label: nil)
let set3 = LineChartDataSet(yVals: yVals3, label: nil)
dataSets.append(set1)
dataSets.append(set2)
dataSets.append(set3)
//limit lines
let limitSet1 = ChartLimitLine(limit: limitLines[0], label: "")
let limitSet2 = ChartLimitLine(limit: limitLines[1], label: "")
let limitSet3 = ChartLimitLine(limit: limitLines[2], label: "")
chartView.rightAxis.addLimitLine(limitSet1)
chartView.rightAxis.addLimitLine(limitSet2)
chartView.rightAxis.addLimitLine(limitSet3)
}
let data: CombinedChartData = CombinedChartData(xVals: xValues)
data.lineData = LineChartData(xVals: xValues, dataSets: dataSets)
chartView.data = data
}

I found a solution to my problem. When the segment was selecting a different number, i was recalling the setChart function causing duplications of limitLines.
To solve this problem i removed the limit lines prior to recalling the setChart function;
var limitSet1 : ChartLimitLine?
var limitSet2 : ChartLimitLine?
var limitSet3 : ChartLimitLine?
var limitLineArray : [Double]
func removeLimitLines {
switch (limitLineArray.count) {
case 1: print("there was 1 limit line, need to remove this from chart view")
chartView.rightAxis.removeLimitLine(limitSet1!)
case 2: print("there was 2 limit line, need to remove this from chart view")
chartView.rightAxis.removeLimitLine(limitSet1!)
chartView.rightAxis.removeLimitLine(limitSet2!)
case 3: print("there was 3 limit line, need to remove this from chart view")
chartView.rightAxis.removeLimitLine(limitSet1!)
chartView.rightAxis.removeLimitLine(limitSet2!)
chartView.rightAxis.removeLimitLine(limitSet3!)
}
}
func setChart(xValues: [String], valuesLineChart: [[Double]], limitLines: [Double]) {
chartView.descriptionText = ""
chartView.noDataText = "You need to provide data for the chart."
print("valuesLineChart has \(valuesLineChart.count) lines")
var dataSets : [LineChartDataSet] = [LineChartDataSet]()
switch valuesLineChart.count {
case 1 : print("1 within switch")
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(value: valuesLineChart[0][i], xIndex: i))
}
let set1 = LineChartDataSet(yVals: yVals1, label: nil)
dataSets.append(set1)
//limit lines
limitSet1 = ChartLimitLine(limit: limitLines[0], label: "switch1, limit1")
chartView.rightAxis.addLimitLine(limitSet1)
case 2 :print("2 within switch")
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(value: valuesLineChart[0][i], xIndex: i))
}
var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals2.append(ChartDataEntry(value: valuesLineChart[1][i], xIndex: i))
}
let set1 = LineChartDataSet(yVals: yVals1, label: nil)
let set2 = LineChartDataSet(yVals: yVals2, label: nil)
dataSets.append(set1)
dataSets.append(set2)
//limit lines
limitSet1 = ChartLimitLine(limit: limitLines[0], label: "")
limitSet2 = ChartLimitLine(limit: limitLines[1], label: "")
chartView.rightAxis.addLimitLine(limitSet1)
chartView.rightAxis.addLimitLine(limitSet2)
case 3 :print("3 within switch")
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(value: valuesLineChart[0][i], xIndex: i))
}
var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals2.append(ChartDataEntry(value: valuesLineChart[1][i], xIndex: i))
}
var yVals3 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yVals3.append(ChartDataEntry(value: valuesLineChart[2][i], xIndex: i))
}
let set1 = LineChartDataSet(yVals: yVals1, label: nil)
let set2 = LineChartDataSet(yVals: yVals2, label: nil)
let set3 = LineChartDataSet(yVals: yVals3, label: nil)
dataSets.append(set1)
dataSets.append(set2)
dataSets.append(set3)
//limit lines
limitSet1 = ChartLimitLine(limit: limitLines[0], label: "")
limitSet2 = ChartLimitLine(limit: limitLines[1], label: "")
limitSet3 = ChartLimitLine(limit: limitLines[2], label: "")
chartView.rightAxis.addLimitLine(limitSet1)
chartView.rightAxis.addLimitLine(limitSet2)
chartView.rightAxis.addLimitLine(limitSet3)
}
let data: CombinedChartData = CombinedChartData(xVals: xValues)
data.lineData = LineChartData(xVals: xValues, dataSets: dataSets)
chartView.data = data
}
Now, I call the removeLimitLines before the setChart function and it works as expected.
EDIT:
you can also just simply call:
chartView.leftAxis.removeAllLimitLines()

Related

Displaying Data in ios Charts

I am creating an ios Chart that is based off of documents in Firestore. Here is my code:
import UIKit
import Charts
import Firebase
import FirebaseFirestoreSwift
import FirebaseAuth
class YearChartViewController: UIViewController, ChartViewDelegate {
enum valetTimeCategory: String{
typealias RawValue = String
case Year = "Year"
case Month = "Month"
case DaysOfWeeks = "Day1"
case CalendarDays = "Day2"
case Hour = "Hour"
}
var selectedCategory = valetTimeCategory.Year.rawValue
private var yearListener: ListenerRegistration!
#IBOutlet weak var segmentedController: UISegmentedControl!
var timeRetrieval = [timeData]()
var timeRetrievalYear = [yearTimeData]()
var barChart = BarChartView()
var pieChart = PieChartView()
lazy var companyUser = ""
#IBOutlet weak var localeIdLabel: UILabel!
private var timeDataCollection: CollectionReference!
var documentName1 = ""
override func viewDidLoad() {
super.viewDidLoad()
barChart.delegate = self
pieChart.delegate = self
localeIdLabel.text = companyUser
timeDataCollection = Firestore.firestore().collection("users").document(companyUser ).collection("time_data")
}
#IBAction func valetTimeCategory3(_ sender: Any) {
switch segmentedController.selectedSegmentIndex {
case 0:
selectedCategory = valetTimeCategory.Year.rawValue
case 1:
selectedCategory = valetTimeCategory.Month.rawValue
case 2:
selectedCategory = valetTimeCategory.DaysOfWeeks.rawValue
case 3: selectedCategory = valetTimeCategory.CalendarDays.rawValue
case 4: selectedCategory = valetTimeCategory.Hour.rawValue
default:
valetTimeCategory.Year.rawValue
}
self.yearListener.remove()
setListener()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setListener()
}
func setListener() {
barChart.frame = CGRect(x: 0, y: 0, width: 250, height: 250)
barChart.center = view.center
view.addSubview(barChart)
var entries = [BarChartDataEntry]()
yearListener = timeDataCollection.whereField(selectedCategory, isNotEqualTo: "Yaguay").order(by: selectedCategory).addSnapshotListener{ (querySnapshot, error) in
if let err = error {
debugPrint("Error fetching docs: \(err)")
} else {
self.timeRetrieval.removeAll()
guard let snap = querySnapshot else { return }
for document in snap.documents {
let FirebaseData = document.data()
let tiempoEs1 = FirebaseData["Year"] as? String ?? ""
let tiempoEs2 = FirebaseData["Month"] as? String ?? ""
let tiempoEs3 = FirebaseData["Day1"] as? String ?? ""
let tiempoEs4 = FirebaseData["Hour"] as? String ?? ""
let tiempoEs5 = FirebaseData["Day2"] as? String ?? ""
let documentIdThird = document.documentID
let newTimeRetrieval = timeData(timeContinuum1: tiempoEs1, timeContinuum2: tiempoEs2, timeContinuum3: tiempoEs3, timeContinuum4: tiempoEs4, timeContinuum5: tiempoEs5, documentId3: documentIdThird);
let newYearRetrieval = yearTimeData(timeContinuumYear: tiempoEs1)
self.timeRetrieval.append(newTimeRetrieval)
self.timeRetrievalYear.append(newYearRetrieval);
if self.selectedCategory == valetTimeCategory.Year.rawValue {
let q = Int(tiempoEs1)
let b = q?.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(q!), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries
)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
let format = NumberFormatter()
format.numberStyle = .decimal
let formatter = DefaultValueFormatter(formatter: format)
data.setValueFormatter(formatter)
self.barChart.legendRenderer.computeLegend(data: BarChartData(dataSet: set))
self.barChart.chartDescription?.text = "Years"
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.Month.rawValue {
let d = tiempoEs2.hashValue.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(d), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.DaysOfWeeks.rawValue {
let d = tiempoEs3.hashValue.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(d), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.CalendarDays.rawValue {
let q = Int(tiempoEs5)
let b = q?.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(b!), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
if self.selectedCategory == valetTimeCategory.Hour.rawValue {
let q = tiempoEs4.hashValue.nonzeroBitCount
entries.append(BarChartDataEntry(x: Double(q), y: Double(self.timeRetrieval.count)));
let set = BarChartDataSet(entries: entries, label: "\(self.selectedCategory)"
)
print(self.selectedCategory)
set.colors = ChartColorTemplates.joyful()
let data = BarChartData(dataSet: set)
self.barChart.data = data
self.yearListener.remove()
}
}
}
}
}
#IBAction func monthButton1Tapped(_ sender: Any) {
self.companyUser = localeIdLabel.text!
performSegue(withIdentifier: "Month", sender: self)
}
#IBAction func logout(_ sender: Any) {
let auth = Auth.auth()
do {
try auth.signOut()
transitionToHome()
} catch let signOutError as Error {
debugPrint(signOutError)
}
}
func transitionToHome() {
let homeViewController = storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController)
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! MonthChartViewController
vc.documentName = self.companyUser
}
}
Hopefully the random, nonsensical names aren't too distracting, but my problem is my Bar Chart isn't exactly displaying the right data. When I run the code, it displays:
Chart Image
There are 22 items (documents) in my collection. So it explicitly displays 22 objects, and if you count the numbers on each bar, the count on each bar is the correct number in each category (5 for 2020 and 17 for 2021). I don't know how to get my bar chart to explicitly display "17" and "5" for each category, please help if you know how to solve this.
timeRetrieval is appending additional entries each loop without clearing the previous entries. This is why the second bar has exactly the sum total.
You have a line self.timeRetrieval.removeAll() that is above the start of your for loop. Moving this line inside the loop should resolve this behavior.

ios-charts xaxis labels not lining up

I have created a grouped bar chart with pretty simple values. I have 5 labels which I would like spread out along the xaxis and 3 bar groups to coincide with each xaxis label.
The graph right now shows 1 xaxis label and 1 bar. (they may be out of frame, it's hard to tell.) I need each case to sync up with the correct msArrayAxis label.
Here is the code:
var msArrayXAxis = ["0-20", "20-50", "50-100", "100-200", "<200"]
barchartView.isUserInteractionEnabled = false
barchartView.noDataText = "You need to provide data for the chart."
barchartView.legend.enabled = false
barchartView.chartDescription?.text = ""
barchartView.xAxis.labelPosition = XAxis.LabelPosition.bottom
barchartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: msArrayXAxis)
barchartView.xAxis.axisMinimum = 0
barchartView.xAxis.granularity = 2
barchartView.xAxis.setLabelCount(5, force: true)
barchartView.xAxis.spaceMin = 0.3
// barchartView.extraBottomOffset = 1
barchartView.xAxis.labelWidth = 1
barchartView.xAxis.avoidFirstLastClippingEnabled = true
barchartView.rightAxis.drawGridLinesEnabled = false
barchartView.rightAxis.drawAxisLineEnabled = false
barchartView.rightAxis.drawLabelsEnabled = false
func parsedArrayCount(case1: Array<Double>,case2: Array<Double>,case3: Array<Double>,case4: Array<Double>, case5: Array<Double>) -> [BarChartDataEntry] {
var dataEntries1: [BarChartDataEntry] = []
NSLog("Parsing array count")
let dataEntry = BarChartDataEntry(x: Double(0), y:Double(case1.count))
dataEntries1.append(dataEntry)
let dataEntry2 = BarChartDataEntry(x: Double(1), y:Double(case2.count))
dataEntries1.append(dataEntry2)
let dataEntry3 = BarChartDataEntry(x: Double(2), y:Double(case3.count))
dataEntries1.append(dataEntry3)
let dataEntry4 = BarChartDataEntry(x: Double(3), y:Double(case4.count))
dataEntries1.append(dataEntry4)
let dataEntry5 = BarChartDataEntry(x: Double(1), y:Double(case5.count))
dataEntries1.append(dataEntry5)
return dataEntries1
}
func updateGraph(array: Array<name>?) {
var dataEntries1: [BarChartDataEntry] = []
var dataEntries2: [BarChartDataEntry] = []
var dataEntries3: [BarChartDataEntry] = []
barchartView.clear()
rArray.removeAll()
nameArray.removeAll()
if array != nil && array!.count > 0 {
for i in 0..<array!.count {
rArray.append(array![i].r)
nameArray.append(array![i].name)
}
NSLog("updating graph..")
let name = Analyzer.sharedInstance.nameArray(names: rArray.map{String($0)}, Name: nameArray)
let cData = parserArrays(rArray: name.first.map {Double($0)!})
let wData = parserArrays(rArray: name.last.map {Double($0)!})
let vData = parserArrays(rArray: name.middle.map {Double($0)!})
dataEntries1 = parsedArrayCount(case1: cData.case1, case2: cData.case2, case3: cData.case3, case4: cData.case4, case5: cData.case5)
dataEntries2 = parsedArrayCount(case1: wData.case1, case2: wData.case2, case3: wData.case3, case4: wData.case4, case5: wData.case5)
dataEntries3 = parsedArrayCount(case1: vData.case1, case2: vData.case2, case3: vData.case3, case4: vData.case4, case5: vData.case5)
let chartDataSet = BarChartDataSet(values: dataEntries1, label: "")
chartDataSet.colors = [UIColor.Blue()]
let chartDataSet1 = BarChartDataSet(values: dataEntries2, label: "")
chartDataSet1.colors = [UIColor.Green()]
let chartDataSet2 = BarChartDataSet(values: dataEntries3, label: "")
chartDataSet2.colors = [UIColor.Orange()]
NSLog("Data set1 \(dataEntries1)")
let groupSpace = 1.0
let barSpace = 0.05
let barWidth = 0.1
/* let xAxis = XAxis()
xAxis.valueFormatter = self
xAxis.drawGridLinesEnabled = true
xAxis.labelPosition = .bottom
xAxis.centerAxisLabelsEnabled = true
barchartView.xAxis.valueFormatter = xAxis.valueFormatter*/
let dataSets: [BarChartDataSet] = [chartDataSet,chartDataSet1]
let chartData = BarChartData(dataSets: dataSets)
chartData.setDrawValues(false)
chartData.barWidth = barWidth
chartData.groupBars(fromX:0.3, groupSpace: groupSpace, barSpace: barSpace)
// let gg = chartData.groupWidth(groupSpace: groupSpace, barSpace: barSpace)
// barchartView.xAxis.axisMaximum = Double(0) + gg * Double(msArrayXAxis.count)
barchartView.data = chartData
barchartView.animate(yAxisDuration: 0.5)
}
}
Please check :
var msArrayXAxis = ["0-20", "20-50", "50-100", "100-200", "<200"]
barChartView.isUserInteractionEnabled = false
barChartView.noDataText = "You need to provide data for the chart."
barChartView.legend.enabled = false
barChartView.chartDescription?.text = ""
barChartView.xAxis.labelPosition = XAxis.LabelPosition.bottom
barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: msArrayXAxis)
barChartView.xAxis.axisMinimum = 0
barChartView.xAxis.granularity = 1
barChartView.xAxis.labelCount = msArrayXAxis.count
barChartView.xAxis.centerAxisLabelsEnabled = true
barChartView.xAxis.spaceMin = 0.3
barChartView.xAxis.labelWidth = 1
barChartView.rightAxis.drawGridLinesEnabled = false
barChartView.rightAxis.drawAxisLineEnabled = false
barChartView.rightAxis.drawLabelsEnabled = false
func parsedArrayCount(case1: Array<Double>,case2: Array<Double>,case3: Array<Double>,case4: Array<Double>, case5: Array<Double>) -> [BarChartDataEntry] {
var dataEntries1: [BarChartDataEntry] = []
NSLog("Parsing array count")
let dataEntry = BarChartDataEntry(x: Double(0), y:Double(case1.count))
dataEntries1.append(dataEntry)
let dataEntry2 = BarChartDataEntry(x: Double(1), y:Double(case2.count))
dataEntries1.append(dataEntry2)
let dataEntry3 = BarChartDataEntry(x: Double(2), y:Double(case3.count))
dataEntries1.append(dataEntry3)
let dataEntry4 = BarChartDataEntry(x: Double(3), y:Double(case4.count))
dataEntries1.append(dataEntry4)
let dataEntry5 = BarChartDataEntry(x: Double(1), y:Double(case5.count))
dataEntries1.append(dataEntry5)
return dataEntries1
}
func updateGraph() {
var dataEntries1: [BarChartDataEntry] = []
var dataEntries2: [BarChartDataEntry] = []
var dataEntries3: [BarChartDataEntry] = []
barChartView.clear()
NSLog("updating graph..")
let name = Analyzer.sharedInstance.nameArray(names: rArray.map{String($0)}, Name: nameArray)
let cData = parserArrays(rArray: name.first.map {Double($0)!})
let wData = parserArrays(rArray: name.last.map {Double($0)!})
let vData = parserArrays(rArray: name.middle.map {Double($0)!})
dataEntries1 = parsedArrayCount(case1: cData.case1, case2: cData.case2, case3: cData.case3, case4: cData.case4, case5: cData.case5)
dataEntries2 = parsedArrayCount(case1: wData.case1, case2: wData.case2, case3: wData.case3, case4: wData.case4, case5: wData.case5)
dataEntries3 = parsedArrayCount(case1: vData.case1, case2: vData.case2, case3: vData.case3, case4: vData.case4, case5: vData.case5)
let chartDataSet = BarChartDataSet(values: dataEntries1, label: "")
chartDataSet.colors = [UIColor.blue]
let chartDataSet1 = BarChartDataSet(values: dataEntries2, label: "")
chartDataSet1.colors = [UIColor.green]
let chartDataSet2 = BarChartDataSet(values: dataEntries3, label: "")
chartDataSet2.colors = [UIColor.orange]
NSLog("Data set1 \(dataEntries1)")
let groupSpace = 0.1
let barSpace = 0.05
let barWidth = 0.25
let dataSets: [BarChartDataSet] = [chartDataSet,chartDataSet1, chartDataSet2]
let chartData = BarChartData(dataSets: dataSets)
chartData.setDrawValues(false)
chartData.barWidth = barWidth
let gg = chartData.groupWidth(groupSpace: groupSpace, barSpace: barSpace)
barChartView.xAxis.axisMaximum = Double(0) + gg * Double(msArrayXAxis.count)
chartData.groupBars(fromX:0.0, groupSpace: groupSpace, barSpace: barSpace)
barChartView.notifyDataSetChanged()
barChartView.data = chartData
barChartView.animate(yAxisDuration: 0.5)
}

Swift - iOS Charts - Two LineChart views using Two datasets in one ViewController

I have an app where I'm getting some data from Firebase by days and I'm trying to display each day's data in a separate chart, using iOS Charts, but it crashes with an error 'fatal error: Index out of range'. Below is my code:
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Units Sold")
let lineChartData = LineChartData(xVals: dataPoints, dataSet: lineChartDataSet)
firstDayChart.data = lineChartData
}
func setChart2(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Units Sold")
let lineChartData = LineChartData(xVals: dataPoints, dataSet: lineChartDataSet)
secondDayChart.data = lineChartData
}
//BUTTON
#IBAction func getResults(sender: UIButton) {
let doubleArray = BGdataOutsideDay1.map { Double($0)!}
// print(doubleArray)
// var newArray:[Double] = []
self.doublesArrayDay1 = doubleArray
if doublesArrayDay1.count != 0 {
let bgAvg = doubleArray.reduce(0, combine: +) / Double(doubleArray.count)
let highest = doubleArray.maxElement()
let lowest = doubleArray.minElement()
self.bgHighestDay1 = String(format: "%.1f", highest!)
self.bgAvgDay1 = String(format: "%.1f", bgAvg)
self.bgLowestDay1 = String(format: "%.1f", lowest!)
self.firstDayHighest.text = self.bgHighestDay1! + " " + "\(self.units!)"
self.firstDayAvg.text = self.bgAvgDay1! + " " + "\(self.units!)"
self.firstDayLowest.text = self.bgLowestDay1! + " " + "\(self.units!)"
} else {
self.firstDayHighest.text = "0" + " " + "\(self.units!)"
self.firstDayAvg.text = "0" + " " + "\(self.units!)"
self.firstDayLowest.text = "0" + " " + "\(self.units!)"
}
let doubleArray2 = BGdataOutsideDay2.map { Double($0)!}
// print(doubleArray)
// var newArray:[Double] = []
self.doublesArrayDay2 = doubleArray
if doublesArrayDay2.count != 0 {
let bgAvg2 = doubleArray2.reduce(0, combine: +) / Double(doubleArray.count)
let highest2 = doubleArray2.maxElement()
let lowest2 = doubleArray2.minElement()
self.bgHighestDay2 = String(format: "%.1f", highest2!)
self.bgAvgDay2 = String(format: "%.1f", bgAvg2)
self.bgLowestDay2 = String(format: "%.1f", lowest2!)
self.secondDayHighest.text = self.bgHighestDay2! + " " + "\(self.units!)"
self.secondDayAvg.text = self.bgAvgDay2! + " " + "\(self.units!)"
self.secondDayLowest.text = self.bgLowestDay2! + " " + "\(self.units!)"
} else {
self.secondDayHighest.text = "0" + " " + "\(self.units!)"
self.secondDayAvg.text = "0" + " " + "\(self.units!)"
self.secondDayLowest.text = "0" + " " + "\(self.units!)"
setChart(DateOutSideDay1, values: doublesArrayDay1)
setChart(DateOutSideDay2, values: doublesArrayDay2)
}
Any help would be greatly appreciated! Thanks in advance! :)
First of all i think it's weird that you have a set of data points and another set of values, but they aren't the same size? Imo those sets should be the same size since the values represent the data points.
Anywho..
You can fix this issue by replacing let dataEntry = ChartDataEntry(value: values[i], xIndex: i) with let dataEntry = ChartDataEntry(value: i < values.count ? values[i] : 0, xIndex: i)
You can define a default value to be used when there's no value available at that index in the values array, I set it to 0.

Getting the right interval on the x-axis in IOS-Charts

I am trying to exclusively display the points which I have data for on the x-axis. As shown in the example below, I only got data for point zero, but -1 and 1 are being displayed as well. How can I get rid of them?
func setChart(_ xValues: [String], yValuesLineChart: [Double], yValuesBarChart: [Double]) {
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
var yVals2 : [BarChartDataEntry] = [BarChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(x: Double(i), y: yValuesLineChart[i]))
yVals2.append(BarChartDataEntry(x: Double(i), y: yValuesBarChart[i]))
}
let lineChartSet = LineChartDataSet(values: yVals1, label: "")
let barChartSet: BarChartDataSet = BarChartDataSet(values: yVals2, label: "")
combinedChartView.drawBarShadowEnabled = false
let data = CombinedChartData()
data.barData = BarChartData(dataSet: barChartSet)
data.lineData = LineChartData(dataSet: lineChartSet)
combinedChartView.xAxis.granularityEnabled = true
combinedChartView.xAxis.granularity = 1.0
combinedChartView.xAxis.decimals = 0
combinedChartView.leftAxis.axisMinimum = 0
combinedChartView.rightAxis.axisMinimum = 0
combinedChartView.chartDescription?.text = ""
combinedChartView.drawGridBackgroundEnabled = false
combinedChartView.xAxis.labelPosition = .bottom
combinedChartView.leftAxis.drawGridLinesEnabled = false
combinedChartView.rightAxis.drawGridLinesEnabled = false
combinedChartView.xAxis.drawGridLinesEnabled = false
combinedChartView.leftAxis.drawZeroLineEnabled = false
combinedChartView.rightAxis.drawZeroLineEnabled = false
barChartSet.axisDependency = .right
lineChartSet.axisDependency = .left
combinedChartView.rightAxis.axisMaximum = barChartSet.yMax*1.4
combinedChartView.leftAxis.axisMaximum = lineChartSet.yMax*1.2
combinedChartView.data = data
combinedChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInCubic)
}
Write an extension for your ViewController that will just display an empty string if you have no value.
extension YourChartViewController:IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if value == 0.0
return ""
} else {
return String(Int(value))
}
}
}

Combined Charts. Swift 2.2

I am trying to create a lineChart ontop of a Bar chart. I have the following code so far:
class AnalysisViewController: UIViewController, ChartViewDelegate {
func setChart(xValues: [String], valuesBarChart: [Double], valuesLineChart: [Double]) {
barChartView.descriptionText = ""
barChartView.noDataText = "You need to provide data for the chart."
var yValsBarChart: [BarChartDataEntry] = []
var yValsLineChart : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<xValues.count {
yValsBarChart.append(BarChartDataEntry(value: valuesBarChart[i], xIndex: i))
yValsLineChart.append(ChartDataEntry(value: valuesLineChart[i] - 1, xIndex: i))
}
let lineChartDataSet = LineChartDataSet(yVals: yValsLineChart, label: nil)
let barChartDataSet = BarChartDataSet(yVals: yValsBarChart, label: nil)
let data: CombinedChartData = CombinedChartData(xVals: xValues)
data.barData = BarChartData(xVals: xValues, dataSets: [barChartDataSet])
data.lineData = LineChartData(xVals: xValues, dataSets: [lineChartDataSet])
barChartView.data = data
barChartView.leftAxis.customAxisMin = 0
UniversalStatic.data.generateColoursForGraph(budgetName.count)
barChartDataSet.colors = UniversalStatic.data.colourArrayForGraph
setDesignChart()
}
}
I am getting the following error on the terminal:
Could not cast value of type 'Charts.CombinedChartData' (0x3d5d70) to 'Charts.BarChartData' (0x3cfc54).
as well as:
I don't really know what i have done wrong as I haven't touched the 'BarChartView' where the error is appearing.
Any help would be appreciated :)
As i initially created the BarChart first and then tried to add the line chart, i forgot to change the view from a BarChartView to a CombinedChartView!