Search code examples
swiftios-charts

How to Setup Data According to weekdays in iOS Bar Chart


I am working on a project of step counter, Where I have to implement the functionality to store the current day steps and append it to ios bar chart data according to the day names. Basically I want to represent the total step counts on the daily weekday basis on ios Bar Chart. It will be very helpful if I get some example code or any hint to append daily steps According to the day name.

Here is my code:-

import UIKit
import Charts

enum WeekDayName: String {
    case Sunday = "Sun"
    case Monday = "Mon"
    case Tuesday = "Tue"
    case Wednesday = "Wed"
    case Thursday = "Thu"
    case Friday = "Fri"
    case Saturday = "Sat"

}

class HistoryViewController: UIViewController,ChartViewDelegate {

    @IBOutlet weak var barChartView: BarChartView!

    var todayName:String!
    let week = ["Sun", "Mon", "Tue", "Wed","Thu", "Fri", "Sat"]
//    let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0, 4.0, 18.0, 2.0, 4.0, 5.0, 4.0]
    let staticSteps = [200, 400, 600, 300, 1200, 1600, 400]

    override func viewDidLoad() {
        super.viewDidLoad()

        getCurrentDayName()

        setup(barLineChartView: barChartView)
    }

    //MARK: Get Current Day Name
    func getCurrentDayName(){
        let weekday = Calendar.current.component(.weekday, from: Date())
        print(weekday)
        switch weekday {
        case 1:
           todayName = WeekDayName.Sunday.rawValue
        case 2:
           todayName = WeekDayName.Monday.rawValue
        case 3:
           todayName = WeekDayName.Tuesday.rawValue
        case 4:
           todayName = WeekDayName.Wednesday.rawValue
        case 5:
           todayName = WeekDayName.Thursday.rawValue
        case 6:
           todayName = WeekDayName.Friday.rawValue
        case 7:
           todayName = WeekDayName.Saturday.rawValue
        default:
            print("nothng")
        }
        print(todayName)
    }


    func setup(barLineChartView chartView: BarChartView) {
        chartView.chartDescription?.enabled = false

        chartView.isUserInteractionEnabled = false //Disables the selection for bar charts
        chartView.dragEnabled = true
        chartView.setScaleEnabled(false) //turn off scaling /kinda pinch zoom type
        chartView.pinchZoomEnabled = false //disables pinch zoom


        let xAxis = chartView.xAxis
        xAxis.labelPosition = .bottom
        xAxis.labelFont = .systemFont(ofSize: 10)

        //hides grid
        xAxis.drawGridLinesEnabled = false


        chartView.xAxis.valueFormatter = WeekValueFormatter()



        xAxis.labelCount = 7
        chartView.animate(yAxisDuration: 3)      
       chartView.rightAxis.enabled = false

        let leftAxisFormatter = NumberFormatter()
        leftAxisFormatter.minimumFractionDigits = 0
        leftAxisFormatter.maximumFractionDigits = 1

        let leftAxis = chartView.leftAxis
        leftAxis.labelFont = .systemFont(ofSize: 10)
        leftAxis.labelCount = 8
        leftAxis.valueFormatter = DefaultAxisValueFormatter(formatter: leftAxisFormatter)
        leftAxis.labelPosition = .outsideChart
        leftAxis.spaceTop = 0.15
        leftAxis.axisMinimum = 0 // FIXME: HUH?? this replaces startAtZero = YES


        let l = chartView.legend
        l.horizontalAlignment = .left
        l.verticalAlignment = .bottom
        l.orientation = .horizontal
        l.drawInside = false
        l.form = .circle
        l.formSize = 9
        l.font = UIFont(name: "HelveticaNeue-Light", size: 11)!
        l.xEntrySpace = 4

        //setChart(dataPoints: months, values: unitsSold.map { Double($0) })
        setChart(dataPoints: week, values: staticSteps)
    }

    func setChart(dataPoints: [String], values: [Int]) {
        barChartView.noDataText = "You need to provide data for the chart."

        var dataEntries: [BarChartDataEntry] = []

        for i in 0..<dataPoints.count {
            let dataEntry = BarChartDataEntry(x: Double(i), y: Double(values[i]))
            dataEntries.append(dataEntry)
        }

        let chartDataSet = BarChartDataSet(entries: dataEntries, label: "BeWell Workout Chart")
        chartDataSet.colors = ChartColorTemplates.colorful()
        let chartData = BarChartData(dataSet: chartDataSet)
        barChartView.data = chartData
    }



//MARK: Weeks Bottom Label Class for x-Axis labels
public class WeekValueFormatter: NSObject, IAxisValueFormatter {

    override init() {
        super.init()
    }

    public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        let weekday = Calendar.current.component(.weekday, from: Date())
        let week = ["Sun", "Mon", "Tue", "Wed","Thu", "Fri", "Sat"]

        return week[Int(value)]
    }
}

Solution

  • Assuming that

    • Your week is only 1 week at a time, so no day String repeats in the bar chart and
    • The day Strings in week stay in order (are never randomly sorted)...

    You can create a new Int for your Bar Chart's dataSet that has the values of weekdays that have passed and today, with 0 values for upcoming days like this:

    func createNewArray() -> [Int] {
    
        var stepsThisWeek = [Int]()
    
        // use todays day to find the index of where it appears in var week=[String]()
        if let todayIndex = week.firstIndex(of: getCurrentDayName()) {
    
            // create indices range of 0 to todayIndex
            let daysSoFarIndices = [Int](0...todayIndex)
    
            // create new array of var staticSteps=[Int]() at daysSoFarIndices
            stepsThisWeek = daysSoFarIndices.map { staticSteps[$0] }
    
            //create indices from todayIndex +1 to lastIndex of var staticSteps=[Int]()
            let daysLaterInWeek = [Int](todayIndex..<staticSteps.endIndex)
            //add 0 values for each daysLaterInWeek remaining
            for _ in daysLaterInWeek {
                stepsThisWeek.append(0)
            }
        }
        return stepsThisWeek
    }
    

    Then you can call this method where you set your Bar Chart's values like:

    setChart(dataPoints: week, values: createNewArray())
    

    Today is Monday, so your bar chart will appear like this.