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

Swift Charts real time update LineMark is slow
Hello I'm currently working on a new gui in my App and I wanted to use the new Swift Charts Framework. It's very beautiful but I'm struggling with performance here. I want to draw a LineMark in realtime. I have code that create me a point every 25ms over a runtime of about 10 seconds. So I have round about 400 Samples which should drawn in realtime to the Chart so I can see the LineMark being drawn. On a first try I used a Binding to the Chart to update the Chart and after 2-3 seconds the ui becomes unresponsive and started lagging. I'm currently using an ObservableObject and the .drawingGroup modifier to improve the Performance. This Helps but it's not perfect. Is there a better way to increase the Performance or what's the way to have a realtime drawing line graph? Here's the Code I use: struct ChartView: View { @ObservedObject public var model = FNMeasurementModel() private let gradient = LinearGradient(gradient: Gradient (colors: [.mint.opacity(0.1),.mint.opacity(0.0)]), startPoint: .top, endPoint: .bottom) var body: some View { Chart() { ForEach(model.data) { item in LineMark( x: .value("Ratio", item.ratio ?? .zero), y: .value("Speed", item.speed ?? .zero) ) .interpolationMethod(.catmullRom) .foregroundStyle(.mint) AreaMark( x: .value("Ratio", item.ratio ?? .zero), y: .value("Speed", item.speed ?? .zero) ) .foregroundStyle(gradient) } } .chartXAxis{ AxisMarks(position: .bottom, values: stride(from: 0, to: 1.0, by: 0.2).map { $0 }) } .chartXScale(domain: 0...1.0) .chartYScale(domain: 0...100) .frame(height: 100) .padding(.vertical, 5) } } The ObservableObject class FNMeasurementModel: ObservableObject { @Published public var data: [FNMeasurementResult] = [] func append(_ sample: FNMeasurementResult) -> Void { data.append(sample) } func reset() -> Void { data.removeAll() } } My Result Type public class FNMeasurementResult: Identifiable { public var id: UUID = UUID() public var ratio: Double? public var speed: Double? public init(speed: Double? = nil, ratio: Double? = nil) { self.ratio = ratio self.speed = speed } }
1
0
2.6k
Apr ’23
Overlapping AreaMarks not working
I am trying to make a chart that looks like: Basically a couple overlapping range AreaMark's, a LineMark and a couple RuleMarks. However when I have two separate AreaMark's I get this: When one or the other of the AreaMark's ForEach loop is commented out it displays the proper graph. Its just the overlap of the two that is wonky. FYI - The top graph was generated by the SwiftUI Charts package on GitHub which we are trying to move away from. Thanks.
2
0
928
Apr ’23
How can I apply the modify my Swift Chart based on the ComplicationRenderingMode
For Apple Watch complications displayed on tinted faced, developers can use: @Environment(\.complicationRenderingMode) var renderingMode to see if the watch face is tinted. You can then use the .complicationForeground() modifier to set elements of the complication to match that tint color. (I appreciate that .complicationForeground() is now deprecated in favour of .widgetAccentable() but I believe the behaviour is the same). However, this can only be applied to a view I believe. I'd like to display a Swift Chart where only certain elements of the chart have the .complicationForeground() rather than the whole chart. For example, in one case I'd like the LineMark to pop with the tinted color of the complication whilst the rest of the complication get the gray default tint. Is there a way to do with with the current APIs? Thanks
2
0
1.3k
Apr ’23
Swift Charts Axis Adjustment
I am working on a Mac app that uses Swift Charts to visualize some data. I can initially plot the data fine. The problem is that I want the ability to "zoom" in on the data. to do this I change the range of the x or y axis using the following modifiers .chartXScale(domain: xMin...xMax) .chartYScale(domain: yMin...yMax) I use a drag gesture to change the values of xMin and xMax for example to zoom in on the data. This does have the effect that I want but the problem is it causes the line to start moving out of the chart area like show below. I don't understand why this is happening. I thought by changing the scale it would cause only the data that is visible on the chart to be displayed.
1
1
1.4k
Mar ’23
Swift Charts BarMark bar shape when stacked
Hi I'm trying to apply clip shape on a BarMark with stacked values and the result is that it's applying the shape for each stack instead for the whole bar. What I want to achieve: What I got: I noticed that corner radius is applied to the whole bar but just the top of it: Is there any way to get this capsule shape when stacked? My code is: enum Value: Int, Hashable, CaseIterable {     case ftb     case nb     case remaining     var color: Color {         switch self {         case .ftb:             return .tint1         case .nb:             return .tint2         case .ramaining:             return .gray4         }     } } @ViewBuilder var barChart: some View {         Chart {             ForEach(dates, id: \.self) { date in                 let incomeSummary = incomeSummaries.first(where: { $0.date?.inSameDay(as: date) == true })                 ForEach(Value.allCases, id: \.self) { value in                     barMark(for: value, date: date, incomeSummary: incomeSummary)                         .foregroundStyle(value.color)                 } //                .cornerRadius(20, style: .continuous) //                .clipShape(Capsule())             }         }         .chartXAxis {             AxisMarks(values: dates) { date in                 AxisValueLabel(format: .dateTime.weekday(), centered: true)             }         }         .chartYAxis {             AxisMarks { mark in                 AxisValueLabel()             }         }     } private func barMark(for value: Value, date: Date, incomeSummary: IncomeSummary?) -> BarMark {         let amount = amount(for: value, in: incomeSummary)         return BarMark(x: .value("WeekDay", date, unit: .day,                                  calendar: Calendar.localTime),                 y: .value("Income", amount))     } Another issue, I've noticed that when AxisValueLabel is centered the last bar looses its label, is it a bug?
0
3
1.7k
Mar ’23
SwiftCharts: How to clip data to specific range?
I found that can customise the range of the x and y axes. But my problem is that for line marks some data might just be outside the axes range. If I add .clipped to the chart that would limit it, but then it also clips off some of the axis marks. No Clipping: With Clipping: you see the green line go over the AxisValueLabel area and the topmost label is clipped off. One way I can imagine addressing this without enabling clipping is to create an interpolated value for values that are just outside the chart range so that the line ends exactly at the min/max.
5
2
2.8k
Mar ’23
Chart: How to achieve a specific X-axis (an awkward log scale)
I'm trying to determine how best to achieve a desired result within Swift Charts. I'm trying to make a sort-of "reversed" log chart. The use case here is for driving into the details of the percentiles from a series latency values stored within a histogram. The X axis percentile values I was hoping to achieve was something along the lines of: 10, 50, 90, 99, 99,9, 99.99, 99.999 With those values being fairly evenly distributed across the chart. If I look at this from an inverted sequence of: ( 1 - (some value) ).reversed() where the values are: 0.00001, 0.0001, 0.0001, 0.001, 0.01, 0.5, 0.1 But I've been struggling with how to start with those values, scale the X axis using a 1-value kind of setup, and then overlaying the values that are more human readable to achieve the end result. Any suggestions on how to tackle this scenario with customizing a chart axis?
1
0
2.1k
Mar ’23
Launch an animation when a value in picker changes
Hi, I have two charts on the page and you can switch between them with the picker. Can you please tell me how can I make them show with animation? I do not know how to start the animation when I change a chart in the picker. Thank you! struct ChartsView: View {     var stackedBarData: [ToyShape] = [         .init(type: "Cube", count: 0),         .init(type: "Sphere", count: 0),         .init(type: "Pyramid", count: 1),     ]     var charts = ["Bar chart", "Area chart"]     @State private var selectedChart = "Bar chart"     var body: some View {         VStack {             if selectedChart == "Bar chart" {                 Chart {                     ForEach(stackedBarData) { shape in                         BarMark(                             x: .value("Shape Type", shape.type),                             y: .value("Total Count", shape.count)                         )                     }                 }                 .padding(.vertical, 20)             } else if selectedChart == "Area chart" {                 Chart {                     ForEach(stackedBarData) { shape in                         AreaMark(                             x: .value("Shape Type", shape.type),                             y: .value("Total Count", shape.count)                         )                     }                 }                 .padding(.vertical, 20)             }             Picker("Select a chart", selection: $selectedChart) {                 ForEach(charts, id: \.self) {                     Text($0)                 }             }             .pickerStyle(.segmented)         }         .padding(16)     } }
0
0
979
Feb ’23
Trading charts tool integration
Hello developers, I'm currently working on an iOS application that requires trading chart functionality, and I'm looking for a solution that I can easily integrate into my app. I've heard about TradingView's charting and technical analysis tools, but I'm not sure if they offer a library that I can use. Can anyone recommend a charting tool that is easy to integrate into an iOS app? Ideally, the tool should offer real-time data streaming, support for multiple chart types, and customizable indicators and drawing tools. Any suggestions or recommendations would be greatly appreciated. Thank you!
0
0
803
Feb ’23
SwiftUI Charts - MTLTextureDescriptor has width (9649) greater than the maximum allowed size of 8192
Hi, SwiftUI Charts IOS 16.1 I get crash in the Simulator (tried iPhone or iPad). See console message below. The strange thing is that if I ran the same app on my iPhone 12, no crash. Thank you 2023-01-11 13:58:57.306324+1100 MyMoney[52429:14665675] Metal API Validation Enabled 2023-01-11 13:58:57.451214+1100 MyMoney[52429:14665675] [error] RBLayer: unable to create texture: BGRA8Unorm, [19057, 938] 2023-01-11 13:58:57.451426+1100 MyMoney[52429:14665675] [error] RBLayer: unable to create texture: BGRA8Unorm, [19057, 938] 2023-01-11 13:58:57.470351+1100 MyMoney[52429:14665675] -[MTLTextureDescriptorInternal validateWithDevice:], line 1344: error 'Texture Descriptor Validation MTLTextureDescriptor has width (9649) greater than the maximum allowed size of 8192. ' -[MTLTextureDescriptorInternal validateWithDevice:]:1344: failed assertion `Texture Descriptor Validation MTLTextureDescriptor has width (9649) greater than the maximum allowed size of 8192.
1
0
1.7k
Feb ’23
SwiftUI Charts Issue - Axis Marks
I'm having an issue with SwiftUI charts and was wondering if anyone knows of a solution or has also run into this. I've been trying to plot data for my app and the X axis does not show the dates and the Y axis only has axis marks 0-9. So, I tried to make another file instance to check what's going on. This is what I have import Charts import SwiftUI struct Exercise: Identifiable { let id = UUID() var dateCompleted: Date var reps: Int } struct ContentView: View { private var exerciseMaxRepsArray: [Exercise] = [] init() { // init dummy data for i in 0 ..< 20 { let date = Calendar.current.date(byAdding: .day, value: i, to: .now) ?? .now let rep = Int.random(in: 1...20) exerciseMaxRepsArray.append( Exercise(dateCompleted: date, reps: rep) ) } } var body: some View { GroupBox(label: Text("Daily Max Reps")) { Chart(exerciseMaxRepsArray) { e in LineMark(x: .value("Date", e.dateCompleted, unit: .day), y: .value("Reps", e.reps) ) } .chartYAxisLabel(position: .trailing, alignment: .center) { Text("Reps") } .chartXAxisLabel(position: .bottom, alignment: .center) { Text("Date") } } and this is the result: I've checked and the issue is not the frame. Has anyone else had this issue or have any clue what could be going on here?
1
0
2.2k
Feb ’23
Swift Charts use custom font for legend
We have a custom font we use through-out our app we've recently starting playing with Swift Charts but can't work out how to use our font in the chart legend easily. Currently we have a simple chart using the default .chartLegend(...). I've managed to use our font in the X-axis and Y-axis by creating our own labels using AxisValueLabel() {} However without making our own completely custom legend, is there a way to specify the font to use in the legend?
0
0
1.2k
Jan ’23
Charts: How do I position x axis value labels below the associated grid lines
I am working with the new Charts Framework. The axis value labels for the x axis are dates (mm/dd/yy). I have 5 vertical grid lines and am trying to get the dates to be centered below the associated grid line with no success. One additional problem is that the values are in an array that contains 5 dates but only the first 4 get displayed. Any solutions will be appreciated. Below is the code. struct LineChart: View { private var localArray: [TradingDayPrices] init(passedInArray: [TradingDayPrices]) { self.localArray = passedInArray } var body: some View { let minCloseValue: Double = localArray.map { $0.close }.min()! let maxCloseValue: Double = localArray.map { $0.close }.max()! let minDate: Date = localArray[0].timeStamp! let itemCount: Int = localArray.count - 1 let maxDate: Date = localArray[itemCount].timeStamp! Spacer() GroupBox (label: Text("VOO Closing Values For The Past Year") .font(.system(size: 20)) .fontWeight(.bold) .frame(width: 700, height: 50, alignment: .center)) { Chart { ForEach(localArray) { item in LineMark ( x: .value("TimeStamp", item.timeStamp!), y: .value("Close", item.close) ) .foregroundStyle(Color.blue) .lineStyle(StrokeStyle(lineWidth: 1.25)) } // end for each } // end chart .padding(50) .chartBackground { item in Color.white } .chartXAxisLabel(position: .bottom, alignment: .center) { Text("Date") .font(.system(size: 14)) .foregroundColor(Color.black) .frame(width: 50, height: 35, alignment: .bottom) } .chartYAxisLabel(position: .leading, alignment: .center, spacing: 0) { Text("Closing Values") .font(.system(size: 14)) .foregroundColor(Color.black) } .chartXAxis { AxisMarks (values: GetXAxisLabels(min: minDate, max: maxDate)) { value in AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisValueLabel() { if let localDate = value.as(Date.self) { let formattedDate = dateToStringFormatter.string(from: localDate) Text(formattedDate) .font(.system(size: 12)) .foregroundColor(Color.black) } } // end axis value label } // end axis marks } // end chart x axis .chartYAxis { AxisMarks (position: .leading, values: GetYAxisLabels(min: minCloseValue, max: maxCloseValue)) { value in AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisValueLabel() { if let localValue = value.as(Double.self) { let formattedValue = String(format: "$%.2f", localValue) Text(formattedValue) .font(.system(size: 12)) .foregroundColor(Color.black) } } } // end axis marks } // end chart y axis .chartXScale(domain: minDate...maxDate) .chartYScale(domain: minCloseValue...maxCloseValue) .frame(width: 700, height: 700, alignment: .center) } // end group box } // end of body } // end of structure func GetXAxisLabels(min: Date, max: Date) -> [Date] { var xLabels: [Date] = [] let increment: Int = 90 for i in 0...3 { let value = Calendar.current.date(byAdding: DateComponents(day: (i * increment)), to: min)! xLabels.append(value) } xLabels.append(max) print("\(xLabels)") return xLabels } func GetYAxisLabels(min: Double, max: Double) -> [Double] { var yLabels: [Double] = [] let increment: Double = (max - min) / 4 for i in 0...3 { let value = min + (Double(i) * increment) yLabels.append(value) } yLabels.append(max) return yLabels } let dateToStringFormatter: DateFormatter = { let result = DateFormatter() result.dateFormat = "MM/dd/yy" return result }()
2
1
4.0k
Jan ’23
SwiftUI Charts - Bar Chart (side by side) (not stacked), proxy value not working
Create a bar Chart with data displayed (side by side) instead of default (stacked bar chart) (using .position modifier) Issue: chart proxy value cannot find any value. If I change to stacked bar chart, then proxy value works ok. Sample code:-             Chart() {                 ForEach(barchartdata, id:\.self) { one_row in                     BarMark(                         x: .value("Date", one_row.shortDate),                         y: .value("$", one_row.steps)                     )   // LineMark                     .foregroundStyle(by: .value("Name", one_row.name))                     .symbol(by: .value("Name", one_row.name))                     .interpolationMethod(.catmullRom)                     .position(by: .value("Name", one_row.name))                 }             }             .chartPlotStyle { plotArea in                 plotArea                     .frame(width: UIScreen.main.bounds.size.width * 6/8)                     .background(.blue.opacity(0.2))                     .border(.blue, width: 1)             }             .chartOverlay { proxy in                 GeometryReader { geometry in                     RoundedRectangle(cornerRadius : 5)                         .fill(.clear)                         .contentShape(Rectangle())                         .onTapGesture { location in                             updateSelectedMonth(location: location, proxy: proxy, geometry: geometry)                         }  // onTapGesture                                     }             } ....     func updateSelectedMonth(location : CGPoint, proxy: ChartProxy, geometry : GeometryProxy) { let local_location = CGPoint(             x: location.x - geometry[proxy.plotAreaFrame].origin.x,             y: location.y - geometry[proxy.plotAreaFrame].origin.y)         let (sel_date, sel_steps) = proxy.value(at: local_location, as: (Date, Int64).self) ?? (nil,nil) }
0
1
2.2k
Jan ’23
Chart moves itself unintentionally with a big frame size
I try to make an interactive chart view. However, in a specific condition, the chart moves iteself unintentionally. In my test code, this phenomenon occurs when the frame width is over 652.5. (And, this is also relevant to the height) Test Movie OK: NG: If you are OK, could you tell me what is a problem in my code? My test code is the followings: import SwiftUI import Charts struct ContentView: View {   @State var chartW = 652.45   @State var basisDate: Date = Date2StartOnADay(date: Date())   @State var dateRange: Double = 7   @State var dateB = Date2StartOnADay(date: Date()).addingTimeInterval(Double(-7*24*60*60))   @State var dateE = Date2StartOnADay(date: Date())   var body: some View {     VStack {       Slider(value: $chartW, in: 652.45 ... 652.55)       Text("\(chartW)")       DailyChartView(dateB: $dateB, dateE: $dateE, basisDate: $basisDate, dateRange: $dateRange)         .frame(width: chartW, height: 300)     }   } } struct ContentView_Previews: PreviewProvider {   static var previews: some View {     ContentView()   } } struct DailyChartView: View {   @Binding var dateB: Date   @Binding var dateE: Date   @Binding var basisDate: Date   @Binding var dateRange: Double   var yMin: Double = 0.0   var yMax: Double = 100.0   var isFixedYRange: Bool = true   @State var dt: TimeInterval?       var body: some View {     Chart {       AreaMark(x: .value("date", Date().addingTimeInterval(-2*24*60*60)),            y: .value("value", 10)       )       AreaMark(x: .value("date", Date().addingTimeInterval(-24*60*60)),            y: .value("value", 50)       )       AreaMark(x: .value("date", Date()),            y: .value("value", 20)       )       AreaMark(x: .value("date", Date().addingTimeInterval(24*60*60)),            y: .value("value", 70)       )     }     .chartXScale(domain: dateB ... dateE)     .chartYScale(domain: yMin ... yMax)     .chartOverlay { proxy in       GeometryReader { geometry in         Rectangle().fill(.clear).contentShape(Rectangle())           .gesture(DragGesture(minimumDistance: 8)             .onChanged {value in               let startX = value.startLocation.x - geometry[proxy.plotAreaFrame].origin.x               let currentX = value.location.x - geometry[proxy.plotAreaFrame].origin.x               if let startDate: Date = proxy.value(atX: startX),                 let currentDate: Date = proxy.value(atX: currentX) {                 dt = currentDate.timeIntervalSince(startDate)                 dateB = basisDate.addingTimeInterval(-dateRange*24*60*60-dt!)                 dateE = basisDate.addingTimeInterval(-dt!)               }             }             .onEnded {_ in               basisDate = dateE             }           )       }     }     .clipped()   } } func Date2StartOnADay(date: Date) -> Date {   let cal = Calendar(identifier: .gregorian)   let comp = cal.dateComponents(     [Calendar.Component.year, Calendar.Component.month, Calendar.Component.day,      Calendar.Component.hour, Calendar.Component.minute, Calendar.Component.second, Calendar.Component.nanosecond],      from: date)   let startOnADay = cal.date(from: DateComponents(year: comp.year!, month: comp.month!, day: comp.day))   return startOnADay! }
0
0
812
Jan ’23
interpolating AreaMarks beyond the edge of the chart
I'm making an app that shows tides. It's approximately a sine wave going smoothly in and out. If I use only the low and high tides times, the line should curve slowly between them. If the first value on the chart is a low tide and the next is a high tide I want the line to start from horizontal, get steeper and then flatten out as the tide peaks. This happens for all the values within the chart except for the first and last because there's no data outside of the chart's range to tell the interpolation code where the line needs to curve to. If I add extra data beyond what I am displaying, the chart adapts and shows that data too, then I have nothing beyond that. Some pictures might help Here the first and last points look like the tide is still going down/up rather fast, where as the other points all slow down as they reach the high/low value I tried using .chartXScale(domain: start...end) to set the bounds of the x-axis, but the chart gets drawn beyond those bounds I believe I can fake it by adding my own interpolated points just seconds before the first and after the last point with the same value as the true data. This would force the interpolation to flatten out, but I'd rather use the real data and control the chart sounds properly
0
0
1k
Jan ’23
problem is solved
problem is solved
Replies
0
Boosts
0
Views
571
Activity
Apr ’23
Swift Charts real time update LineMark is slow
Hello I'm currently working on a new gui in my App and I wanted to use the new Swift Charts Framework. It's very beautiful but I'm struggling with performance here. I want to draw a LineMark in realtime. I have code that create me a point every 25ms over a runtime of about 10 seconds. So I have round about 400 Samples which should drawn in realtime to the Chart so I can see the LineMark being drawn. On a first try I used a Binding to the Chart to update the Chart and after 2-3 seconds the ui becomes unresponsive and started lagging. I'm currently using an ObservableObject and the .drawingGroup modifier to improve the Performance. This Helps but it's not perfect. Is there a better way to increase the Performance or what's the way to have a realtime drawing line graph? Here's the Code I use: struct ChartView: View { @ObservedObject public var model = FNMeasurementModel() private let gradient = LinearGradient(gradient: Gradient (colors: [.mint.opacity(0.1),.mint.opacity(0.0)]), startPoint: .top, endPoint: .bottom) var body: some View { Chart() { ForEach(model.data) { item in LineMark( x: .value("Ratio", item.ratio ?? .zero), y: .value("Speed", item.speed ?? .zero) ) .interpolationMethod(.catmullRom) .foregroundStyle(.mint) AreaMark( x: .value("Ratio", item.ratio ?? .zero), y: .value("Speed", item.speed ?? .zero) ) .foregroundStyle(gradient) } } .chartXAxis{ AxisMarks(position: .bottom, values: stride(from: 0, to: 1.0, by: 0.2).map { $0 }) } .chartXScale(domain: 0...1.0) .chartYScale(domain: 0...100) .frame(height: 100) .padding(.vertical, 5) } } The ObservableObject class FNMeasurementModel: ObservableObject { @Published public var data: [FNMeasurementResult] = [] func append(_ sample: FNMeasurementResult) -> Void { data.append(sample) } func reset() -> Void { data.removeAll() } } My Result Type public class FNMeasurementResult: Identifiable { public var id: UUID = UUID() public var ratio: Double? public var speed: Double? public init(speed: Double? = nil, ratio: Double? = nil) { self.ratio = ratio self.speed = speed } }
Replies
1
Boosts
0
Views
2.6k
Activity
Apr ’23
Overlapping AreaMarks not working
I am trying to make a chart that looks like: Basically a couple overlapping range AreaMark's, a LineMark and a couple RuleMarks. However when I have two separate AreaMark's I get this: When one or the other of the AreaMark's ForEach loop is commented out it displays the proper graph. Its just the overlap of the two that is wonky. FYI - The top graph was generated by the SwiftUI Charts package on GitHub which we are trying to move away from. Thanks.
Replies
2
Boosts
0
Views
928
Activity
Apr ’23
Using Charts with the storyboard in xcode
Hello, I'm trying to find an easy way to use "Swift Charts" in Storyboard mode with xcode. I understood how it works with swiftUI but can it be done with storyboard only? THANKS
Replies
1
Boosts
0
Views
572
Activity
Apr ’23
How can I apply the modify my Swift Chart based on the ComplicationRenderingMode
For Apple Watch complications displayed on tinted faced, developers can use: @Environment(\.complicationRenderingMode) var renderingMode to see if the watch face is tinted. You can then use the .complicationForeground() modifier to set elements of the complication to match that tint color. (I appreciate that .complicationForeground() is now deprecated in favour of .widgetAccentable() but I believe the behaviour is the same). However, this can only be applied to a view I believe. I'd like to display a Swift Chart where only certain elements of the chart have the .complicationForeground() rather than the whole chart. For example, in one case I'd like the LineMark to pop with the tinted color of the complication whilst the rest of the complication get the gray default tint. Is there a way to do with with the current APIs? Thanks
Replies
2
Boosts
0
Views
1.3k
Activity
Apr ’23
Swift Charts Axis Adjustment
I am working on a Mac app that uses Swift Charts to visualize some data. I can initially plot the data fine. The problem is that I want the ability to "zoom" in on the data. to do this I change the range of the x or y axis using the following modifiers .chartXScale(domain: xMin...xMax) .chartYScale(domain: yMin...yMax) I use a drag gesture to change the values of xMin and xMax for example to zoom in on the data. This does have the effect that I want but the problem is it causes the line to start moving out of the chart area like show below. I don't understand why this is happening. I thought by changing the scale it would cause only the data that is visible on the chart to be displayed.
Replies
1
Boosts
1
Views
1.4k
Activity
Mar ’23
Swift Charts BarMark bar shape when stacked
Hi I'm trying to apply clip shape on a BarMark with stacked values and the result is that it's applying the shape for each stack instead for the whole bar. What I want to achieve: What I got: I noticed that corner radius is applied to the whole bar but just the top of it: Is there any way to get this capsule shape when stacked? My code is: enum Value: Int, Hashable, CaseIterable {     case ftb     case nb     case remaining     var color: Color {         switch self {         case .ftb:             return .tint1         case .nb:             return .tint2         case .ramaining:             return .gray4         }     } } @ViewBuilder var barChart: some View {         Chart {             ForEach(dates, id: \.self) { date in                 let incomeSummary = incomeSummaries.first(where: { $0.date?.inSameDay(as: date) == true })                 ForEach(Value.allCases, id: \.self) { value in                     barMark(for: value, date: date, incomeSummary: incomeSummary)                         .foregroundStyle(value.color)                 } //                .cornerRadius(20, style: .continuous) //                .clipShape(Capsule())             }         }         .chartXAxis {             AxisMarks(values: dates) { date in                 AxisValueLabel(format: .dateTime.weekday(), centered: true)             }         }         .chartYAxis {             AxisMarks { mark in                 AxisValueLabel()             }         }     } private func barMark(for value: Value, date: Date, incomeSummary: IncomeSummary?) -> BarMark {         let amount = amount(for: value, in: incomeSummary)         return BarMark(x: .value("WeekDay", date, unit: .day,                                  calendar: Calendar.localTime),                 y: .value("Income", amount))     } Another issue, I've noticed that when AxisValueLabel is centered the last bar looses its label, is it a bug?
Replies
0
Boosts
3
Views
1.7k
Activity
Mar ’23
Does the new Swift Charts support pie charts?
I now watched all 4 charts WWDC22 videos. It looks like there is no pie chart support. Do I need to build such style by myself or is there a way to implement this in the new Swift Charts framework?
Replies
4
Boosts
1
Views
2.3k
Activity
Mar ’23
SwiftCharts: How to clip data to specific range?
I found that can customise the range of the x and y axes. But my problem is that for line marks some data might just be outside the axes range. If I add .clipped to the chart that would limit it, but then it also clips off some of the axis marks. No Clipping: With Clipping: you see the green line go over the AxisValueLabel area and the topmost label is clipped off. One way I can imagine addressing this without enabling clipping is to create an interpolated value for values that are just outside the chart range so that the line ends exactly at the min/max.
Replies
5
Boosts
2
Views
2.8k
Activity
Mar ’23
Chart: How to achieve a specific X-axis (an awkward log scale)
I'm trying to determine how best to achieve a desired result within Swift Charts. I'm trying to make a sort-of "reversed" log chart. The use case here is for driving into the details of the percentiles from a series latency values stored within a histogram. The X axis percentile values I was hoping to achieve was something along the lines of: 10, 50, 90, 99, 99,9, 99.99, 99.999 With those values being fairly evenly distributed across the chart. If I look at this from an inverted sequence of: ( 1 - (some value) ).reversed() where the values are: 0.00001, 0.0001, 0.0001, 0.001, 0.01, 0.5, 0.1 But I've been struggling with how to start with those values, scale the X axis using a 1-value kind of setup, and then overlaying the values that are more human readable to achieve the end result. Any suggestions on how to tackle this scenario with customizing a chart axis?
Replies
1
Boosts
0
Views
2.1k
Activity
Mar ’23
Launch an animation when a value in picker changes
Hi, I have two charts on the page and you can switch between them with the picker. Can you please tell me how can I make them show with animation? I do not know how to start the animation when I change a chart in the picker. Thank you! struct ChartsView: View {     var stackedBarData: [ToyShape] = [         .init(type: "Cube", count: 0),         .init(type: "Sphere", count: 0),         .init(type: "Pyramid", count: 1),     ]     var charts = ["Bar chart", "Area chart"]     @State private var selectedChart = "Bar chart"     var body: some View {         VStack {             if selectedChart == "Bar chart" {                 Chart {                     ForEach(stackedBarData) { shape in                         BarMark(                             x: .value("Shape Type", shape.type),                             y: .value("Total Count", shape.count)                         )                     }                 }                 .padding(.vertical, 20)             } else if selectedChart == "Area chart" {                 Chart {                     ForEach(stackedBarData) { shape in                         AreaMark(                             x: .value("Shape Type", shape.type),                             y: .value("Total Count", shape.count)                         )                     }                 }                 .padding(.vertical, 20)             }             Picker("Select a chart", selection: $selectedChart) {                 ForEach(charts, id: \.self) {                     Text($0)                 }             }             .pickerStyle(.segmented)         }         .padding(16)     } }
Replies
0
Boosts
0
Views
979
Activity
Feb ’23
Adapt SwiftUI Chart Colour on Cell Selection
How do I best adapt the color of my SwiftUI charts when the cell in a list is selected? The text color seems to be changing automatically to white, but how do I achieve the same for the graph? I'm using primary and secondary color in my graph like this: LineMark(...) .foregroundStyle(.primary) LineMark(...) .foregroundStyle(.secondary)
Replies
0
Boosts
1
Views
891
Activity
Feb ’23
Trading charts tool integration
Hello developers, I'm currently working on an iOS application that requires trading chart functionality, and I'm looking for a solution that I can easily integrate into my app. I've heard about TradingView's charting and technical analysis tools, but I'm not sure if they offer a library that I can use. Can anyone recommend a charting tool that is easy to integrate into an iOS app? Ideally, the tool should offer real-time data streaming, support for multiple chart types, and customizable indicators and drawing tools. Any suggestions or recommendations would be greatly appreciated. Thank you!
Replies
0
Boosts
0
Views
803
Activity
Feb ’23
SwiftUI Charts - MTLTextureDescriptor has width (9649) greater than the maximum allowed size of 8192
Hi, SwiftUI Charts IOS 16.1 I get crash in the Simulator (tried iPhone or iPad). See console message below. The strange thing is that if I ran the same app on my iPhone 12, no crash. Thank you 2023-01-11 13:58:57.306324+1100 MyMoney[52429:14665675] Metal API Validation Enabled 2023-01-11 13:58:57.451214+1100 MyMoney[52429:14665675] [error] RBLayer: unable to create texture: BGRA8Unorm, [19057, 938] 2023-01-11 13:58:57.451426+1100 MyMoney[52429:14665675] [error] RBLayer: unable to create texture: BGRA8Unorm, [19057, 938] 2023-01-11 13:58:57.470351+1100 MyMoney[52429:14665675] -[MTLTextureDescriptorInternal validateWithDevice:], line 1344: error 'Texture Descriptor Validation MTLTextureDescriptor has width (9649) greater than the maximum allowed size of 8192. ' -[MTLTextureDescriptorInternal validateWithDevice:]:1344: failed assertion `Texture Descriptor Validation MTLTextureDescriptor has width (9649) greater than the maximum allowed size of 8192.
Replies
1
Boosts
0
Views
1.7k
Activity
Feb ’23
SwiftUI Charts Issue - Axis Marks
I'm having an issue with SwiftUI charts and was wondering if anyone knows of a solution or has also run into this. I've been trying to plot data for my app and the X axis does not show the dates and the Y axis only has axis marks 0-9. So, I tried to make another file instance to check what's going on. This is what I have import Charts import SwiftUI struct Exercise: Identifiable { let id = UUID() var dateCompleted: Date var reps: Int } struct ContentView: View { private var exerciseMaxRepsArray: [Exercise] = [] init() { // init dummy data for i in 0 ..< 20 { let date = Calendar.current.date(byAdding: .day, value: i, to: .now) ?? .now let rep = Int.random(in: 1...20) exerciseMaxRepsArray.append( Exercise(dateCompleted: date, reps: rep) ) } } var body: some View { GroupBox(label: Text("Daily Max Reps")) { Chart(exerciseMaxRepsArray) { e in LineMark(x: .value("Date", e.dateCompleted, unit: .day), y: .value("Reps", e.reps) ) } .chartYAxisLabel(position: .trailing, alignment: .center) { Text("Reps") } .chartXAxisLabel(position: .bottom, alignment: .center) { Text("Date") } } and this is the result: I've checked and the issue is not the frame. Has anyone else had this issue or have any clue what could be going on here?
Replies
1
Boosts
0
Views
2.2k
Activity
Feb ’23
Swift Charts use custom font for legend
We have a custom font we use through-out our app we've recently starting playing with Swift Charts but can't work out how to use our font in the chart legend easily. Currently we have a simple chart using the default .chartLegend(...). I've managed to use our font in the X-axis and Y-axis by creating our own labels using AxisValueLabel() {} However without making our own completely custom legend, is there a way to specify the font to use in the legend?
Replies
0
Boosts
0
Views
1.2k
Activity
Jan ’23
Charts: How do I position x axis value labels below the associated grid lines
I am working with the new Charts Framework. The axis value labels for the x axis are dates (mm/dd/yy). I have 5 vertical grid lines and am trying to get the dates to be centered below the associated grid line with no success. One additional problem is that the values are in an array that contains 5 dates but only the first 4 get displayed. Any solutions will be appreciated. Below is the code. struct LineChart: View { private var localArray: [TradingDayPrices] init(passedInArray: [TradingDayPrices]) { self.localArray = passedInArray } var body: some View { let minCloseValue: Double = localArray.map { $0.close }.min()! let maxCloseValue: Double = localArray.map { $0.close }.max()! let minDate: Date = localArray[0].timeStamp! let itemCount: Int = localArray.count - 1 let maxDate: Date = localArray[itemCount].timeStamp! Spacer() GroupBox (label: Text("VOO Closing Values For The Past Year") .font(.system(size: 20)) .fontWeight(.bold) .frame(width: 700, height: 50, alignment: .center)) { Chart { ForEach(localArray) { item in LineMark ( x: .value("TimeStamp", item.timeStamp!), y: .value("Close", item.close) ) .foregroundStyle(Color.blue) .lineStyle(StrokeStyle(lineWidth: 1.25)) } // end for each } // end chart .padding(50) .chartBackground { item in Color.white } .chartXAxisLabel(position: .bottom, alignment: .center) { Text("Date") .font(.system(size: 14)) .foregroundColor(Color.black) .frame(width: 50, height: 35, alignment: .bottom) } .chartYAxisLabel(position: .leading, alignment: .center, spacing: 0) { Text("Closing Values") .font(.system(size: 14)) .foregroundColor(Color.black) } .chartXAxis { AxisMarks (values: GetXAxisLabels(min: minDate, max: maxDate)) { value in AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisValueLabel() { if let localDate = value.as(Date.self) { let formattedDate = dateToStringFormatter.string(from: localDate) Text(formattedDate) .font(.system(size: 12)) .foregroundColor(Color.black) } } // end axis value label } // end axis marks } // end chart x axis .chartYAxis { AxisMarks (position: .leading, values: GetYAxisLabels(min: minCloseValue, max: maxCloseValue)) { value in AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisValueLabel() { if let localValue = value.as(Double.self) { let formattedValue = String(format: "$%.2f", localValue) Text(formattedValue) .font(.system(size: 12)) .foregroundColor(Color.black) } } } // end axis marks } // end chart y axis .chartXScale(domain: minDate...maxDate) .chartYScale(domain: minCloseValue...maxCloseValue) .frame(width: 700, height: 700, alignment: .center) } // end group box } // end of body } // end of structure func GetXAxisLabels(min: Date, max: Date) -> [Date] { var xLabels: [Date] = [] let increment: Int = 90 for i in 0...3 { let value = Calendar.current.date(byAdding: DateComponents(day: (i * increment)), to: min)! xLabels.append(value) } xLabels.append(max) print("\(xLabels)") return xLabels } func GetYAxisLabels(min: Double, max: Double) -> [Double] { var yLabels: [Double] = [] let increment: Double = (max - min) / 4 for i in 0...3 { let value = min + (Double(i) * increment) yLabels.append(value) } yLabels.append(max) return yLabels } let dateToStringFormatter: DateFormatter = { let result = DateFormatter() result.dateFormat = "MM/dd/yy" return result }()
Replies
2
Boosts
1
Views
4.0k
Activity
Jan ’23
SwiftUI Charts - Bar Chart (side by side) (not stacked), proxy value not working
Create a bar Chart with data displayed (side by side) instead of default (stacked bar chart) (using .position modifier) Issue: chart proxy value cannot find any value. If I change to stacked bar chart, then proxy value works ok. Sample code:-             Chart() {                 ForEach(barchartdata, id:\.self) { one_row in                     BarMark(                         x: .value("Date", one_row.shortDate),                         y: .value("$", one_row.steps)                     )   // LineMark                     .foregroundStyle(by: .value("Name", one_row.name))                     .symbol(by: .value("Name", one_row.name))                     .interpolationMethod(.catmullRom)                     .position(by: .value("Name", one_row.name))                 }             }             .chartPlotStyle { plotArea in                 plotArea                     .frame(width: UIScreen.main.bounds.size.width * 6/8)                     .background(.blue.opacity(0.2))                     .border(.blue, width: 1)             }             .chartOverlay { proxy in                 GeometryReader { geometry in                     RoundedRectangle(cornerRadius : 5)                         .fill(.clear)                         .contentShape(Rectangle())                         .onTapGesture { location in                             updateSelectedMonth(location: location, proxy: proxy, geometry: geometry)                         }  // onTapGesture                                     }             } ....     func updateSelectedMonth(location : CGPoint, proxy: ChartProxy, geometry : GeometryProxy) { let local_location = CGPoint(             x: location.x - geometry[proxy.plotAreaFrame].origin.x,             y: location.y - geometry[proxy.plotAreaFrame].origin.y)         let (sel_date, sel_steps) = proxy.value(at: local_location, as: (Date, Int64).self) ?? (nil,nil) }
Replies
0
Boosts
1
Views
2.2k
Activity
Jan ’23
Chart moves itself unintentionally with a big frame size
I try to make an interactive chart view. However, in a specific condition, the chart moves iteself unintentionally. In my test code, this phenomenon occurs when the frame width is over 652.5. (And, this is also relevant to the height) Test Movie OK: NG: If you are OK, could you tell me what is a problem in my code? My test code is the followings: import SwiftUI import Charts struct ContentView: View {   @State var chartW = 652.45   @State var basisDate: Date = Date2StartOnADay(date: Date())   @State var dateRange: Double = 7   @State var dateB = Date2StartOnADay(date: Date()).addingTimeInterval(Double(-7*24*60*60))   @State var dateE = Date2StartOnADay(date: Date())   var body: some View {     VStack {       Slider(value: $chartW, in: 652.45 ... 652.55)       Text("\(chartW)")       DailyChartView(dateB: $dateB, dateE: $dateE, basisDate: $basisDate, dateRange: $dateRange)         .frame(width: chartW, height: 300)     }   } } struct ContentView_Previews: PreviewProvider {   static var previews: some View {     ContentView()   } } struct DailyChartView: View {   @Binding var dateB: Date   @Binding var dateE: Date   @Binding var basisDate: Date   @Binding var dateRange: Double   var yMin: Double = 0.0   var yMax: Double = 100.0   var isFixedYRange: Bool = true   @State var dt: TimeInterval?       var body: some View {     Chart {       AreaMark(x: .value("date", Date().addingTimeInterval(-2*24*60*60)),            y: .value("value", 10)       )       AreaMark(x: .value("date", Date().addingTimeInterval(-24*60*60)),            y: .value("value", 50)       )       AreaMark(x: .value("date", Date()),            y: .value("value", 20)       )       AreaMark(x: .value("date", Date().addingTimeInterval(24*60*60)),            y: .value("value", 70)       )     }     .chartXScale(domain: dateB ... dateE)     .chartYScale(domain: yMin ... yMax)     .chartOverlay { proxy in       GeometryReader { geometry in         Rectangle().fill(.clear).contentShape(Rectangle())           .gesture(DragGesture(minimumDistance: 8)             .onChanged {value in               let startX = value.startLocation.x - geometry[proxy.plotAreaFrame].origin.x               let currentX = value.location.x - geometry[proxy.plotAreaFrame].origin.x               if let startDate: Date = proxy.value(atX: startX),                 let currentDate: Date = proxy.value(atX: currentX) {                 dt = currentDate.timeIntervalSince(startDate)                 dateB = basisDate.addingTimeInterval(-dateRange*24*60*60-dt!)                 dateE = basisDate.addingTimeInterval(-dt!)               }             }             .onEnded {_ in               basisDate = dateE             }           )       }     }     .clipped()   } } func Date2StartOnADay(date: Date) -> Date {   let cal = Calendar(identifier: .gregorian)   let comp = cal.dateComponents(     [Calendar.Component.year, Calendar.Component.month, Calendar.Component.day,      Calendar.Component.hour, Calendar.Component.minute, Calendar.Component.second, Calendar.Component.nanosecond],      from: date)   let startOnADay = cal.date(from: DateComponents(year: comp.year!, month: comp.month!, day: comp.day))   return startOnADay! }
Replies
0
Boosts
0
Views
812
Activity
Jan ’23
interpolating AreaMarks beyond the edge of the chart
I'm making an app that shows tides. It's approximately a sine wave going smoothly in and out. If I use only the low and high tides times, the line should curve slowly between them. If the first value on the chart is a low tide and the next is a high tide I want the line to start from horizontal, get steeper and then flatten out as the tide peaks. This happens for all the values within the chart except for the first and last because there's no data outside of the chart's range to tell the interpolation code where the line needs to curve to. If I add extra data beyond what I am displaying, the chart adapts and shows that data too, then I have nothing beyond that. Some pictures might help Here the first and last points look like the tide is still going down/up rather fast, where as the other points all slow down as they reach the high/low value I tried using .chartXScale(domain: start...end) to set the bounds of the x-axis, but the chart gets drawn beyond those bounds I believe I can fake it by adding my own interpolated points just seconds before the first and after the last point with the same value as the true data. This would force the interpolation to flatten out, but I'd rather use the real data and control the chart sounds properly
Replies
0
Boosts
0
Views
1k
Activity
Jan ’23