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!
Related
I want to show my data to LineCharts.
I have checked the Realm Studio, there is data saved in the Realm. It just doesn't show anything one the View.
Maybe something going wrong with my code.
import UIKit
import Charts
import RealmSwift
class GraphViewController: UIViewController {
#IBOutlet weak var linechart: LineChartView!
weak var axisFormatDelegate: IAxisValueFormatter?
override func viewDidLoad() {
super.viewDidLoad()
axisFormatDelegate = self
// Do any additional setup after loading the view.
//setLineGraph()
updateChartWithData()
}
func updateChartWithData() {
var dataEntries: [ChartDataEntry] = []
let scoreCounts = getScoreFromDatabase()
//let visitorCounts = getScoreFromDatabase()
for i in 0..<scoreCounts.count {
let timeIntervalForDate: TimeInterval = scoreCounts[i].exactdate.timeIntervalSince1970
let dataEntry = ChartDataEntry(x: Double(timeIntervalForDate), y: Double(scoreCounts[i].datesc))
dataEntries.append(dataEntry)
}
let chartDataSet = LineChartDataSet(entries: dataEntries, label: "Score count" )
linechart.data = LineChartData(dataSet: chartDataSet)
linechart.chartDescription?.text = "Your Score"
let xaxis = linechart.xAxis
xaxis.valueFormatter = axisFormatDelegate
}
func getScoreFromDatabase() -> Results<DateScore> {
let realm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "MyInMemoryRealm"))
return realm.objects(DateScore.self)
}
}
extension GraphViewController: IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY/MM/DD"
return dateFormatter.string(from: Date(timeIntervalSince1970: value))
}
}
Here is my Realm class
import Foundation
import RealmSwift
class DateScore: Object {
#objc dynamic var datesc : Int16 = 0
#objc dynamic var exactdate : Date = Date()
}
And I got error message below is this related?
[Unknown process name] CGAffineTransformInvert: singular matrix.
I am a beginner. Can anyone help me?
I am using the Charts library to show bar charts but it still shows nil. I have set the view as BarChartView.
#IBOutlet weak var barChartView: BarChartView!
func setChart() {
var dataEntries: [BarChartDataEntry] = []
for i in 0..<testArray.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: Double(testArray[i]))
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(entries: dataEntries, label: "logs")
let chartData = BarChartData(dataSet: chartDataSet)
barChartView.data = chartData
}
and I do call setChart() in viewDidLoad()
How to remove decimals from y values in iOS Charts?
Im using the latest iOS Charts release with Swift3
Thanks for every one who tried to help, here was the fix, adding the below code
let formatter = NumberFormatter()
formatter.numberStyle = .none
formatter.maximumFractionDigits = 0
formatter.multiplier = 1.0
chartData.valueFormatter = DefaultValueFormatter(formatter: formatter)
to the setBarChartData func
func setBarChartData(xValues: [String], yValues: [Double], label: String) {
var dataEntries: [BarChartDataEntry] = []
for i in 0..<yValues.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: yValues[i])
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(values: dataEntries, label: label)
let chartData = BarChartData(dataSet: chartDataSet)
let formatter = NumberFormatter()
formatter.numberStyle = .none
formatter.maximumFractionDigits = 0
formatter.multiplier = 1.0
chartData.valueFormatter = DefaultValueFormatter(formatter: formatter)
let chartFormatter = BarChartFormatter(labels: xValues)
let xAxis = XAxis()
xAxis.valueFormatter = chartFormatter
self.xAxis.valueFormatter = xAxis.valueFormatter
self.data = chartData
}
Could also use:
let format = NumberFormatter()
format.numberStyle = .none
let formatter = DefaultValueFormatter(formatter: format)
data.setValueFormatter(formatter)
You need to set delegate for value formatter in DataSet like below
Obj-C :
//DataSet 1
LineChartDataSet *set1 = [[LineChartDataSet alloc] initWithValues:values label:#"outstanding"];
set1.valueFormatter = self;
Use below delegate method for formatting your value :
#pragma mark - IChartValueFormatter
- (NSString * _Nonnull)stringForValue:(double)value entry:(ChartDataEntry * _Nonnull)entry dataSetIndex:(NSInteger)dataSetIndex viewPortHandler:(ChartViewPortHandler * _Nullable)viewPortHandler{
//Format your value what you want here
return [NSString stringWithFormat:#"%0.f",value];
}
Confirm Protocol :
#interface YourViewController ()<ChartViewDelegate,IChartValueFormatter>
For Swift you need to create Extension of BarChart and use below methods in it
Swift :
extension BarChartView {
private class BarChartFormatter: NSObject, IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return labels[Int(value)]
}
init(labels: [String]) {
super.init()
self.labels = labels
}
}
func setBarChartData(xValues: [String], yValues: [Double], label: String) {
var dataEntries: [BarChartDataEntry] = []
for i in 0..<yValues.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: yValues[i])
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(values: dataEntries, label: label)
let chartData = BarChartData(dataSet: chartDataSet)
let chartFormatter = BarChartFormatter(labels: xValues)
let xAxis = XAxis()
xAxis.valueFormatter = chartFormatter
self.xAxis.valueFormatter = xAxis.valueFormatter
self.data = chartData
}
}
Call Above Extension Method like this :
func setChart(){
let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
let unitsSold = [20.0, 4.0, 3.0, 6.0, 12.0, 16.0, 4.0, 18.0, 2.0, 4.0, 5.0, 4.0]
barChartView.setBarChartData(xValues: months, yValues: unitsSold, label: "Monthly Sales")
}
hope you will get your formatted value on line chart.
After lots of research and test. i was able to remove the decimal.
First unlock the pod chartViewBase
Remove two lines from the { } i.e 'digits' from chartViewBase pod.
Before:
if let formatter = defaultValueFormatter as? DefaultValueFormatter
{
// setup the formatter with a new number of digits
let digits = reference.decimalPlaces
formatter.decimals = digits
}
After:
if let formatter = defaultValueFormatter as? DefaultValueFormatter
{
}
It will look like following::
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()
I was doing a tutorial on AppCoda for iOS-charts the bar chart portion on the app worked fine but the pie chart portion crashes with the the error: fatal error: unexpectedly found nil while unwrapping a optional value. It crashes on this command pieChartView.data = pieChartData. Here is the 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 pieChartDataSet = PieChartDataSet(yVals: dataEntries)
let pieChartData = PieChartData(xVals: dataPoints, dataSet: pieChartDataSet)
pieChartDataSet.label = ""
pieChartView.data = pieChartData
var colors: [UIColor] = []
colors.append(UIColor.greenColor())
colors.append(UIColor.blueColor())
colors.append(UIColor.blackColor())
pieChartDataSet.colors = colors
}
anyone have any idea why??