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()
Related
I have these buttons in my app so user can switch from light to dark mode in the app, how can I save this preference so whichever mode the user selected will still be active the next time they open the app?
I'm on Xcode 14.2
Code example please.
#IBAction func darkButton(_ sender: Any) {
overrideUserInterfaceStyle = .dark
}
#IBAction func lightButton(_ sender: Any) {
overrideUserInterfaceStyle = .light
}
Full code below
import UIKit
class ViewController: UIViewController {
// All Input Texts
#IBOutlet weak var machineODInputText: UITextField!
#IBOutlet weak var pipeODInputText: UITextField!
#IBOutlet weak var pipeLengthInputText: UITextField!
#IBOutlet weak var driveLengthInputText: UITextField!
#IBOutlet weak var muckUpInputText: UITextField!
#IBOutlet weak var jackingSpeedInputText: UITextField!
#IBOutlet weak var weightOfBenoBagInputText: UITextField!
#IBOutlet weak var noOfBenoBagsInputText: UITextField!
#IBOutlet weak var benoQtyForTanksInputText: UITextField!
#IBOutlet weak var noOfBenoBagsPerPalletInputText: UITextField!
// All Result Texts
#IBOutlet weak var lubricationPumpSpeedResult: UILabel!
#IBOutlet weak var volumePerMeterResult: UILabel!
#IBOutlet weak var volumePerPipeResult: UILabel!
#IBOutlet weak var volumeForDriveResult: UILabel!
#IBOutlet weak var benoQtyForLubricationResult: UILabel!
#IBOutlet weak var benoQtyForDriveResult: UILabel!
#IBOutlet weak var noOfPalletsForDriveResult: UILabel!
// All Buttons
#IBAction func lightButton(_ sender: Any) {
overrideUserInterfaceStyle = .light
UserDefaults.standard.set("light", forKey: "mode")
}
#IBAction func darkButton(_ sender: Any) {
overrideUserInterfaceStyle = .dark
UserDefaults.standard.set("dark", forKey: "mode")
}
#IBAction func calculateButton(_ sender: Any) {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 0
let formatter2 = NumberFormatter()
formatter2.numberStyle = .decimal
formatter2.maximumFractionDigits = 2
let pi = Double.pi / 4
let TBMOD = (Double(machineODInputText.text!) ?? 1) / 1000.0
let pipeOD = (Double(pipeODInputText.text!) ?? 1) / 1000.0
let muckup = (Double(muckUpInputText.text!) ?? 2.5)
let advanceSpeed = (Double(jackingSpeedInputText.text!) ?? 1)
let volPerPipe = (Double(pipeLengthInputText.text!) ?? 1)
let volForDrive = (Double(driveLengthInputText.text!) ?? 1)
let noOfBenoBagsForLub = (Double(noOfBenoBagsInputText.text!) ?? 1)
let weightOfEachBenoBag = (Double(weightOfBenoBagInputText.text!) ?? 1)
let amountOfBenoBagsInTamks = (Double(benoQtyForTanksInputText.text!) ?? 1)
let noOfBenoBagsPerPallet = (Double(noOfBenoBagsPerPalletInputText.text!) ?? 1)
// Calculate Volume per Meter (Ltr per meter)
let volPerMtrResults1 = ((pi * (TBMOD) * (TBMOD)) - (pi * (pipeOD) * (pipeOD))) * muckup * 1000
let volPerMtrResult = formatter.string (from: NSNumber(value: volPerMtrResults1))
volumePerMeterResult.text = volPerMtrResult
// Calculate Lubrication Pump Capacity (Ltr per min)
let pumpCapacityResults1 = (advanceSpeed / 1000) * volPerMtrResults1
let lubPerMtrResult = formatter.string(from: NSNumber(value: pumpCapacityResults1))
lubricationPumpSpeedResult.text = lubPerMtrResult
// Calculate Volume per pipe (M³ per pipe)
let volPerPipeResults1 = (volPerMtrResults1 / 1000) * volPerPipe
let volPerPipeResult = formatter2.string(from: NSNumber(value: volPerPipeResults1))
volumePerPipeResult.text = volPerPipeResult
// Calculate Volume for drive (M³ for drive)
let volPerDriveResults1 = (volPerMtrResults1 / 1000) * volForDrive
let volPerDriveResult = formatter.string(from: NSNumber(value: volPerDriveResults1))
volumeForDriveResult.text = volPerDriveResult
// Calculate Amount of beno for lubrication
let ammountOfBenoForLubResults1 = noOfBenoBagsForLub * volPerDriveResults1 * weightOfEachBenoBag
let ammountOfBenoForLubResult = formatter.string(from: NSNumber(value: ammountOfBenoForLubResults1))
benoQtyForLubricationResult.text = ammountOfBenoForLubResult
// Calculate beno quantity for drive
let amountOfBenoForDriveResults1 = ammountOfBenoForLubResults1 + (amountOfBenoBagsInTamks * 1000)
let amountOfBenoForDriveResult = formatter.string(from: NSNumber(value: amountOfBenoForDriveResults1))
benoQtyForDriveResult.text = amountOfBenoForDriveResult
// Calculate number of pallets for drive
let ammountOfBenoPerPalletResults1 = amountOfBenoForDriveResults1 / weightOfEachBenoBag / noOfBenoBagsPerPallet
let ammountOfBenoPerPalletResult = formatter2.string(from: NSNumber(value: ammountOfBenoPerPalletResults1))
noOfPalletsForDriveResult.text = ammountOfBenoPerPalletResult
UserDefaults.standard.set(machineODInputText.text, forKey: "TBMOD")
UserDefaults.standard.set(pipeODInputText.text, forKey: "pipeOD")
UserDefaults.standard.set(muckUpInputText.text, forKey: "muckUp")
UserDefaults.standard.set(jackingSpeedInputText.text, forKey: "speed")
UserDefaults.standard.set(pipeLengthInputText.text, forKey: "pipeLength")
UserDefaults.standard.set(driveLengthInputText.text, forKey: "driveLength")
UserDefaults.standard.set(noOfBenoBagsInputText.text, forKey: "noOfBenoBags")
UserDefaults.standard.set(weightOfBenoBagInputText.text, forKey: "weightOfBenoBag")
UserDefaults.standard.set(benoQtyForTanksInputText.text, forKey: "benoQtyForTanks")
UserDefaults.standard.set(noOfBenoBagsPerPalletInputText.text, forKey: "benoBagsPerPallet")
}
// Adding toolbar to top of keyboard with "Done" button (toolbar.swift file)
override func viewDidLoad() {
super.viewDidLoad()
machineODInputText.inputAccessoryView = toolBar()
pipeODInputText.inputAccessoryView = toolBar()
pipeLengthInputText.inputAccessoryView = toolBar()
driveLengthInputText.inputAccessoryView = toolBar()
muckUpInputText.inputAccessoryView = toolBar()
jackingSpeedInputText.inputAccessoryView = toolBar()
weightOfBenoBagInputText.inputAccessoryView = toolBar()
noOfBenoBagsInputText.inputAccessoryView = toolBar()
benoQtyForTanksInputText.inputAccessoryView = toolBar()
noOfBenoBagsPerPalletInputText.inputAccessoryView = toolBar()
}
// load old data into input feilds
override func viewDidAppear(_ animated: Bool) {
if let a = UserDefaults.standard.object(forKey: "TBMOD") as? String {
machineODInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "pipeOD") as? String {
pipeODInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "muckUp") as? String {
muckUpInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "speed") as? String {
jackingSpeedInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "pipeLength") as? String {
pipeLengthInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "driveLength") as? String {
driveLengthInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "noOfBenoBags") as? String {
noOfBenoBagsInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "weightOfBenoBag") as? String {
weightOfBenoBagInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "benoQtyForTanks") as? String {
benoQtyForTanksInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "benoBagsPerPallet") as? String {
noOfBenoBagsPerPalletInputText.text = a
}
// load dark/light mode last selected by user
let mode = UserDefaults.standard.string(forKey: "mode")
if mode == "dark" {
overrideUserInterfaceStyle = .dark
} else {
overrideUserInterfaceStyle = .light
}
machineODInputText.clearsOnBeginEditing = true
pipeODInputText.clearsOnBeginEditing = true
pipeLengthInputText.clearsOnBeginEditing = true
driveLengthInputText.clearsOnBeginEditing = true
muckUpInputText.clearsOnBeginEditing = true
jackingSpeedInputText.clearsOnBeginEditing = true
weightOfBenoBagInputText.clearsOnBeginEditing = true
noOfBenoBagsInputText.clearsOnBeginEditing = true
benoQtyForTanksInputText.clearsOnBeginEditing = true
noOfBenoBagsPerPalletInputText.clearsOnBeginEditing = true
}
}
you can save it in UserDefaults as follows.
#IBAction func darkButton(_ sender: Any) {
overrideUserInterfaceStyle = .dark
UserDefaults.standard.set("dark", forKey: "mode")
}
#IBAction func lightButton(_ sender: Any) {
overrideUserInterfaceStyle = .light
UserDefaults.standard.set("light", forKey: "mode")
}
When reopening the application do as follow.
let mode = UserDefaults.standard.string(forKey: "mode")
if mode == "dark" {
overrideUserInterfaceStyle = .dark
} else {
overrideUserInterfaceStyle = .light
}
Where you need to add the above code depends on your scenario. I suggest to add it inside AppDelegate -> didFinishLaunchingWithOptions.
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.
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 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!
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??