Swift Charts

RSS for tag

Visualize data with highly customizable charts across all Apple platforms using the compositional syntax of SwifUI.

Posts under Swift Charts tag

192 Posts

Post

Replies

Boosts

Views

Activity

Why AreaMark doesn't work where BarMark and PointMark works perfectly?
I'm trying to visualize some data using AreaMark of Swift Charts, however, different data structures seem to affect the result. Really confused here. The following two example structs hold the same data, but in different ways: import SwiftUI import Charts struct Food: Identifiable { let name: String let sales: Int let day: Int let id = UUID() init(name: String, sales: Int, day: Int) { self.name = name self.sales = sales self.day = day } } struct Sales: Identifiable { let day: Int let burger: Int let salad: Int let steak: Int let id = UUID() var total: Int { burger + salad + steak } init(day: Int, burger: Int, salad: Int, steak: Int) { self.day = day self.burger = burger self.salad = salad self.steak = steak } } Now if I populate data and use Swift Charts to plot the data, the first struct works perfectly with all types of charts. However, the second struct, while works well with BarMark and PointMark, doesn't seem to work with AreaMark. To reproduce, change "AreaMark" to "BarMark" or "PointMark" in the following code: struct ExperimentView: View { let cheeseburgerSalesByItem: [Food] = [ .init(name: "Burger", sales: 29, day: 1), .init(name: "Salad", sales: 35, day: 1), .init(name: "Steak", sales: 30, day: 1), .init(name: "Burger", sales: 32, day: 2), .init(name: "Salad", sales: 38, day: 2), .init(name: "Steak", sales: 42, day: 2), .init(name: "Burger", sales: 35, day: 3), .init(name: "Salad", sales: 29, day: 3), .init(name: "Steak", sales: 41, day: 3), .init(name: "Burger", sales: 29, day: 4), .init(name: "Salad", sales: 38, day: 4), .init(name: "Steak", sales: 39, day: 4), .init(name: "Burger", sales: 43, day: 5), .init(name: "Salad", sales: 42, day: 5), .init(name: "Steak", sales: 30, day: 5), .init(name: "Burger", sales: 45, day: 6), .init(name: "Salad", sales: 39, day: 6), .init(name: "Steak", sales: 31, day: 6), .init(name: "Burger", sales: 37, day: 7), .init(name: "Salad", sales: 35, day: 7), .init(name: "Steak", sales: 30, day: 7), ] let cheeseburgerSalesByDay: [Sales] = [ .init(day: 1, burger: 29, salad: 35, steak: 30), .init(day: 2, burger: 32, salad: 38, steak: 42), .init(day: 3, burger: 35, salad: 29, steak: 41), .init(day: 4, burger: 29, salad: 38, steak: 39), .init(day: 5, burger: 43, salad: 42, steak: 30), .init(day: 6, burger: 45, salad: 39, steak: 31), .init(day: 7, burger: 37, salad: 35, steak: 30) ] var body: some View { VStack { Chart(cheeseburgerSalesByItem) { sale in AreaMark( x: .value("Day", sale.day), y: .value("Sales", sale.sales) ) .foregroundStyle(by: .value("Food Item", sale.name)) } .chartXScale(domain: 1...7) .padding() Spacer() Chart(cheeseburgerSalesByDay) { sale in AreaMark( x: .value("Day", sale.day), y: .value("Burger", sale.burger) ) .foregroundStyle(.brown) AreaMark( x: .value("Day", sale.day), y: .value("Salad", sale.salad) ) .foregroundStyle(.green) AreaMark( x: .value("Day", sale.day), y: .value("Steak", sale.steak) ) .foregroundStyle(.red) } .padding() } } } If two of the three AreaMarks are commented out, the left one would work. Just more than one AreaMark plots don't work for this struct. So what is the problem here? What to do if I want to use the second structure and plot a AreaMark chart?
0
0
595
Jan ’24
Can't keep scrollable chart in same position when changing .chartXVisibleDomain(length: xChartVisible)
Hi, I'm making use of iOS17 Charts and getting data from Core Data. Chart { ForEach(weightContext, id: \.timestamp) { series in LineMark( x: .value("Day", series.timestamp!, unit: .day), y: .value("Measurement", WeightFunctions.weightConversions(weightValue: series.value, metric: selectedWeight)) ) PointMark( x: .value("Day", series.timestamp!, unit: .day), y: .value("Measurement", WeightFunctions.weightConversions(weightValue: series.value, metric: selectedWeight)) ) } } .chartYScale(domain: lowestValue...highestValue) .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: xChartVisible) .chartScrollPosition(x: $xScrollPosition) .chartScrollPosition(initialX: xInitialPosition) // .chartXVisibleDomain(length: xChartVisible) .chartXScale(domain: startDate...endDate) I've linked the .chartXVisibleDomain(length: xChartVisible) to a Picker which changes the length to show month, quarter, half year, year: length = 3600 * 24 * 30, length = 3600 * 24 * 90 etc. Each time the xChartVisible changes the chart sometimes stays in the right area if I'm at the end of the x axis, but otherwise moves out of the view. I've noticed the $xScrollPosition number stays exactly the same, even though the visibility has changed but not sure what to do about that. .onAppear { xInitialPosition = weightPeriodFunc.initialScrollDate xScrollPosition = weightPeriodFunc.initialScrollDate.timeIntervalSinceReferenceDate xChartVisible = weightPeriodFunc.length } .onChange(of: weightPeriod) { newValue in xChartVisible = weightPeriodFunc.length xScrollPosition = newPeriodStartDate.timeIntervalSinceReferenceDate } I've set the xScrollPosition as a TimerInterval as I'm also getting the dates from it's location to provide date information above the chart. @State private var xChartVisible : Int = 3600 * 24 * 90 @State private var xScrollPosition : TimeInterval = TimeInterval() @State private var xInitialPosition : Date = Date() @State private var newPeriodStartDate : Date = Date()
0
2
697
Jan ’24
I'm facing a SectorMark Bug
Hello, When I input Data 1 into SectorMark and then switch to Data 2, my application crashes. Any suggestions for resolving this issue? Data 1 [ReadingLog.PieChartData(id: "E24A2F4F-5A80-4734-8497-1AE33EF4F007", hour: 4.3, category: "biography"), ReadingLog.PieChartData(id: "710C328D-0B58-4329-A3C1-66CC42A9C602", hour: 0.75, category: "philosophy"), ReadingLog.PieChartData(id: "37F0F9CE-7144-4B78-99C8-921292F6E730", hour: 0.17, category: "novel")] Data 2 [ReadingLog.PieChartData(id: "E24A2F4F-5A80-4734-8497-1AE33EF4F007", hour: 6.3, category: "biography")] Error Message: Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x0000000216287cb8 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [1978] Triggered by Thread: 0 Kernel Triage: VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed
0
0
601
Jan ’24
SectorMark AxisMark color change
Hi I am trying to build a pie chart with SwiftUI. I have created one with a dark background, and it seems like labels that correspond to each sector (labels are of black color) are not visible. It would be better to switch these labels' foreground color to white, but I don't see any suitable method to modify this. I tried both chartYAxis and chartXAxis (they worked for BarChart), but the color didn't change. Also, I added a separate struct that conforms to LabelStyle and defines makeBody in the following way struct WhiteLabelStyle : LabelStyle { func makeBody(configuration: Configuration) -> some View { Label { configuration.title.foregroundColor(.white) } icon: { configuration.icon } } } However, that also doesn't change color of labels on a chart. Below the complete code of the view: ZStack { CommonConstants.defaultBackground Chart(data, id: \.name) { name, sales in SectorMark(angle: .value("Value", sales)) .foregroundStyle(by: .value("Product category", name)) } .labelStyle(WhiteLabelStyle()) } Can you suggest any ways to manipulate with a chart comprised of SectorMarks
0
0
965
Dec ’23
SwiftUI bar charts shows overlapping bars
I'm doing a dead simple bar chart. It will show one bar per hour for a few days. The bar chart seems to have a bug where it will overlap the bars as soon as the overall width of the chart reaches some hardcoded value. The chart has .chartScrollableAxes(.horizontal) so horizontal space is no issue, there's infinite amounts of it. This screenshot shows the same content, but the bottom one has 25pt wide bars and the top one 16pt. 16 is the last width before they started overlapping. To test play with numberOfValues as well as the fixed widths for the BarMark:s. Under no circumstances should the bars overlap unless I tell it to, it should use some configurable minimum spacing between bars. In my real case I do not artificially color the bars like this and the chart is really hard to read. I've tried to look in the docs, but most modifiers are totally undocumented and I can't seem to find anything that would apply. By setting .chartXVisibleDomain to some really low value I can force it to spread the bars out more, but then the my bar width is not honoured. import SwiftUI import Charts struct Value: Hashable { let x: Int let y: Int } struct ContentView: View { let values: [Value] let colors: [Color] = [.red, .green, .blue] var body: some View { VStack { Chart { ForEach(values, id: \.self) { value in BarMark( x: .value("X", value.x), y: .value("Y", value.y), width: .fixed(16) ) .foregroundStyle(colors[value.x % colors.count]) } } .chartScrollableAxes(.horizontal) Chart { ForEach(values, id: \.self) { value in BarMark( x: .value("X", value.x), y: .value("Y", value.y), width: .fixed(25) ) .foregroundStyle(colors[value.x % colors.count]) } } .chartScrollableAxes(.horizontal) } .padding() } } #Preview { var rnd = SystemRandomNumberGenerator() let numberOfValues = 50 var values: [Value] = [] for index in 0 ..< numberOfValues { values.append(Value(x: index, y: Int(rnd.next() % 50))) } return ContentView(values: values) } Example with bars the same color. It's pretty much unusable.
4
0
2.5k
Dec ’23
Possible SwiftChart bug with overflowResolution
I've been trying to reproduce the example used in the WWDC 23 Presentation "Explore Pit Charts and Interactivity in SwiftCharts" where a popover annotation is set on top of the chart and vertical; RuleMark. However when doing so the annotation doesn't appear at all. I worked around that issue by setting: y: .fit(to: .chart) in the init of the overflowResolution, like: .annotation(position: .top, spacing: 0, overflowResolution: .init(x: .fit(to: .chart), y: .fit(to: .chart))) Probably a SwiftUI bug given this API is only a few months old. If anyone has been able to reproduce that example let me know!
1
0
1.1k
Nov ’23
Swift Charts: Jumpy, unpredictable chart when using .chartXSelection(value:)
I'm seeing an issue related to Swift Charts when I use a @Binding to dynamically change the selection of the chart. Below is a quick example View that demonstrates the issue. This example is a chart that shows a count of events that happened in a day, and the user can touch a bar to reveal the count as an annotation above the bar. The expected behavior is that as the user can touch a bar and see the annotation appear above the bar. In some cases, the chart scale may need to change to allow space for the annotation, which is expected. However, unexpectedly, the whole chart's width changes unexpectedly by a few points, sometimes, when touching a bar. It would be fine if this was consistent with times when the updated scale needs to include an additional digit, however even when that's not the case the whole chart's width seems to change by a few points, and then inconsistently sometimes change back (or not) with subsequent touches. This behavior is not present in all cases, so you may need to run the preview a few times to get data where it's reproducible. Is there something I can do here to fix the issue? Or is it just a bug in Swift Charts? import SwiftUI import Charts struct ContentView: View { var body: some View { VStack { WeekHistogram() .frame(maxHeight: 180) } .padding() } } #Preview { ContentView() } // A simple struct to contain the data for the chart. public struct EventCount: Identifiable { /// Start date of a day let date: Date /// Counts of events on that day public let count: Int /// The ID: date stored as a string public var id: String { date.ISO8601Format() } // Storing a Date as the ID changes how Swift Charts lays them out along the axis to an undesired way. init(day: Date, count: Int) { self.date = day self.count = count } } struct WeekHistogram: View { // Dummy data that gets refreshed every time you run the preview private let countByDay: [EventCount] = EventCount.dummyData // Used to extract the date back from the EventCount.id private let formatter = ISO8601DateFormatter() // The currently selected bar (while user is touching the bar) @State private var selection: String? = nil var body: some View { Chart(countByDay) { element in // X-axis: Date of the event count // Y-axis: Count of events on that date BarMark( x: .value("Day", element.id), y: .value("Count", element.count) ) .annotation(position: .top) { // Only show the annotation when this bar is being touched if element.id == selection { Text("\(element.count)") .font(.headline) } } } .chartXSelection(value: $selection) .chartXAxis { // Custom view to show the weekday and day of the month // Removing this custom .chartXAxis does not fix the issue AxisMarks { value in // Convert the text of the date back to an actual date let date = formatter.date(from: value.as(String.self)!)! AxisValueLabel { VStack { Text(date.formatted(.dateTime.weekday())) Text(date.formatted(.dateTime.day())) .font(.headline) } } } } } } // Generate dummy data extension EventCount { static let dummyData: [EventCount] = { let startOfToday = Calendar.current.startOfDay(for: .now) let secondsPerDay = 24 * 60 * 60 // Generate [EventCount] with a random count from 3–8 for toady and each of the past 7 days. var counts = [EventCount]() for i in 0...7 { let day = startOfToday .addingTimeInterval(TimeInterval(-i * secondsPerDay)) let count = Int.random(in: 3...8) let eventCount = EventCount(day: day, count: count) counts.append(eventCount) } // Reverse the direction to order it for the chart counts.reverse() return counts }() }
0
0
949
Nov ’23
Improve display grid of SwiftUI Charts
Hello all! I'm implementing a view that shows a grid of different histograms to show a final report to the user. It could have ~100 rows and ~10 columns. I'm using a LazyVGrid and it looks like: Note: the example contains only 3 rows. It takes less than a second to render the grid, but you can feel the app is blocked for a few ms. I was wonder if some of you know how to render asynchronously the chart views so, at least, not block the interface. Thanks!
0
0
602
Nov ’23
`.chartAngleSelection` doesn't register taps when tapping a `SectorMark`, have to hold down a little bit
I'm using .chartAngleSelection to grab the angle of the taps on a SectorMark. When using .chartAngleSelection, it does not register "fast" taps on the screen. You have to hold your finger on the screen for longer than a tap for it to be registered. I've tried the same code with .chartXSelection and .chartYSelection and there is no tap delay. I'm not sure if this is because .chartAngleSelection just came out of beta but it definitely impacts UX.
2
0
1.7k
Nov ’23
MTLDebugRenderCommandEncoder Error from Swift Charts
I've started using swift charts and since then get random crashes with the error: Thread 467: hit program assert The console outputs the following at the time of the crash: -[MTLDebugRenderCommandEncoder setVertexBufferOffset:atIndex:]:1758: failed assertion Set Vertex Buffer Offset Validation index(0) must have an existing buffer.` I'm not using Metal directly buit it seems like this is related to Swift Charts. I cannot work out the source of the issue from the stack trace and the debugger shows teh crash in libsystem_kernel.dylib so does not tie back to my code. I'm looking for ideas about where to start to try and find the source of the issue 0 libsystem_kernel.dylib 0x9764 __pthread_kill + 8 1 libsystem_pthread.dylib 0x6c28 (Missing UUID 1f30fb9abdf932dba7098417666a7e45) 2 libsystem_c.dylib 0x76ae8 abort + 180 3 libsystem_c.dylib 0x75e44 __assert_rtn + 270 4 Metal 0x1426c4 MTLReportFailure.cold.1 + 46 5 Metal 0x11f22c MTLReportFailure + 464 6 Metal 0x11552c _MTLMessageContextEnd + 876 7 MetalTools 0x95350 -[MTLDebugRenderCommandEncoder setVertexBufferOffset:atIndex:] + 272 8 RenderBox 0xa5e18 RB::RenderQueue::encode(RB::RenderQueue::EncoderState&) + 1804 9 RenderBox 0x7d5fc RB::RenderFrame::encode(RB::RenderFrame::EncoderData&, RB::RenderQueue&) + 432 10 RenderBox 0x7d928 RB::RenderFrame::flush_pass(RB::RenderPass&, bool)::$_4::__invoke(void*) + 48 11 libdispatch.dylib 0x4400 (Missing UUID 9897030f75d3374b8787322d3d72e096) 12 libdispatch.dylib 0xba88 (Missing UUID 9897030f75d3374b8787322d3d72e096) 13 libdispatch.dylib 0xc5f8 (Missing UUID 9897030f75d3374b8787322d3d72e096) 14 libdispatch.dylib 0x17244 (Missing UUID 9897030f75d3374b8787322d3d72e096) 15 libsystem_pthread.dylib 0x3074 (Missing UUID 1f30fb9abdf932dba7098417666a7e45) 16 libsystem_pthread.dylib 0x1d94 (Missing UUID 1f30fb9abdf932dba7098417666a7e45)
1
0
1.1k
Nov ’23
SwiftUI Charts: poor performance when synchronizing scrolling among multiple charts
I'm currently learning Swift and SwiftUI. I'm working at a MacOS app that will need to visualize a number of traces. The user must be able to scroll along the X axis of any of the traces and the other ones should be scrolling synchronously (think about a visualization similar to Apple's own "Instruments" app). I'm using SwiftUI Charts framework for visualizing the traces, this on MacOS 14.0 (beta at the time of writing) and Xcode 15 beta 6. The app is also built against the latest MacOS target (explicitly to use the new Charts functionalities). My implementation manages to correctly synchronize the scrolling of the separate charts using a binding in combination with the chartScrollPosition method, however the scrolling performance is really terrible (the scrolling movement is sluggish and jittery). If I disable the synchronization by removing the binding and chartScrollPosition calls, the charts can be scrolled independently with no performance issues. I have the feeling that I'm making some mistake in the way I used the binding, which is causing some internal loop in the UI update/drawing process. This is also supported by the logging message I get in the console when I'm scrolling: onChange(of: Optional\<CGRect\>) action tried to update multiple times per frame. I included below the code for a test app that reproduces the issue: ContentView.swift import SwiftUI struct ContentView: View { @State private var markerValue = 0.0 var body: some View { VStack { DataTraceView(markerValue: $markerValue) } .padding() } } DataTraceView.swift import SwiftUI import Charts private let SAMPLES = 10000 func generateRandomDataPoints(count: Int) -> [DataPoint] { return (0..<count).map { idx in DataPoint(id: idx, xValue: Double(idx), yValue: Double.random(in: 0..<1)) } } struct DataPoint: Identifiable { var id: Int var xValue: Double var yValue: Double } struct DataTraceView: View { @State var testVector1: [DataPoint] = generateRandomDataPoints(count: SAMPLES) @State var testVector2: [DataPoint] = generateRandomDataPoints(count: SAMPLES) @Binding var markerValue: Double var body: some View { VStack { Chart(testVector1) { LineMark( x: .value("Time", $0.xValue), y: .value("Speed", $0.yValue) ) } .chartScrollPosition(x: $markerValue) .chartXVisibleDomain(length: 15) .chartScrollableAxes(.horizontal) Chart(testVector2) { LineMark( x: .value("Time", $0.xValue), y: .value("LatG", $0.yValue) ) } .chartScrollPosition(x: $markerValue) .chartXVisibleDomain(length: 15) .chartScrollableAxes(.horizontal) } } } Any ideas about what am I doing wrong?
4
4
3.0k
Oct ’23
Charts: ScaleResolutionFailure(message: "Scale domain configuration doesn't match encoded value type")
Chart { ForEach(viewModel.chartDBdata) { index in LineMark(x: .value("Seq", index.dataSeqInSwing), y: .value("Value",index.value) ) .foregroundStyle(by: .value("itemType", index.itemType)) } } .chartForegroundStyleScale([ "angle": .red, "degree": .orange, "grip1": .yellow, "grip2": .blue ]) .frame(height: 300) .padding() .onAppear{ viewModel.findContact() print("Chart_OnAppear after vm.findcontact") } .tabItem { Image(systemName: "2.circle") Text("data base") }.tag(2) Charts: ScaleResolutionFailure(message: "Scale domain configuration doesn't match encoded value type") <0x10190ebd0> Gesture: System gesture gate timed out. immediately after ForEach looping completion, error message above is shown. why does this happen ?
0
0
893
Oct ’23
Swift Chart LineMark create chart each time different
Hi There, Same data shows different line drawing. What I am missing here ? Each time I click to see chart, its drawing is different. Chart{ ForEach(data) { series in ForEach(series.data){ entry in LineMark( x: .value("Day", entry.day), y: .value("Amount", entry.amount) ) .foregroundStyle(by: .value("Doc", series.Doc)) .symbol(by: .value("Doc", series.Doc)) PointMark( x: .value("Day", entry.day), y: .value("Sales", entry.amount) ) .foregroundStyle(.purple) .symbolSize(symbolSize) } .lineStyle(StrokeStyle(lineWidth: lineWidth)) } } .chartLegend(position: .top) .chartYScale(domain: .automatic(includesZero: false)) .chartXAxis { AxisMarks(values: .automatic(roundLowerBound: false, roundUpperBound: false)) { value in if value.index < value.count - 1 { AxisValueLabel() } AxisTick() AxisGridLine() } }
2
0
1.9k
Oct ’23
SwiftUI chart annotation not working when using chartScrollableAxes
When using the new iOS “chartScrollableAxes” feature annotation that should show on top of the chart view no longer work. When disabling “chartScrollableAxes” everything works again. Filed as FB12584128 import SwiftUI import Charts class ChartDataEntry:Identifiable { var date:Date var value:Double init(date:Date, value: Double) { self.date=date self.value=value } } struct ContentView: View { @State var rawSelectedDate: Date? var chartData = [ChartDataEntry(date: Date().yesterday.yesterday.yesterday.yesterday.startOfDay, value: 10.0), ChartDataEntry(date: Date().yesterday.yesterday.yesterday.startOfDay, value: 20.0), ChartDataEntry(date: Date().yesterday.yesterday.startOfDay, value: 30.0), ChartDataEntry(date: Date().yesterday.startOfDay, value: 40.0), ChartDataEntry(date: Date().startOfDay, value: 50.0)] var body: some View { VStack { Chart(chartData) { entry in BarMark( x: .value("Day", entry.date, unit: .day), y: .value("Values", entry.value) ) if let selectedDate { RuleMark( x: .value("Selected", selectedDate, unit: .day)) .foregroundStyle(Color.gray.opacity(0.3)) .offset(yStart: -10) .zIndex(-1) .annotation(position: .top, spacing: -10, overflowResolution: .init( x: .fit(to: .chart), y: .disabled ) ) { Text("Longer Sample Text") } } } .chartScrollableAxes(.horizontal) // <<--- when this is disabled the annotation will be shown correctly .chartXSelection(value: $rawSelectedDate) .frame(height: 300) } .padding() } var selectedDate: Date? { guard let rawSelectedDate else { return nil } return chartData.first(where: { let endOfDay = $0.date.endOfDay return ($0.date ... endOfDay).contains(rawSelectedDate) })?.date } } #Preview { ContentView() } extension Date { var yesterday: Date { return Calendar.current.date(byAdding: .day, value: -1, to: self)! } var startOfDay: Date { return Calendar.current.startOfDay(for: self) } var endOfDay: Date { var components = DateComponents() components.day = 1 components.second = -1 return Calendar.current.date(byAdding: components, to: startOfDay)! } }
9
1
3.3k
Oct ’23
Scrollable Plot Area
Is there a way to create scrolling/paging behavior in the charts just like is done in the Health app? I have a similar app that also displays health data (such as heart rate and steps) and with my current custom charts the user can page back to see data from previous weeks (by default it shows the current week). Just like in the health app the user can go back as long as there is data, which can be several years (so hundreds go pages). I'd love to replace my custom implementation with Swift Charts but for that I do need this scrolling behavior.
8
11
4.2k
Oct ’23
Swift Chart RuleMark annotation not respecting overflow resolution when using chartScrollableAxis
I'm currently in the process on making a horizontally scrollable bar chart with selection. Upon selection, I want to show an annotation attached to a RuleMark. I want to be able to show this annotation above the chart plot area since it is large and will likely cover many bars. I'm using the overflowResolution option on the annotation with the y set to disabled; however, this does not do anything and the annotation seems pushed up inside the plot area rather than overlapping with the plot area itself. If I comment out the chartScrollableAxis modifier than the overflow resolution works as expected.
4
9
2.9k
Sep ’23
Chart - Last (right most) x axis label not being displayed
I have a swift program that displays a chart using Chart. The code includes an X Axis Scale parameter but for some reason the last value (right most) on the x axis does not display. It should display Aug 2023. In checking the array used for the x axis labels I find that the last value is Aug 2023. I do not know how to overcome this obstacle. Any assistance will be appreciated. Below is a picture of the bottom of the chart and the code. struct CustomChartView: View { let vm: SQLDataVM = SQLDataVM.shared let closingValues: [TradingDay] let fundName: String let numYears: Int let maxCloseStruct: TradingDay let maxClose: Double let minCloseStruct: TradingDay let minClose: Double let yIncrment: Double let yAxisValues: [Double] let minTimeStampStruct: TradingDay let minTimeStamp: Date var dateComponent = DateComponents() let maxTimeStampStruct: TradingDay let maxTimeStamp: Date var xAxisValues: [Date] = [] init (fundName: String, numYears: Int) { self.fundName = fundName self.numYears = numYears closingValues = self.vm.QueryDatabase(fundName: fundName, numYears: numYears) maxCloseStruct = self.closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.close < tradingDay2.close })! maxClose = maxCloseStruct.close minCloseStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.close < tradingDay2.close })! minClose = minCloseStruct.close yIncrment = (maxClose - minClose)/4 yAxisValues = [ minClose, minClose + (1 * yIncrment), minClose + (2 * yIncrment), minClose + (3 * yIncrment), maxClose ] minTimeStampStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.timeStamp < tradingDay2.timeStamp })! minTimeStamp = minTimeStampStruct.timeStamp maxTimeStampStruct = closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.timeStamp < tradingDay2.timeStamp })! maxTimeStamp = maxTimeStampStruct.timeStamp xAxisValues.append(minTimeStamp) for i in 1...11 { dateComponent.month = i let nextMonth = Calendar.current.date(byAdding: dateComponent, to: minTimeStamp) xAxisValues.append(nextMonth!) } xAxisValues.append(maxTimeStamp) print("\(xAxisValues[12])") // prints 2023-08-04 00:00:00 +0000 } // end init var body: some View { HStack(alignment: .center) { VStack(alignment: .center) { Chart(closingValues, id:\.id) { LineMark( x: .value("Date", $0.timeStamp, unit: .day), y: .value("Closing", $0.close) ) .foregroundStyle(.blue) } // end chart .frame(width: 1000, height: 700, alignment: .center) .chartXAxisLabel(position: .bottom, alignment: .center, spacing: 15) { Text("Date") .font(.custom("Arial", size: 20)) } .chartYAxisLabel(position: .leading, alignment: .center, spacing: 20) { Text("Closing Value") .font(.custom("Arial", size: 20)) } .chartXAxis { AxisMarks(values: xAxisValues) { value in if let date = value.as(Date.self) { AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) { VStack(alignment: .leading) { Text(ChartMonthFormatter.string(from: date)) .font(.custom("Arial", size: 14)) Text(ChartYearFormatter.string(from: date)) .font(.custom("Arial", size: 14)) } // end v stack } // end axis label } // end if statement AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) .foregroundStyle(Color.black) AxisTick(centered: true, length: 0, stroke: .none) } } // end chart x axis .chartXScale(domain: [xAxisValues[0], xAxisValues[12]]) .chartYAxis { AxisMarks(position: .leading, values: yAxisValues) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) .foregroundStyle(Color.black) AxisTick(centered: true, length: 0, stroke: .none) AxisValueLabel(horizontalSpacing: 10) { if let yAxisValue = value.as(Double.self) { let stringValue = String(format: "$%.02f", yAxisValue) Text(stringValue) .font(.custom("Arial", size: 14)) } } } } .chartYScale(domain: [minClose, maxClose]) .chartPlotStyle { plotArea in plotArea.background(.white.opacity(0.9)) .border(.black, width: 1) } // end chart plot style } // end v stack .frame(width: 1200, height: 900, alignment: .center) } // end h stack } // end some view }
2
0
2.7k
Sep ’23
Why AreaMark doesn't work where BarMark and PointMark works perfectly?
I'm trying to visualize some data using AreaMark of Swift Charts, however, different data structures seem to affect the result. Really confused here. The following two example structs hold the same data, but in different ways: import SwiftUI import Charts struct Food: Identifiable { let name: String let sales: Int let day: Int let id = UUID() init(name: String, sales: Int, day: Int) { self.name = name self.sales = sales self.day = day } } struct Sales: Identifiable { let day: Int let burger: Int let salad: Int let steak: Int let id = UUID() var total: Int { burger + salad + steak } init(day: Int, burger: Int, salad: Int, steak: Int) { self.day = day self.burger = burger self.salad = salad self.steak = steak } } Now if I populate data and use Swift Charts to plot the data, the first struct works perfectly with all types of charts. However, the second struct, while works well with BarMark and PointMark, doesn't seem to work with AreaMark. To reproduce, change "AreaMark" to "BarMark" or "PointMark" in the following code: struct ExperimentView: View { let cheeseburgerSalesByItem: [Food] = [ .init(name: "Burger", sales: 29, day: 1), .init(name: "Salad", sales: 35, day: 1), .init(name: "Steak", sales: 30, day: 1), .init(name: "Burger", sales: 32, day: 2), .init(name: "Salad", sales: 38, day: 2), .init(name: "Steak", sales: 42, day: 2), .init(name: "Burger", sales: 35, day: 3), .init(name: "Salad", sales: 29, day: 3), .init(name: "Steak", sales: 41, day: 3), .init(name: "Burger", sales: 29, day: 4), .init(name: "Salad", sales: 38, day: 4), .init(name: "Steak", sales: 39, day: 4), .init(name: "Burger", sales: 43, day: 5), .init(name: "Salad", sales: 42, day: 5), .init(name: "Steak", sales: 30, day: 5), .init(name: "Burger", sales: 45, day: 6), .init(name: "Salad", sales: 39, day: 6), .init(name: "Steak", sales: 31, day: 6), .init(name: "Burger", sales: 37, day: 7), .init(name: "Salad", sales: 35, day: 7), .init(name: "Steak", sales: 30, day: 7), ] let cheeseburgerSalesByDay: [Sales] = [ .init(day: 1, burger: 29, salad: 35, steak: 30), .init(day: 2, burger: 32, salad: 38, steak: 42), .init(day: 3, burger: 35, salad: 29, steak: 41), .init(day: 4, burger: 29, salad: 38, steak: 39), .init(day: 5, burger: 43, salad: 42, steak: 30), .init(day: 6, burger: 45, salad: 39, steak: 31), .init(day: 7, burger: 37, salad: 35, steak: 30) ] var body: some View { VStack { Chart(cheeseburgerSalesByItem) { sale in AreaMark( x: .value("Day", sale.day), y: .value("Sales", sale.sales) ) .foregroundStyle(by: .value("Food Item", sale.name)) } .chartXScale(domain: 1...7) .padding() Spacer() Chart(cheeseburgerSalesByDay) { sale in AreaMark( x: .value("Day", sale.day), y: .value("Burger", sale.burger) ) .foregroundStyle(.brown) AreaMark( x: .value("Day", sale.day), y: .value("Salad", sale.salad) ) .foregroundStyle(.green) AreaMark( x: .value("Day", sale.day), y: .value("Steak", sale.steak) ) .foregroundStyle(.red) } .padding() } } } If two of the three AreaMarks are commented out, the left one would work. Just more than one AreaMark plots don't work for this struct. So what is the problem here? What to do if I want to use the second structure and plot a AreaMark chart?
Replies
0
Boosts
0
Views
595
Activity
Jan ’24
Can't keep scrollable chart in same position when changing .chartXVisibleDomain(length: xChartVisible)
Hi, I'm making use of iOS17 Charts and getting data from Core Data. Chart { ForEach(weightContext, id: \.timestamp) { series in LineMark( x: .value("Day", series.timestamp!, unit: .day), y: .value("Measurement", WeightFunctions.weightConversions(weightValue: series.value, metric: selectedWeight)) ) PointMark( x: .value("Day", series.timestamp!, unit: .day), y: .value("Measurement", WeightFunctions.weightConversions(weightValue: series.value, metric: selectedWeight)) ) } } .chartYScale(domain: lowestValue...highestValue) .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: xChartVisible) .chartScrollPosition(x: $xScrollPosition) .chartScrollPosition(initialX: xInitialPosition) // .chartXVisibleDomain(length: xChartVisible) .chartXScale(domain: startDate...endDate) I've linked the .chartXVisibleDomain(length: xChartVisible) to a Picker which changes the length to show month, quarter, half year, year: length = 3600 * 24 * 30, length = 3600 * 24 * 90 etc. Each time the xChartVisible changes the chart sometimes stays in the right area if I'm at the end of the x axis, but otherwise moves out of the view. I've noticed the $xScrollPosition number stays exactly the same, even though the visibility has changed but not sure what to do about that. .onAppear { xInitialPosition = weightPeriodFunc.initialScrollDate xScrollPosition = weightPeriodFunc.initialScrollDate.timeIntervalSinceReferenceDate xChartVisible = weightPeriodFunc.length } .onChange(of: weightPeriod) { newValue in xChartVisible = weightPeriodFunc.length xScrollPosition = newPeriodStartDate.timeIntervalSinceReferenceDate } I've set the xScrollPosition as a TimerInterval as I'm also getting the dates from it's location to provide date information above the chart. @State private var xChartVisible : Int = 3600 * 24 * 90 @State private var xScrollPosition : TimeInterval = TimeInterval() @State private var xInitialPosition : Date = Date() @State private var newPeriodStartDate : Date = Date()
Replies
0
Boosts
2
Views
697
Activity
Jan ’24
I'm facing a SectorMark Bug
Hello, When I input Data 1 into SectorMark and then switch to Data 2, my application crashes. Any suggestions for resolving this issue? Data 1 [ReadingLog.PieChartData(id: "E24A2F4F-5A80-4734-8497-1AE33EF4F007", hour: 4.3, category: "biography"), ReadingLog.PieChartData(id: "710C328D-0B58-4329-A3C1-66CC42A9C602", hour: 0.75, category: "philosophy"), ReadingLog.PieChartData(id: "37F0F9CE-7144-4B78-99C8-921292F6E730", hour: 0.17, category: "novel")] Data 2 [ReadingLog.PieChartData(id: "E24A2F4F-5A80-4734-8497-1AE33EF4F007", hour: 6.3, category: "biography")] Error Message: Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x0000000216287cb8 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [1978] Triggered by Thread: 0 Kernel Triage: VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed
Replies
0
Boosts
0
Views
601
Activity
Jan ’24
SectorMark AxisMark color change
Hi I am trying to build a pie chart with SwiftUI. I have created one with a dark background, and it seems like labels that correspond to each sector (labels are of black color) are not visible. It would be better to switch these labels' foreground color to white, but I don't see any suitable method to modify this. I tried both chartYAxis and chartXAxis (they worked for BarChart), but the color didn't change. Also, I added a separate struct that conforms to LabelStyle and defines makeBody in the following way struct WhiteLabelStyle : LabelStyle { func makeBody(configuration: Configuration) -> some View { Label { configuration.title.foregroundColor(.white) } icon: { configuration.icon } } } However, that also doesn't change color of labels on a chart. Below the complete code of the view: ZStack { CommonConstants.defaultBackground Chart(data, id: \.name) { name, sales in SectorMark(angle: .value("Value", sales)) .foregroundStyle(by: .value("Product category", name)) } .labelStyle(WhiteLabelStyle()) } Can you suggest any ways to manipulate with a chart comprised of SectorMarks
Replies
0
Boosts
0
Views
965
Activity
Dec ’23
SwiftUI bar charts shows overlapping bars
I'm doing a dead simple bar chart. It will show one bar per hour for a few days. The bar chart seems to have a bug where it will overlap the bars as soon as the overall width of the chart reaches some hardcoded value. The chart has .chartScrollableAxes(.horizontal) so horizontal space is no issue, there's infinite amounts of it. This screenshot shows the same content, but the bottom one has 25pt wide bars and the top one 16pt. 16 is the last width before they started overlapping. To test play with numberOfValues as well as the fixed widths for the BarMark:s. Under no circumstances should the bars overlap unless I tell it to, it should use some configurable minimum spacing between bars. In my real case I do not artificially color the bars like this and the chart is really hard to read. I've tried to look in the docs, but most modifiers are totally undocumented and I can't seem to find anything that would apply. By setting .chartXVisibleDomain to some really low value I can force it to spread the bars out more, but then the my bar width is not honoured. import SwiftUI import Charts struct Value: Hashable { let x: Int let y: Int } struct ContentView: View { let values: [Value] let colors: [Color] = [.red, .green, .blue] var body: some View { VStack { Chart { ForEach(values, id: \.self) { value in BarMark( x: .value("X", value.x), y: .value("Y", value.y), width: .fixed(16) ) .foregroundStyle(colors[value.x % colors.count]) } } .chartScrollableAxes(.horizontal) Chart { ForEach(values, id: \.self) { value in BarMark( x: .value("X", value.x), y: .value("Y", value.y), width: .fixed(25) ) .foregroundStyle(colors[value.x % colors.count]) } } .chartScrollableAxes(.horizontal) } .padding() } } #Preview { var rnd = SystemRandomNumberGenerator() let numberOfValues = 50 var values: [Value] = [] for index in 0 ..< numberOfValues { values.append(Value(x: index, y: Int(rnd.next() % 50))) } return ContentView(values: values) } Example with bars the same color. It's pretty much unusable.
Replies
4
Boosts
0
Views
2.5k
Activity
Dec ’23
Possible SwiftChart bug with overflowResolution
I've been trying to reproduce the example used in the WWDC 23 Presentation "Explore Pit Charts and Interactivity in SwiftCharts" where a popover annotation is set on top of the chart and vertical; RuleMark. However when doing so the annotation doesn't appear at all. I worked around that issue by setting: y: .fit(to: .chart) in the init of the overflowResolution, like: .annotation(position: .top, spacing: 0, overflowResolution: .init(x: .fit(to: .chart), y: .fit(to: .chart))) Probably a SwiftUI bug given this API is only a few months old. If anyone has been able to reproduce that example let me know!
Replies
1
Boosts
0
Views
1.1k
Activity
Nov ’23
Swift Charts: Jumpy, unpredictable chart when using .chartXSelection(value:)
I'm seeing an issue related to Swift Charts when I use a @Binding to dynamically change the selection of the chart. Below is a quick example View that demonstrates the issue. This example is a chart that shows a count of events that happened in a day, and the user can touch a bar to reveal the count as an annotation above the bar. The expected behavior is that as the user can touch a bar and see the annotation appear above the bar. In some cases, the chart scale may need to change to allow space for the annotation, which is expected. However, unexpectedly, the whole chart's width changes unexpectedly by a few points, sometimes, when touching a bar. It would be fine if this was consistent with times when the updated scale needs to include an additional digit, however even when that's not the case the whole chart's width seems to change by a few points, and then inconsistently sometimes change back (or not) with subsequent touches. This behavior is not present in all cases, so you may need to run the preview a few times to get data where it's reproducible. Is there something I can do here to fix the issue? Or is it just a bug in Swift Charts? import SwiftUI import Charts struct ContentView: View { var body: some View { VStack { WeekHistogram() .frame(maxHeight: 180) } .padding() } } #Preview { ContentView() } // A simple struct to contain the data for the chart. public struct EventCount: Identifiable { /// Start date of a day let date: Date /// Counts of events on that day public let count: Int /// The ID: date stored as a string public var id: String { date.ISO8601Format() } // Storing a Date as the ID changes how Swift Charts lays them out along the axis to an undesired way. init(day: Date, count: Int) { self.date = day self.count = count } } struct WeekHistogram: View { // Dummy data that gets refreshed every time you run the preview private let countByDay: [EventCount] = EventCount.dummyData // Used to extract the date back from the EventCount.id private let formatter = ISO8601DateFormatter() // The currently selected bar (while user is touching the bar) @State private var selection: String? = nil var body: some View { Chart(countByDay) { element in // X-axis: Date of the event count // Y-axis: Count of events on that date BarMark( x: .value("Day", element.id), y: .value("Count", element.count) ) .annotation(position: .top) { // Only show the annotation when this bar is being touched if element.id == selection { Text("\(element.count)") .font(.headline) } } } .chartXSelection(value: $selection) .chartXAxis { // Custom view to show the weekday and day of the month // Removing this custom .chartXAxis does not fix the issue AxisMarks { value in // Convert the text of the date back to an actual date let date = formatter.date(from: value.as(String.self)!)! AxisValueLabel { VStack { Text(date.formatted(.dateTime.weekday())) Text(date.formatted(.dateTime.day())) .font(.headline) } } } } } } // Generate dummy data extension EventCount { static let dummyData: [EventCount] = { let startOfToday = Calendar.current.startOfDay(for: .now) let secondsPerDay = 24 * 60 * 60 // Generate [EventCount] with a random count from 3–8 for toady and each of the past 7 days. var counts = [EventCount]() for i in 0...7 { let day = startOfToday .addingTimeInterval(TimeInterval(-i * secondsPerDay)) let count = Int.random(in: 3...8) let eventCount = EventCount(day: day, count: count) counts.append(eventCount) } // Reverse the direction to order it for the chart counts.reverse() return counts }() }
Replies
0
Boosts
0
Views
949
Activity
Nov ’23
Improve display grid of SwiftUI Charts
Hello all! I'm implementing a view that shows a grid of different histograms to show a final report to the user. It could have ~100 rows and ~10 columns. I'm using a LazyVGrid and it looks like: Note: the example contains only 3 rows. It takes less than a second to render the grid, but you can feel the app is blocked for a few ms. I was wonder if some of you know how to render asynchronously the chart views so, at least, not block the interface. Thanks!
Replies
0
Boosts
0
Views
602
Activity
Nov ’23
`.chartAngleSelection` doesn't register taps when tapping a `SectorMark`, have to hold down a little bit
I'm using .chartAngleSelection to grab the angle of the taps on a SectorMark. When using .chartAngleSelection, it does not register "fast" taps on the screen. You have to hold your finger on the screen for longer than a tap for it to be registered. I've tried the same code with .chartXSelection and .chartYSelection and there is no tap delay. I'm not sure if this is because .chartAngleSelection just came out of beta but it definitely impacts UX.
Replies
2
Boosts
0
Views
1.7k
Activity
Nov ’23
MTLDebugRenderCommandEncoder Error from Swift Charts
I've started using swift charts and since then get random crashes with the error: Thread 467: hit program assert The console outputs the following at the time of the crash: -[MTLDebugRenderCommandEncoder setVertexBufferOffset:atIndex:]:1758: failed assertion Set Vertex Buffer Offset Validation index(0) must have an existing buffer.` I'm not using Metal directly buit it seems like this is related to Swift Charts. I cannot work out the source of the issue from the stack trace and the debugger shows teh crash in libsystem_kernel.dylib so does not tie back to my code. I'm looking for ideas about where to start to try and find the source of the issue 0 libsystem_kernel.dylib 0x9764 __pthread_kill + 8 1 libsystem_pthread.dylib 0x6c28 (Missing UUID 1f30fb9abdf932dba7098417666a7e45) 2 libsystem_c.dylib 0x76ae8 abort + 180 3 libsystem_c.dylib 0x75e44 __assert_rtn + 270 4 Metal 0x1426c4 MTLReportFailure.cold.1 + 46 5 Metal 0x11f22c MTLReportFailure + 464 6 Metal 0x11552c _MTLMessageContextEnd + 876 7 MetalTools 0x95350 -[MTLDebugRenderCommandEncoder setVertexBufferOffset:atIndex:] + 272 8 RenderBox 0xa5e18 RB::RenderQueue::encode(RB::RenderQueue::EncoderState&) + 1804 9 RenderBox 0x7d5fc RB::RenderFrame::encode(RB::RenderFrame::EncoderData&, RB::RenderQueue&) + 432 10 RenderBox 0x7d928 RB::RenderFrame::flush_pass(RB::RenderPass&, bool)::$_4::__invoke(void*) + 48 11 libdispatch.dylib 0x4400 (Missing UUID 9897030f75d3374b8787322d3d72e096) 12 libdispatch.dylib 0xba88 (Missing UUID 9897030f75d3374b8787322d3d72e096) 13 libdispatch.dylib 0xc5f8 (Missing UUID 9897030f75d3374b8787322d3d72e096) 14 libdispatch.dylib 0x17244 (Missing UUID 9897030f75d3374b8787322d3d72e096) 15 libsystem_pthread.dylib 0x3074 (Missing UUID 1f30fb9abdf932dba7098417666a7e45) 16 libsystem_pthread.dylib 0x1d94 (Missing UUID 1f30fb9abdf932dba7098417666a7e45)
Replies
1
Boosts
0
Views
1.1k
Activity
Nov ’23
Swift Chart in storyboard
Hello, I'm trying to find a way to implement Charts in my project. I'm using storyboard. All the resource that I'm getting everywhere they are using only SwiftUI. Did anyone help me finding a way to implement it.
Replies
1
Boosts
0
Views
603
Activity
Nov ’23
SwiftUI Charts: poor performance when synchronizing scrolling among multiple charts
I'm currently learning Swift and SwiftUI. I'm working at a MacOS app that will need to visualize a number of traces. The user must be able to scroll along the X axis of any of the traces and the other ones should be scrolling synchronously (think about a visualization similar to Apple's own "Instruments" app). I'm using SwiftUI Charts framework for visualizing the traces, this on MacOS 14.0 (beta at the time of writing) and Xcode 15 beta 6. The app is also built against the latest MacOS target (explicitly to use the new Charts functionalities). My implementation manages to correctly synchronize the scrolling of the separate charts using a binding in combination with the chartScrollPosition method, however the scrolling performance is really terrible (the scrolling movement is sluggish and jittery). If I disable the synchronization by removing the binding and chartScrollPosition calls, the charts can be scrolled independently with no performance issues. I have the feeling that I'm making some mistake in the way I used the binding, which is causing some internal loop in the UI update/drawing process. This is also supported by the logging message I get in the console when I'm scrolling: onChange(of: Optional\<CGRect\>) action tried to update multiple times per frame. I included below the code for a test app that reproduces the issue: ContentView.swift import SwiftUI struct ContentView: View { @State private var markerValue = 0.0 var body: some View { VStack { DataTraceView(markerValue: $markerValue) } .padding() } } DataTraceView.swift import SwiftUI import Charts private let SAMPLES = 10000 func generateRandomDataPoints(count: Int) -> [DataPoint] { return (0..<count).map { idx in DataPoint(id: idx, xValue: Double(idx), yValue: Double.random(in: 0..<1)) } } struct DataPoint: Identifiable { var id: Int var xValue: Double var yValue: Double } struct DataTraceView: View { @State var testVector1: [DataPoint] = generateRandomDataPoints(count: SAMPLES) @State var testVector2: [DataPoint] = generateRandomDataPoints(count: SAMPLES) @Binding var markerValue: Double var body: some View { VStack { Chart(testVector1) { LineMark( x: .value("Time", $0.xValue), y: .value("Speed", $0.yValue) ) } .chartScrollPosition(x: $markerValue) .chartXVisibleDomain(length: 15) .chartScrollableAxes(.horizontal) Chart(testVector2) { LineMark( x: .value("Time", $0.xValue), y: .value("LatG", $0.yValue) ) } .chartScrollPosition(x: $markerValue) .chartXVisibleDomain(length: 15) .chartScrollableAxes(.horizontal) } } } Any ideas about what am I doing wrong?
Replies
4
Boosts
4
Views
3.0k
Activity
Oct ’23
Charts: ScaleResolutionFailure(message: "Scale domain configuration doesn't match encoded value type")
Chart { ForEach(viewModel.chartDBdata) { index in LineMark(x: .value("Seq", index.dataSeqInSwing), y: .value("Value",index.value) ) .foregroundStyle(by: .value("itemType", index.itemType)) } } .chartForegroundStyleScale([ "angle": .red, "degree": .orange, "grip1": .yellow, "grip2": .blue ]) .frame(height: 300) .padding() .onAppear{ viewModel.findContact() print("Chart_OnAppear after vm.findcontact") } .tabItem { Image(systemName: "2.circle") Text("data base") }.tag(2) Charts: ScaleResolutionFailure(message: "Scale domain configuration doesn't match encoded value type") <0x10190ebd0> Gesture: System gesture gate timed out. immediately after ForEach looping completion, error message above is shown. why does this happen ?
Replies
0
Boosts
0
Views
893
Activity
Oct ’23
Swift Chart LineMark create chart each time different
Hi There, Same data shows different line drawing. What I am missing here ? Each time I click to see chart, its drawing is different. Chart{ ForEach(data) { series in ForEach(series.data){ entry in LineMark( x: .value("Day", entry.day), y: .value("Amount", entry.amount) ) .foregroundStyle(by: .value("Doc", series.Doc)) .symbol(by: .value("Doc", series.Doc)) PointMark( x: .value("Day", entry.day), y: .value("Sales", entry.amount) ) .foregroundStyle(.purple) .symbolSize(symbolSize) } .lineStyle(StrokeStyle(lineWidth: lineWidth)) } } .chartLegend(position: .top) .chartYScale(domain: .automatic(includesZero: false)) .chartXAxis { AxisMarks(values: .automatic(roundLowerBound: false, roundUpperBound: false)) { value in if value.index < value.count - 1 { AxisValueLabel() } AxisTick() AxisGridLine() } }
Replies
2
Boosts
0
Views
1.9k
Activity
Oct ’23
SwiftUI chart annotation not working when using chartScrollableAxes
When using the new iOS “chartScrollableAxes” feature annotation that should show on top of the chart view no longer work. When disabling “chartScrollableAxes” everything works again. Filed as FB12584128 import SwiftUI import Charts class ChartDataEntry:Identifiable { var date:Date var value:Double init(date:Date, value: Double) { self.date=date self.value=value } } struct ContentView: View { @State var rawSelectedDate: Date? var chartData = [ChartDataEntry(date: Date().yesterday.yesterday.yesterday.yesterday.startOfDay, value: 10.0), ChartDataEntry(date: Date().yesterday.yesterday.yesterday.startOfDay, value: 20.0), ChartDataEntry(date: Date().yesterday.yesterday.startOfDay, value: 30.0), ChartDataEntry(date: Date().yesterday.startOfDay, value: 40.0), ChartDataEntry(date: Date().startOfDay, value: 50.0)] var body: some View { VStack { Chart(chartData) { entry in BarMark( x: .value("Day", entry.date, unit: .day), y: .value("Values", entry.value) ) if let selectedDate { RuleMark( x: .value("Selected", selectedDate, unit: .day)) .foregroundStyle(Color.gray.opacity(0.3)) .offset(yStart: -10) .zIndex(-1) .annotation(position: .top, spacing: -10, overflowResolution: .init( x: .fit(to: .chart), y: .disabled ) ) { Text("Longer Sample Text") } } } .chartScrollableAxes(.horizontal) // <<--- when this is disabled the annotation will be shown correctly .chartXSelection(value: $rawSelectedDate) .frame(height: 300) } .padding() } var selectedDate: Date? { guard let rawSelectedDate else { return nil } return chartData.first(where: { let endOfDay = $0.date.endOfDay return ($0.date ... endOfDay).contains(rawSelectedDate) })?.date } } #Preview { ContentView() } extension Date { var yesterday: Date { return Calendar.current.date(byAdding: .day, value: -1, to: self)! } var startOfDay: Date { return Calendar.current.startOfDay(for: self) } var endOfDay: Date { var components = DateComponents() components.day = 1 components.second = -1 return Calendar.current.date(byAdding: components, to: startOfDay)! } }
Replies
9
Boosts
1
Views
3.3k
Activity
Oct ’23
Scrollable Plot Area
Is there a way to create scrolling/paging behavior in the charts just like is done in the Health app? I have a similar app that also displays health data (such as heart rate and steps) and with my current custom charts the user can page back to see data from previous weeks (by default it shows the current week). Just like in the health app the user can go back as long as there is data, which can be several years (so hundreds go pages). I'd love to replace my custom implementation with Swift Charts but for that I do need this scrolling behavior.
Replies
8
Boosts
11
Views
4.2k
Activity
Oct ’23
Swift Chart RuleMark annotation not respecting overflow resolution when using chartScrollableAxis
I'm currently in the process on making a horizontally scrollable bar chart with selection. Upon selection, I want to show an annotation attached to a RuleMark. I want to be able to show this annotation above the chart plot area since it is large and will likely cover many bars. I'm using the overflowResolution option on the annotation with the y set to disabled; however, this does not do anything and the annotation seems pushed up inside the plot area rather than overlapping with the plot area itself. If I comment out the chartScrollableAxis modifier than the overflow resolution works as expected.
Replies
4
Boosts
9
Views
2.9k
Activity
Sep ’23
Swift Charts in ObjC project using bridging headers?
Is it possible to use Swift Charts in my ObjC project using bridging headers? The documentation names its Swift Charts but its seems they can only be used in SwiftUI projects.
Replies
2
Boosts
0
Views
842
Activity
Sep ’23
Swift Charts Styling
How to apply Swift Charts, for instance, barmark, without x and y axes and labels?
Replies
0
Boosts
0
Views
599
Activity
Sep ’23
Chart - Last (right most) x axis label not being displayed
I have a swift program that displays a chart using Chart. The code includes an X Axis Scale parameter but for some reason the last value (right most) on the x axis does not display. It should display Aug 2023. In checking the array used for the x axis labels I find that the last value is Aug 2023. I do not know how to overcome this obstacle. Any assistance will be appreciated. Below is a picture of the bottom of the chart and the code. struct CustomChartView: View { let vm: SQLDataVM = SQLDataVM.shared let closingValues: [TradingDay] let fundName: String let numYears: Int let maxCloseStruct: TradingDay let maxClose: Double let minCloseStruct: TradingDay let minClose: Double let yIncrment: Double let yAxisValues: [Double] let minTimeStampStruct: TradingDay let minTimeStamp: Date var dateComponent = DateComponents() let maxTimeStampStruct: TradingDay let maxTimeStamp: Date var xAxisValues: [Date] = [] init (fundName: String, numYears: Int) { self.fundName = fundName self.numYears = numYears closingValues = self.vm.QueryDatabase(fundName: fundName, numYears: numYears) maxCloseStruct = self.closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.close < tradingDay2.close })! maxClose = maxCloseStruct.close minCloseStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.close < tradingDay2.close })! minClose = minCloseStruct.close yIncrment = (maxClose - minClose)/4 yAxisValues = [ minClose, minClose + (1 * yIncrment), minClose + (2 * yIncrment), minClose + (3 * yIncrment), maxClose ] minTimeStampStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.timeStamp < tradingDay2.timeStamp })! minTimeStamp = minTimeStampStruct.timeStamp maxTimeStampStruct = closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in return tradingDay1.timeStamp < tradingDay2.timeStamp })! maxTimeStamp = maxTimeStampStruct.timeStamp xAxisValues.append(minTimeStamp) for i in 1...11 { dateComponent.month = i let nextMonth = Calendar.current.date(byAdding: dateComponent, to: minTimeStamp) xAxisValues.append(nextMonth!) } xAxisValues.append(maxTimeStamp) print("\(xAxisValues[12])") // prints 2023-08-04 00:00:00 +0000 } // end init var body: some View { HStack(alignment: .center) { VStack(alignment: .center) { Chart(closingValues, id:\.id) { LineMark( x: .value("Date", $0.timeStamp, unit: .day), y: .value("Closing", $0.close) ) .foregroundStyle(.blue) } // end chart .frame(width: 1000, height: 700, alignment: .center) .chartXAxisLabel(position: .bottom, alignment: .center, spacing: 15) { Text("Date") .font(.custom("Arial", size: 20)) } .chartYAxisLabel(position: .leading, alignment: .center, spacing: 20) { Text("Closing Value") .font(.custom("Arial", size: 20)) } .chartXAxis { AxisMarks(values: xAxisValues) { value in if let date = value.as(Date.self) { AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) { VStack(alignment: .leading) { Text(ChartMonthFormatter.string(from: date)) .font(.custom("Arial", size: 14)) Text(ChartYearFormatter.string(from: date)) .font(.custom("Arial", size: 14)) } // end v stack } // end axis label } // end if statement AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) .foregroundStyle(Color.black) AxisTick(centered: true, length: 0, stroke: .none) } } // end chart x axis .chartXScale(domain: [xAxisValues[0], xAxisValues[12]]) .chartYAxis { AxisMarks(position: .leading, values: yAxisValues) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) .foregroundStyle(Color.black) AxisTick(centered: true, length: 0, stroke: .none) AxisValueLabel(horizontalSpacing: 10) { if let yAxisValue = value.as(Double.self) { let stringValue = String(format: "$%.02f", yAxisValue) Text(stringValue) .font(.custom("Arial", size: 14)) } } } } .chartYScale(domain: [minClose, maxClose]) .chartPlotStyle { plotArea in plotArea.background(.white.opacity(0.9)) .border(.black, width: 1) } // end chart plot style } // end v stack .frame(width: 1200, height: 900, alignment: .center) } // end h stack } // end some view }
Replies
2
Boosts
0
Views
2.7k
Activity
Sep ’23