Swift Charts

RSS for tag

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

Swift Charts Documentation

Posts under Swift Charts tag

53 Posts
Sort by:
Post not yet marked as solved
0 Replies
354 Views
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!
Posted
by
Post not yet marked as solved
1 Replies
611 Views
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!
Posted
by
Post not yet marked as solved
1 Replies
448 Views
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)
Posted
by
Post not yet marked as solved
0 Replies
295 Views
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.
Posted
by
Post not yet marked as solved
0 Replies
412 Views
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 ?
Posted
by
Post not yet marked as solved
1 Replies
491 Views
I'm currently evaluating Swift Charts to use in my macOS app, where I need to (potentially) display a few millions of data points, ideally all of them at one time. I want to give users the possibility to zoom in & out, so the entire range of values could be displayed at one moment. However, starting at around 20K data points (on my computer), the Chart takes a little bit to set up, but the window resizing is laggy. The performance seems to decrease linearly (?), when dealing with 100K data points you can barely resize the window and the Chart setup/creation is noticeable enough. Dealing with 500K data points is out of the question, the app is pretty much not useable. So I'm wondering if anybody else had a similar issue and what can be done? Is there any "magic" Swift Charts setting that could improve the performance? I have a "data decimation" algorithm, and given no choice I will use it, but somehow I was hoping for Swift Charts to gracefully handle at least 100K data points (there are other libs which do this!). Also, limiting the displayed data range is out of the question for my case, this is a crucial feature of the app. Here's the code that I'm using, but it's the most basic one: struct DataPoint: Identifiable { var id: Double { Double(xValue) } let xValue: Int let yValue: Double } let dataPoints: [DataPoint] = (0..<100_000).map { DataPoint(xValue: $0, yValue: Double($0)) } struct MyChart: View { var body: some View { Chart(dataPoints) { dataPoint in PointMark(x: .value("Index", dataPoint.xValue), y: .value("Y Value", dataPoint.yValue)) } } } Some additional info, if it helps: The Chart is included in a AppKit window via NSHostingController (in my sample project the window contains nothing but the chart) The computer is a MacBook Pro, 2019 and is running macOS 10.14
Posted
by
Post not yet marked as solved
2 Replies
734 Views
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.
Posted
by
Post marked as solved
2 Replies
1.2k Views
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 }
Posted
by
Post not yet marked as solved
3 Replies
1.2k Views
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.
Posted
by
Post not yet marked as solved
0 Replies
541 Views
I want the line grow without a canvas resize so I need to scale the canvas before the animation. If I apply both X and Y Scale modifiers to set the domain, animation doesn't work, if I comment either of both, yes... Any idea why and any workaround? import SwiftUI import Charts struct Entry: Identifiable { var id = UUID() var time: Double var value: Double } struct ContentView: View { @State var data: [Entry] = [ .init(time: 0, value: 0), .init(time: 1, value: 1)] var body: some View { VStack{ Button("+"){ data.append(.init(time: 2, value: 3)) } Chart(data){entry in LineMark(x: .value("time", entry.time), y: .value("value", entry.value)) } .chartXScale(domain: 0...3) .chartYScale(domain: 0...3) .padding() .animation(.easeIn(duration:3), value: data) } } }
Posted
by
Post marked as solved
1 Replies
760 Views
I've encountered an animation glitch affecting the text for AxisMarks and AxisLabels in the SwiftUI Chart framework. Below are the sample project code and animated gif for reference: (I'm not being able to attach the gif for some reason. Here's my StackOverflow post with a the gift: https://stackoverflow.com/questions/77007744/swiftui-chart-text-animation-glitch-with-axismarks-and-axislabels) struct ContentView: View { @State var isDisplayingAge = true var body: some View { ChartView(data: ChartDataSample, isDisplayingAge: isDisplayingAge) .onTapGesture { withAnimation { isDisplayingAge.toggle() } } } } struct ChartData: Identifiable { let age: Int let presence: Int let grade: Int let id = UUID() } struct ChartView: View { let data: [ChartData] let isDisplayingAge: Bool let xAxis = [0, 50, 100] var body: some View { VStack { Chart { ForEach(data) { chartData in BarMark(x: .value("X Axis", isDisplayingAge ? chartData.age : chartData.presence), y: .value("Y Axis", chartData.grade)) } } .chartXAxis(content: { AxisMarks(position: .bottom, values: xAxis.map{$0}) { data in AxisValueLabel(String(xAxis[data.index]) + (isDisplayingAge ? " years" : " days")) } }) .chartXAxisLabel(content: { Text(isDisplayingAge ? "Data: age" : "Data: presence") }) } .padding(.horizontal, 13) } } As you can observe, when I tap the chart to trigger a content change with animation, the text for AxisMarks (e.g., x years / x days) and AxisLabels (e.g., Data: age / Data: presence) animates unusually. A portion of the text is temporarily replaced by an ellipsis ("...") during the animation. Interestingly, this issue occurs only in one direction of the animation. When transitioning from "year" to "day" or from "presence" to "age," the text simply gets replaced without any noticeable animation. Can anyone explain what's happening here? Ideally, I'd like the texts to either fade into each other or be replaced without any animation. Thank you.
Posted
by
Post not yet marked as solved
3 Replies
1.4k Views
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?
Posted
by
Post not yet marked as solved
0 Replies
441 Views
How to scale LineMark to fill all chart automatically? Here is my sample: import SwiftUI import Charts struct EnergyView: View { var body: some View { VStack { Chart { ForEach(DailyEnergy.mockData) { dailyEnergy in LineMark(x: .value("Data", dailyEnergy.date), y: .value("Value", dailyEnergy.energy)) PointMark(x: .value("Data", dailyEnergy.date), y: .value("Value", dailyEnergy.energy)) .annotation(alignment: .center, spacing: 10) { Text("\(Int(dailyEnergy.energy))") .minimumScaleFactor(0.5) .scaledToFit() .frame(width: 40) } } .interpolationMethod(.monotone) } }.frame(height: 100) } } struct EnergyView_Previews: PreviewProvider { static var previews: some View { EnergyView() } } struct DailyEnergy: Identifiable { let id: UUID = .init() let date: Date let energy: Double } extension DailyEnergy { static var mockData: [Self] { [ .init(date: "2023-08-01".formattedDate, energy: 1376), .init(date: "2023-08-02".formattedDate, energy: 1576), .init(date: "2023-08-03".formattedDate, energy: 1875), .init(date: "2023-08-04".formattedDate, energy: 1676), .init(date: "2023-08-05".formattedDate, energy: 1475), .init(date: "2023-08-06".formattedDate, energy: 1574), .init(date: "2023-08-07".formattedDate, energy: 1674) ] } } and here is result what I have: and here is result what I'm expect: I want to build LineMark on full chart view, but how I can do this? I tried to use scalledToFill(), but it change all chart instead only LineMark, also I tried to use .chartYScale(domain: 1200...2800), but in this case I can't be sure that all chart line will be fitted to chart view including my PointMark. Maybe Charts has any function to do this?
Posted
by
Post not yet marked as solved
0 Replies
616 Views
Does anyone know of to get the currently visible data items in chart (e.g. BarMarks) on iOS 17 when using chartScrollableAxes. From the WWDC23 video of session "Explore pie charts and interactivity in Swift Charts" at time 8:18 you see that the "Total sales" lists the visible time frame (e.g. May 4 - June 4, 2023) and a few seconds late when the chart scrolls the values do update.
Posted
by
Post not yet marked as solved
3 Replies
1.5k Views
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)! } }
Posted
by
Post not yet marked as solved
2 Replies
457 Views
When using charts framework to make a Bar Chart after creating my fake data and creating the chart in the contentView no x or y axis contents appeared I was following a tutorial and they appeared with him any one can help Bar Chart import SwiftUI import Charts struct Items : Identifiable { var id = UUID() let type : String let value : Double } struct ContentView: View { let items : [Items] = [ Items(type: "Medical", value: 10000), Items(type: "Engeneering", value: 5000), Items(type: "singing", value: 15000), Items(type: "pilot", value: 1000), Items(type: "athlete", value: 18000), ] ![]("https://developer.apple.com/forums/content/attachment/73dd58fb-2753-4d65-be30-ad4ae7ebb1be" "title=Screen Shot 2023-07-10 at 6.19.04 AM.png;width=854;height=1598") var body: some View { NavigationView{ ScrollView{ Chart(items){item in BarMark( x: .value("Job", item.type), y: .value("salary", item.value) ) .foregroundStyle(.brown) .cornerRadius(10) } .frame(height: 200) .padding() } .navigationTitle("Charts") } }
Posted
by