Search code examples
xcodeplotswiftuichartsswiftui-charts

How do I display dates along X axis using Charts in SwiftUI?


I am having some trouble using the Charts framework in SwiftUI. Everything plots as expected, however the x axis does not show the dates for each point. The Y axis is working and shows the weight values along the Y axis. dateCompleted is of type Date().

             Chart(exerciseMaxRepsArray) { e in
                                    LineMark(x: .value("Date", e.dateCompleted),                                         
                                             y: .value("Reps", e.reps)                                             
                                    )}

I've tried to use dateFormatter and plot it as a string, i've tried to specify

LineMark(x: .value("Date", e.dateCompleted, unit: .day),                                         
         y: .value("Reps", e.reps))}                                                                            

But nothing is working to show the date values. I've ensured that the dates are populated and that the frame is large enough so they're not being cut out. Any help would be greatly appreciated. Thanks!!!

This is what the graph looks like in the simulator: simulator screen

EDITED :

GroupBox(label: Text("Daily Max Reps"){
 Chart(exerciseMaxRepsArray) { e in
    LineMark(x: .value("Date", e.dateCompleted, unit: .day),
 y: .value("Reps", e.reps)
 ) } 
.chartYAxisLabel(position: .trailing, alignment: .center) {
   Text("Reps")
 }
.chartXAxisLabel(position: .bottom, alignment: .center) {
 Text("Date")
}
.padding()
 } .groupBoxStyle(BackgroundGroupBoxStyle()) 

EDIT :

//
//  ExerciseDetailView.swift
//  WorkoutTrackerTrial
//
//  Created by Rachel Scott on 12/7/22.
//

import SwiftUI
import Charts


struct ExerciseDetailView: View {
    
    @FetchRequest var exercisesets: FetchedResults<ExerciseSet>
    
    var exercise: String

    init(exercise: String) {
        self.exercise = exercise
        self._exercisesets = FetchRequest(
            entity: ExerciseSet.entity(),
            sortDescriptors: [],
            predicate: NSPredicate(format: "exercisename == %@", exercise as any CVarArg)
        )
    }
        
    var exerciseMaxRepsArray: [ExerciseSet] {
        var seenDates: Set<Date> = []
        return exercisesets
            .sorted { $0.reps > $1.reps } // you can skip this line if already sorted by weight in the @fetchrequest
            .filter { seenDates.insert($0.dateCompleted.startOfDay).inserted }
            .sorted { $0.dateCompleted < $1.dateCompleted }
    }
    
    var body: some View {
        
        if #available(iOS 16.0, *) {
            ZStack{
                CustomColor.backgroundColor.edgesIgnoringSafeArea(.all)
                // for weights on that day, return from largest to smallest and use highest from that day
                
                VStack {
                    Text(exercise)
                        .font(Font.custom("Montserrat-SemiBold", size: 24))
                        .foregroundColor(CustomColor.darkGreen)
                        .background(CustomColor.backgroundColor)

                        GroupBox(label: Text("Daily Max Reps")
                            .font(Font.custom("Montserrat-SemiBold", size: 18))
                            .foregroundColor(CustomColor.darkGreen)) {
                                
                                
                                Chart(exerciseMaxRepsArray) { e in
                                    LineMark(x: .value("Date", e.dateCompleted, unit: .day),
                                             y: .value("Reps", e.reps)
                                             
                                    ).foregroundStyle(CustomColor.lightGreen)
                                }
                                .chartYAxisLabel(position: .trailing, alignment: .center) {
                                    Text("Reps")
                                        .font(Font.custom("Montserrat-Medium", size: 16))
                                        .foregroundColor(CustomColor.darkGreen)
                                }
                                .chartXAxisLabel(position: .bottom, alignment: .center) {
                                    Text("Date")
                                        .font(Font.custom("Montserrat-Medium", size: 16))
                                        .foregroundColor(CustomColor.darkGreen)
                                }
                                .padding()
                            } .groupBoxStyle(BackgroundGroupBoxStyle()) //.background(CustomColor.backgroundColor)
                    }
                    
                }
                
                
            }
        }
    }
    





Solution

  • It works fine with me, might me something in the model data code?

    Here is my working example:

    enter image description here

    struct Exercise: Identifiable {
        let id = UUID()
        var dateCompleted: Date
        var reps: Int
    }
    
    
    struct ContentView: View {
        
        private var exerciseMaxRepsArray: [Exercise] = []
    
        init() { // init dummy data
            for i in 0 ..< 10 {
                let date = Calendar.current.date(byAdding: .day, value: i, to: .now) ?? .now
                let rep = Int.random(in: 1...10)
                exerciseMaxRepsArray.append(
                    Exercise(dateCompleted: date, reps: rep)
                )
            }
        }
    
        var body: some View {
            
            GroupBox(label: Text("Daily Max Reps")) {
                Chart(exerciseMaxRepsArray) { e in
                    LineMark(x: .value("Date", e.dateCompleted, unit: .day),
                             y: .value("Reps", e.reps)
                    ) }
                .chartYAxisLabel(position: .trailing, alignment: .center) {
                    Text("Reps")
                }
                .chartXAxisLabel(position: .bottom, alignment: .center) {
                    Text("Date")
                }
                .padding()
            }
        }
    }