Post

Replies

Boosts

Views

Activity

Reply to .chartXScale not scaling domain of Chart as expected
[quote='795150022, AppleCare Staff, /thread/759244?answerId=795150022#795150022'] So just a few lines of code would be enough, I think it should fit in 20 lines or less. For data, you can inline an array of tuples as I described. No need for preview, extensions, structs etc. just a single Chart. [/quote] Apologies, I thought perhaps an example with a Preview would be beneficial for demonstration purposes. I'm happy to reduce the amount of code a bit. No more extra structs, previews or extensions! However, I can't really get it down to 20 lines if I am to simulate my issue. I need a month of measurements and I'm not sure I can even create the array of ~30 items (with plenty of Calendar.current operations) in 20 lines of code. I hope about 40 lines of code is okay! let cal: Calendar = .current struct ChartWithNilValues2: View { let start: Date = cal.date(from: cal.dateComponents([.year, .month], from: .now))! let end: Date init() { end = cal.date(byAdding: .month, value: 1, to: start)! } var body: some View { Chart(generateMeasurements(start: start, end: end), id: \.0) { measurement in if let total = measurement.1 { BarMark( x: .value("", measurement.0, unit: .weekOfYear, calendar: cal), y: .value("", total) ) } } .chartXAxis { AxisMarks(values: .stride(by: .weekOfYear)) { value in AxisValueLabel("\(value.index)", centered: true) } } .padding() .chartXScale(domain: start...end) } func generateMeasurements(start: Date, end: Date) -> [(Date, Double?)] { var measurements: [(Date, Double?)] = [] let dateComponents = cal.dateComponents([.day], from: start, to: end) guard let count = dateComponents.value(for: .day) else { return [] } for i in 0 ..< count { if let time = cal.date(byAdding: .day, value: i, to: start), time <= end { let production = i > count - 10 ? nil : Double.random(in: 0 ... 50) let measurement = (time, production) measurements.append(measurement) } } return measurements } } One thing that I observed trimming this down, is that if I move the definition of the end date from the init function to the struct definition, the problem seems to go away. 🤔 Hope that can be of some kind of assistance! Final note: I'm in Stockholm, Sweden. So Calendar.current is Central European Time for me, if that makes a difference in your assessment.
Jul ’24
Reply to .chartXScale not scaling domain of Chart as expected
[quote='794978022, AppleCare Staff, /thread/759244?answerId=794978022#794978022'] No need for an entire repo, just a minimal, but runnable example that exhibits the issue. [/quote] Alright! This should do: import SwiftUI import Charts struct ChartWithoutNilValues: View { let firstDayOfMonth: Date let firstDayOfNextMonth: Date let measurements: [PerformanceMeasurement] init() { firstDayOfMonth = Date.now.firstDayOfMonth()! firstDayOfNextMonth = Calendar.current.date(byAdding: .month, value: 1, to: firstDayOfMonth)! measurements = DataGenerator.generateMeasurements( interval: DateInterval(start: firstDayOfMonth, end: firstDayOfNextMonth), component: .day ) } var body: some View { Chart(measurements, id: \.timestamp) { measurement in BarMark( x: .value( "Timestamp", measurement.timestamp, unit: .weekOfYear, calendar: .current ), y: .value( "Solar production", measurement.production?.total ?? 0 ) ) } .chartXAxis { AxisMarks(values: .stride(by: .weekOfYear)) { value in AxisValueLabel("\(value.index)", centered: true) } } .padding() } } struct ChartWithNilValues: View { let firstDayOfMonth: Date let firstDayOfNextMonth: Date let measurements: [PerformanceMeasurement] init() { firstDayOfMonth = Date.now.firstDayOfMonth()! firstDayOfNextMonth = Calendar.current.date(byAdding: .month, value: 1, to: firstDayOfMonth)! measurements = DataGenerator.generateMeasurements( interval: DateInterval(start: firstDayOfMonth, end: firstDayOfNextMonth), component: .day ) } var body: some View { Chart(measurements, id: \.timestamp) { measurement in if let total = measurement.production?.total { BarMark( x: .value( "Timestamp", measurement.timestamp, unit: .weekOfYear, calendar: .current ), y: .value( "Solar production", total ) ) } } .chartXAxis { AxisMarks(values: .stride(by: .weekOfYear)) { value in AxisValueLabel("\(value.index)", centered: true) } } .padding() .chartXScale(domain: firstDayOfMonth...firstDayOfNextMonth) } } #Preview { VStack { ChartWithoutNilValues() ChartWithNilValues() } .padding() } struct DataGenerator { let currentYear = Calendar.current.component(.year, from: .now) let startOfDay = Calendar.current.startOfDay(for: .now) static func generateMeasurements(interval: DateInterval, component: Calendar.Component) -> [PerformanceMeasurement] { var measurements: [PerformanceMeasurement] = [] let calendar = Calendar.current let dateComponents = calendar.dateComponents([component], from: interval.start, to: interval.end) guard let count = dateComponents.value(for: component) else { return [] } for i in 0 ..< count { if let time = calendar.date(byAdding: component, value: i, to: interval.start), time <= interval.end { let production = createProduction(from: i > count - 10 ? nil : randomNumber) let measurement = PerformanceMeasurement( timestamp: time, production: production ) measurements.append(measurement) } } return measurements } static private var randomNumber: Double? { Double.random(in: 0 ... 50) } static private func createProduction(from total: Double?) -> PerformanceMeasurement.Production { guard let total else { return PerformanceMeasurement.Production(total: nil, sold: nil, consumed: nil) } let sold = Double.random(in: 0 ... total) let consumed = total - sold return PerformanceMeasurement.Production(total: total, sold: sold, consumed: consumed) } } struct PerformanceMeasurement: Codable, Equatable { let timestamp: Date let production: Production? struct Production: Codable, Equatable { let total: Double? let sold: Double? let consumed: Double? } } extension Date { func firstDayOfMonth(in calendar: Calendar = .current) -> Date? { calendar.date(from: calendar.dateComponents([.year, .month], from: self)) } }
Jul ’24
Reply to .chartXScale not scaling domain of Chart as expected
[quote='794844022, AppleCare Staff, /thread/759244?answerId=794844022#794844022'] Got it, I see what you want. But I'm not sure I understand the full setup. The code on the top uses .weekOfYear and then the domain is not set to week boundaries but to month boundaries, and it's not clear to me how the two relate in your use. Have you a small, single self-contained example with data in place? You can even use tuples in an array like [(date0, value0), ...] [/quote] I apologize if things are not clear. It might simply be because I don't have a full understanding of how I'm supposed to use the modifier. Let me try and break it down. My data set is an array of one measurement per day in a month (so I have about ~30 entries per array, naturally). This is the reason I try to set the domain of the chart from the first day in a month, to the last day in a month. I figured with that, the Chart would understand the timespan I'm trying to plot (no matter if I sort it all by .weekOfYear or not). Is that not the case? Should I set the domain in some different way when sorting the data by weekOfYear? I'm not sure I get the last sentence? Tuples for the domain? I do have an Xcode project with a minimum reproducible example, but I guess I can't share it here directly. Should I file a feedback with it, or share it in some other way?
Jul ’24
Reply to .chartXScale not scaling domain of Chart as expected
[quote='794848022, AppleCare Staff, /thread/759244?answerId=794848022#794848022'] Currently, the bar placement is conditional (non-nil total). Can you make it unconditional, such that nils get mapped to zero values? [/quote] My intention is to differentiate between nil and 0. nil would mean there's data missing, and 0 would mean there technically is data present, the total value of the measurements is just 0. So if I understand your question correctly, my answer would be: No, sadly not.
Jul ’24
Reply to Apple Watch not showing in XCode
Same issue. Xcode 15.3 (tried downloading 15.2 as well, no luck). watchOS 10.4. Here's how I got into this state: Xcode would never be able to build to my watch, so I figured I'd try and unpair the Watch from the devices list in Xcode and then pair it again. Should probably never have done that, because even after unpairing the Watch from my iPhone and resetting it, turning on and off developer mode, cleaning out all sorts of caches... I've tried everything and it never shows up anywhere. It's not even listed when using xcrun devicectl list devices. It's now taken about 24 hours of dev time away from me, which is unacceptable for something this basic.
Apr ’24
Reply to PDFKIT issue in zooming after adding ink annotation
How are you initiating your ink annotations? More specifically, what bounds do you assign to them? I had the same problem when I initially initiated each ink annotation with the bounds of the PDF page (which I at the time thought was the correct approach), only to later discover that initiating each annotation with the bounds of the bezier path that represents the drawing fixed the memory issue.
Oct ’20