在图表中创建日期条形图时处理无值的日期

问题描述 投票:0回答:1

部分数据有跳过日期,如下数据。

TrainingSession(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!, maxRM: 10.0, totalVolume: 0.0),
TrainingSession(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!, maxRM: 10.5, totalVolume: 105.0),
TrainingSession(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!, maxRM: 10.0, totalVolume: 100.0)

在这种情况下,图表不会显示相应日期的任何内容。如图所示。 enter image description here

是否可以通过仅显示有值的数据而不显示没有值的日期来创建连续图表? 我想创建一个仅包含日期和值的条形图。

源码如下

import SwiftUI
import Charts

struct TrainingSession {
    var date: Date
    var maxRM: Double
    var totalVolume: Double
}

struct GraphView: View {
    var sessions: [TrainingSession]

    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                // 最大RMのグラフ
                VStack(alignment: .leading) {
                    Text("最大RM")
                        .font(.headline)
                        .padding()
                    Chart(sessions, id: \.date) { session in
                        BarMark(
                            x: .value("Date", session.date),
                            y: .value("Max RM", session.maxRM)
                        )
                    }
                    .chartXAxis {
                        AxisMarks(values: .stride(by: .day, count:7)) // 日付の表示間隔を調整
                    }
                    .chartScrollableAxes(.horizontal) // 横スクロールを有効にする
                    .padding([.leading, .trailing, .bottom])
                }

                // 総負荷量のグラフ
                VStack(alignment: .leading) {
                    Text("総負荷量")
                        .font(.headline)
                        .padding()
                    Chart(sessions, id: \.date) { session in
                        BarMark(
                            x: .value("Date", session.date),
                            y: .value("Total Volume", session.totalVolume)
                        )
                    }
                    .chartXAxis {
                        AxisMarks(values: .stride(by: .day, count:7)) // 日付の表示間隔を調整
                    }
                    .chartScrollableAxes(.horizontal) // 横スクロールを有効にする
                    .padding([.leading, .trailing, .bottom])
                }
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        GraphView(sessions: sampleData)
    }

    var sampleData: [TrainingSession] {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
        return [
            TrainingSession(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!, maxRM: 10.0, totalVolume: 0.0),
            TrainingSession(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!, maxRM: 10.5, totalVolume: 105.0),
            TrainingSession(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!, maxRM: 10.0, totalVolume: 100.0)
        ]
    }
}

struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

swift swiftui charts
1个回答
0
投票

进行了以下修改,并且可以正常工作。

//
//  ContentView.swift
//  GraphSample
//
//  Created by 齋藤卓馬 on 2024/06/09.
//

import SwiftUI
import Charts
import Foundation

struct YearMonthDay: Plottable, Hashable {
    init?(primitivePlottable: String) {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        guard let date = formatter.date(from: primitivePlottable) else {
            return nil
        }
        let calendar = Calendar.current
        self.year = calendar.component(.year, from: date)
        self.month = calendar.component(.month, from: date)
        self.day = calendar.component(.day, from: date)
    }
    
    let year: Int
    let month: Int
    let day: Int
    
    init(date: Date) {
        let calendar = Calendar.current
        self.year = calendar.component(.year, from: date)
        self.month = calendar.component(.month, from: date)
        self.day = calendar.component(.day, from: date)
    }
    
    var primitivePlottable: String {
        let dateComponents = DateComponents(year: year, month: month, day: day)
        let date = Calendar.current.date(from: dateComponents)!
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter.string(from: date)
    }
}


struct TrainingSession {
    var date: YearMonthDay
    var maxRM: Double
    var totalVolume: Double
}

struct GraphView: View {
    var sessions: [TrainingSession]
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                // 最大RMのグラフ
                VStack(alignment: .leading) {
                    Text("最大RM")
                        .font(.headline)
                        .padding()
                    Chart(sessions, id: \.date) { session in
                        BarMark(
                            x: .value("Date", session.date.primitivePlottable),
                            y: .value("Max RM", session.maxRM)
                        )
                    }
                    .chartXAxis {
                        AxisMarks(values: .automatic) { value in
                            AxisValueLabel {
                                Text(value.as(YearMonthDay.self)?.primitivePlottable ?? "")
                            }
                        }
                    }
                    .chartScrollableAxes(.horizontal)
                    .padding([.leading, .trailing, .bottom])
                }
                
                // 総負荷量のグラフ
                VStack(alignment: .leading) {
                    Text("総負荷量")
                        .font(.headline)
                        .padding()
                    Chart(sessions, id: \.date) { session in
                        BarMark(
                            x: .value("Date", session.date.primitivePlottable),
                            y: .value("Total Volume", session.totalVolume)
                        )
                    }
                    .chartXAxis {
                        AxisMarks(values: .automatic) { value in
                            AxisValueLabel {
                                Text(value.as(YearMonthDay.self)?.primitivePlottable ?? "")
                            }
                        }
                    }
                    .chartScrollableAxes(.horizontal)
                    .padding([.leading, .trailing, .bottom])
                }
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
                    ScrollView(.horizontal) {
                        HStack {
                            GraphView(sessions: sampleData)
                                .frame(width: UIScreen.main.bounds.width) // 画面の幅に合わせる
                        }
                    }
                    .navigationTitle("Training Data")
                }

    }
    
    var sampleData: [TrainingSession] {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
        return [
            TrainingSession(date: YearMonthDay(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!), maxRM: 10.0, totalVolume: 0.0),
            TrainingSession(date: YearMonthDay(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!), maxRM: 10.5, totalVolume: 105.0),
            TrainingSession(date: YearMonthDay(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!), maxRM: 10.0, totalVolume: 100.0)
        ]
    }
    
}

struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.