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

56 Posts
Sort by:
Post not yet marked as solved
0 Replies
48 Views
Hello all, if I enable the .chartScrollableAxes(.horizontal) and .chartXVisibleDomain(length: length) for a chart view to zoom in the screenshot of the view misses the graphs. I use this extension: `extension View { @MainActor func snapshot() { let renderer = ImageRenderer(content: self) if let exportImage = renderer.nsImage { let pasteboard = NSPasteboard.general pasteboard.clearContents() pasteboard.writeObjects([exportImage]) } } }` The screenshot is taken with: Button("Snap") { let view = ChartView(text: $statusText, length: $chartLength) .padding() .frame(width: 1500, height: 500) view.snapshot() } If I omit .chartScrollableAxes(.horizontal) the snapshot is ok and the graphs are visible in the image but then a zoom is not possible and the whole range is shown. Any ideas?
Posted
by Zettifour.
Last updated
.
Post not yet marked as solved
4 Replies
181 Views
I have multiple barmark Charts in a List for SwiftUI. For app running on iOS 17.4.1, and one running on MacOS Sonoma 14.4.1, by scrolling up and down on the list, the order of charts changes. Sometimes one chart will replace another chart, showing duplicate charts in the List. This did not happen for iOS 17.3, and earlier OS versions. Want to see if anyone else face the same issue. I have checked that correct chart model is used in onAppear, but what is displayed in Chart is not corresponding to the chart model.
Posted Last updated
.
Post not yet marked as solved
0 Replies
114 Views
I tried to narrow down the y-axis and use the clipped() to crop the excess. However, the clipped portion is too small, causing some of the chart to render above the x-axis. Is there any way to fix this, or any way to have the framework automatically set the y-axis range based on the data?
Posted
by zacJI.
Last updated
.
Post not yet marked as solved
1 Replies
364 Views
I created a SwiftChart as below and I would like to have two YAxis, one for amount and the second for count. So, the amount YAxis is a different scale then the count YAxis. Does anybody have an example of this or shed some light on coding two different YAxis? Thanks ForEach(seriesArt) { series in ForEach(series.chartSeries.chartEntry) { BarMark( x: .value("Tier", $0.tier), y: .value("Price", $0.keyValue) ) } .foregroundStyle(by: .value("Count", series.chartCategory)) .position(by: .value("Price", series.chartCategory)) } } .frame(width: 400, height: 200) .chartXAxis { AxisMarks(position: .bottom, values: .automatic) { AxisValueLabel() .foregroundStyle(Color.white) } } .chartYAxis { AxisMarks(position: .leading, values: .automatic) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) AxisValueLabel() { if let intValue = value.as(Int.self) { Text("\(intValue)") .font(.system(size: 10)) .foregroundColor(.white) } } } .chartYAixs - for count sum by tier which needs to be a different scale from the amount YAxis } } }
Posted
by BigEagle.
Last updated
.
Post not yet marked as solved
1 Replies
177 Views
Hello Apple Developers, I am trying to get the annotation text (the percentages) to stay on the outside perimeter of the pie chart and not in the middle of the pie chart like it currently is. Is there possibly a way to increase the radius of the annotation text to be that of the pie chart edge and maybe a little more? I don't know. Please help me out. What I currently have:
Posted Last updated
.
Post not yet marked as solved
1 Replies
229 Views
Hi All, Please excuse my relatively basic question but I am new to swift programming and I am battling with a project. I currently have an app that receives data from an Arduino using ble and displays the data as an integer. I used this medium article From Arduino programming to iOS App development as a guide for most of the functionality but changed the sensor data being sent to better suit my project requirements. Based on the link above, I have all of the bluetooth handling in PeripheralUseCase.swift file and then I have the ConnectView file for the display: @ObservedObject var viewModel: ConnectViewModel @Environment(\.dismiss) var dismiss @State var isToggleOn: Bool = false @State var isPeripheralReady: Bool = false @State var lastPressure: Int = 0 var body: some View { VStack { Text(viewModel.connectedPeripheral.name ?? "Unknown") .font(.title) ZStack { CardView() VStack { Text("Surface") HStack { Button("Flats") { viewModel.flats() } .disabled(!isPeripheralReady) .buttonStyle(.borderedProminent) Button("FlatPoint") { viewModel.flatPoint() } .disabled(!isPeripheralReady) .buttonStyle(.borderedProminent) Button("Points") { viewModel.points() } .disabled(!isPeripheralReady) .buttonStyle(.borderedProminent) } } } ZStack { CardView() VStack { Text("\(lastPressure) kPa") .font(.largeTitle) HStack { Spacer() .frame(alignment: .trailing) Toggle("Notify", isOn: $isToggleOn) .disabled(!isPeripheralReady) Spacer() .frame(alignment: .trailing) } } } Spacer() .frame(maxHeight:.infinity) Button { dismiss() } label: { Text("Disconnect") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .padding(.horizontal) } .onChange(of: isToggleOn) { newValue in if newValue == true { viewModel.startNotifyPressure() } else { viewModel.stopNotifyPressure() } let startTime = Date().timeIntervalSince1970 } .onReceive(viewModel.$state) { state in switch state { case .ready: isPeripheralReady = true case let .Pressure(temp): lastPressure = temp default: print("Not handled") } } } } struct PeripheralView_Previews: PreviewProvider { final class FakeUseCase: PeripheralUseCaseProtocol { var peripheral: Peripheral? var onWriteLedState: ((Bool) -> Void)? var onReadPressure: ((Int) -> Void)? var onPeripheralReady: (() -> Void)? var onError: ((Error) -> Void)? func writeLedState(isOn: String) {} func readPressure() { onReadPressure?(25) } func notifyPressure(_ isOn: Bool) {} } static var viewModel = { ConnectViewModel(useCase: FakeUseCase(), connectedPeripheral: .init(name: "iOSArduinoBoard")) }() static var previews: some View { ConnectView(viewModel: viewModel, isPeripheralReady: true) } } struct CardView: View { var body: some View { RoundedRectangle(cornerRadius: 16, style: .continuous) .shadow(color: Color(white: 0.5, opacity: 0.2), radius: 6) .foregroundColor(.init(uiColor: .secondarySystemBackground)) } } With the associated View Model: @Published var state = State.idle var useCase: PeripheralUseCaseProtocol let connectedPeripheral: Peripheral init(useCase: PeripheralUseCaseProtocol, connectedPeripheral: Peripheral) { self.useCase = useCase self.useCase.peripheral = connectedPeripheral self.connectedPeripheral = connectedPeripheral self.setCallbacks() } private func setCallbacks() { useCase.onPeripheralReady = { [weak self] in self?.state = .ready } useCase.onReadPressure = { [weak self] value in self?.state = .Pressure(value) } useCase.onWriteLedState = { [weak self] value in self?.state = .ledState(value) } useCase.onError = { error in print("Error \(error)") } } func startNotifyPressure() { useCase.notifyPressure(true) } func stopNotifyPressure() { useCase.notifyPressure(false) } func readPressure() { useCase.readPressure() } func flats() { useCase.writeLedState(isOn: "1") } func flatPoint() { useCase.writeLedState(isOn: "2") } func points() { useCase.writeLedState(isOn: "3") } } extension ConnectViewModel { enum State { case idle case ready case Pressure(Int) case ledState(Bool) } } What I am now trying to do is plot the data that is received from the Arduino in a line graph as it is received. Preferably the graph will scroll with time as well.
Posted
by tbuys.
Last updated
.
Post marked as solved
2 Replies
358 Views
Does anyone knows if it is possible to make a half donut chart using the new one SectorMark? I am exploring the initializers but so far no luck, this is my code like anyone else making a normal donut: struct Score: Identifiable { let id = UUID() let type: String let value: Int } @State private var scores: [Score] = [ .init(type: "Hits", value: 1), .init(type: "Misses", value: 9) ] Chart(scores) { score in SectorMark( angle: .value("Values", score.value), innerRadius: .ratio(0.9), outerRadius: .ratio(0.7) ) .foregroundStyle( by: .value("Type", score.type) ) }
Posted
by vitoe.
Last updated
.
Post marked as solved
6 Replies
333 Views
Hi there, I have a TabView in page style. Inside that TabView I have a number of views, each view is populated with a model object from an array. The array is iterated to provide the chart data. Here is the code: TabView(selection: $displayedChartIndex) { ForEach((0..<data.count), id: \.self) { index in ZStack { AccuracyLineView(graphData: tabSelectorModel.lineChartModels[index]) .padding(5) } .tag((index)) } } .tabViewStyle(.page) .indexViewStyle(.page(backgroundDisplayMode: .always)) I am seeing odd behaviour, as I swipe left and right, occasionally the chart area shows the chart from another page in the TabView. I know the correct view is being shown as there are text elements. See the screenshot below. The screen on the right is running iOS 17.2 and this works correctly. The screen on the left is running iOS 17.4 and the date at the top is correct which tells me that the data object is correct. However the graph is showing a chart from a different page. When I click on the chart on the left (I have interaction enabled) then it immediately draws the correct chart. If I disable the interaction then I still get the behaviour albeit the chart never corrects itself because there is no interaction! I can reproduce this in the 17.4 simulator and it is happening in my live app on iOS17.4. This has only started happening since iOS 17.4 dropped and works perfectly in iOS 17.2 simulator and I didn't notice it in the live app when I was running 17.3. Is this a bug and/or is there a workaround? For info this is the chart view code, it is not doing anything clever: struct AccuracyLineView: View { @State private var selectedIndex: Int? let graphData: LineChartModel func calcHourMarkers (maxTime: Int) -> [Int] { let secondsInDay = 86400 // 60 * 60 * 24 var marks: [Int] = [] var counter = 0 while counter <= maxTime { if (counter > 0) { marks.append(counter) } counter += secondsInDay } return marks } var selectedGraphMark: GraphMark? { var returnMark: GraphMark? = nil var prevPoint = graphData.points.first for point in graphData.points { if let prevPoint { if let selectedIndex, let lastPoint = graphData.points.last, ((point.interval + prevPoint.interval) / 2 > selectedIndex || point == lastPoint) { if point == graphData.points.last { if selectedIndex > (point.interval + prevPoint.interval) / 2 { returnMark = point } else { returnMark = prevPoint } } else { returnMark = prevPoint break } } } prevPoint = point } return returnMark } var body: some View { let lineColour:Color = Color(AppTheme.globalAccentColour) VStack { HStack { Image(systemName: "clock") Text(graphData.getStartDate() + " - " + graphData.getEndDate()) // 19-29 Sept .font(.caption) .fontWeight(.light) Spacer() } Spacer() Chart { // Lines ForEach(graphData.points) { item in LineMark( x: .value("Interval", item.interval), y: .value("Offset", item.timeOffset), series: .value("A", "A") ) .interpolationMethod(.catmullRom) .foregroundStyle(lineColour) .symbol { Circle() .stroke(Color(Color(UIColor.secondarySystemGroupedBackground)), lineWidth: 4) .fill(AppTheme.globalAccentColour) .frame(width: 10) } } ForEach(graphData.trend) { item in LineMark ( x: .value("Interval", item.interval), y: .value("Offset", item.timeOffset) ) .foregroundStyle(Color(UIColor.systemGray2)) } if let selectedGraphMark { RuleMark(x: .value("Offset", selectedGraphMark.interval)) .foregroundStyle(Color(UIColor.systemGray4)) } } .chartXSelection(value: $selectedIndex) .chartXScale(domain: [0, graphData.getMaxTime()]) } } }
Posted Last updated
.
Post not yet marked as solved
0 Replies
247 Views
I've been working on migrating some graphics to Swift Charts for an app I work on. However I've been noticing strange behavior when it comes to VoiceOver. If I create a bar chart and use: BarMark(x: .value("Month", x, unit: .month), y: ...) While the chart looks fine, the voice over values seem to follow arbitrary values set for the bin. From what I can tell they are following the underlying bin values that Swift Charts uses to provide spacing between bars. For instance, this simple example: let monthlyRevenueData = [ (x: try! Date("2024-01-01T00:00:00Z", strategy: .iso8601), y: (income: 55000, revenue: 124000), id: UUID()), (x: try! Date("2024-02-01T00:00:00Z", strategy: .iso8601), y: (income: 58000, revenue: 130000), id: UUID()), (x: try! Date("2024-03-01T00:00:00Z", strategy: .iso8601), y: (income: 59000, revenue: 120000), id: UUID()), ] struct ContentView: View { var body: some View { Chart(monthlyRevenueData, id: \.id) { (x, y, _) in BarMark(x: .value("Month", x, unit: .month), y: .value("Income", y.income)) .foregroundStyle(.green) BarMark(x: .value("Month", x, unit: .month), y: .value("Revenue", y.revenue)) } } } #Preview { ContentView() } Results in the Voice Over reading "January 14th 2024 at 12 AM to January 28th 2024 at 12am ..." despite the fact that the data should be for the entire month of Jan. Is there any way to get VoiceOver to read the input data rather than relying on how the chart is formatted? Preferably without the need to remove all visual spacing between the bars. Video link: https://drive.google.com/file/d/11mxCl3wR2HzoOaihOvci-vZk4zgG1d39/view?usp=drive_link
Posted Last updated
.
Post marked as solved
2 Replies
234 Views
Dear all, I have a line chart and on the Y axis it shows values from 0 (bottom) to 20 (top). Now, I'd like to show value from 20 (bottom) to 1 (top). Here below the code I used: Chart{ ForEach(andamento, id: \.posizione) { item in LineMark( x: .value("Giornata", item.giornata), y: .value("Posizione", item.posizione) ) PointMark( x: .value("Giornata", item.giornata), y: .value("Posizione", item.posizione) ) // We need .opacity(0) or it will // overlay your `.symbol` .opacity(0) .annotation(position: .overlay, alignment: .bottom, spacing: 10) { Text("\(item.posizione)") .font(.subheadline) } } .symbol(Circle()) } Can anybody help me? Thanks, A.
Posted
by AndreB82.
Last updated
.
Post marked as solved
2 Replies
382 Views
Dear all, I am using SwiftUI 15.2 and I have created a donut chart using SectorMark. Now, I have three values to show in the chart. When I set up the foregroundstyle, it returns orange, blu and green colors, whereas I'd like to have different colors (e.g. red, yellow and green). Chart(data, id: \.risultato) { dataItem in SectorMark(angle: .value("Type", dataItem.partite), innerRadius: .ratio(0.7), angularInset: 1.5) .foregroundStyle(by: .value("Type", dataItem.risultato)) .annotation(position: .overlay){ Text("\(dataItem.partite)") .font(.caption) } } .frame(height: 150) I'm reporting the final result here below. Do you know how I can customize them? Thanks in advance for your support, Andrea
Posted
by AndreB82.
Last updated
.
Post not yet marked as solved
1 Replies
288 Views
I have created a simple app where a user is tracking their mood. A simple click of the button inserts the necessary data to a CloudKit database. So I consider each record as a 'transactional' record. I am able to successfully query the data and present in a list view. I am able to sort and incorporate simple predicates. I am now at a point in my development that I would like to add a pie chart based on the users data and I am not sure how to roll-up the data / group by the data / aggregate the data [I am not sure what the correct terminology is within Swift] The pie chart would show the various moods that the exists in the CloudKit database and the slices would be sized based on the count of each mood. Any guidance that you can provide would be greatly helpful!
Posted
by mbain108.
Last updated
.
Post marked as solved
5 Replies
455 Views
I am currently working on a project for the Swift Student Challenge. One part of the app is for visualizing goals with a chart created using Swift Charts. In the app, you log your progress for the goal and then it should show up in the chart. My issue is that the data is not showing after it has been logged. Here are some code snippets: Code For Chart View Chart { let currentDate = Date.now BarMark ( x: .value("Day", "Today"), y: .value("Score", goalItem.getLogItemByDate(date: currentDate).score) ) } .frame(maxHeight: 225) .padding() GoalItem Data Object public class GoalItem: Identifiable { public var id: String var name: String var description: String var logItems: [String: GoalLogItem] init(name: String, description: String) { self.id = UUID().uuidString self.name = name self.description = description self.logItems = [:] } func log(date: Date, score: Double, notes: String) { self.logItems[dateToDateString(date: date)] = GoalLogItem(date: date, score: score, notes: notes) } func getLogItemByDate(date: Date) -> GoalLogItem { let logItem = self.logItems[dateToDateString(date: date)] if logItem != nil { return logItem! } else { return GoalLogItem(isPlaceholder: true) } } } After logging something using the GoalItem.log method, why does it not show up in the chart? Are the variables not updated? If so, how would I get the variables to update? Thanks
Posted
by jcovin293.
Last updated
.
Post not yet marked as solved
1 Replies
329 Views
Hello everyone, I am new to Swift, it is my first project and I am a PhD Electrical Engineer student. I am designing an iOS app for a device that we are designing that is capable of reading electrical brain data and sending them via BLE with a sampling frequency of 2400 Hz. I created a Bluetooth service for the Swift app that every time it receives new data, processes it to split the different channels and add the new data to the Charts data arrays. Here is the code I've designed: func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { if characteristic.uuid == Nordic_UART_TX_CHAR_UUID { guard error == nil, let data = characteristic.value else { print("[Bluetooth] Error receiving data or no data: \(error?.localizedDescription ?? "Unknown Error")") return } DispatchQueue.global(qos: .background).async { self.processReceivedData(data) } } } func processReceivedData(_ data: Data) { var batch = [(Int, Int)]() for i in stride(from: 0, to: data.count - 4, by: 4) { let channel = Int(data[i] & 0xFF) let value = Int((Int(data[i + 3] & 0xFF) << 16) | (Int(data[i + 2] & 0xFF) << 8) | (Int(data[i + 1] & 0xFF))) - 8388608 batch.append((channel, value)) } DispatchQueue.main.async { for (channel, value) in batch { let nowTime = (Date().timeIntervalSince1970 - self.dataGraphService.startTime) let newDataPoint = DataGraphService.VoltagePerTime(time: nowTime, voltage: Double(value)/8388608, channel: "Channel \(channel - 15)") if channel == 16 { self.dataGraphService.lastX1 = nowTime self.dataGraphService.dataCh1.append(newDataPoint) } else if channel == 17 { self.dataGraphService.lastX2 = nowTime self.dataGraphService.dataCh2.append(newDataPoint) } else if channel == 18 { self.dataGraphService.lastX3 = nowTime self.dataGraphService.dataCh3.append(newDataPoint) } else if channel == 19 { self.dataGraphService.lastX4 = nowTime self.dataGraphService.dataCh4.append(newDataPoint) } } } } // DataGraphService.swift struct VoltagePerTime { var time: Double var voltage: Double var channel: String } @Published var dataCh1: [VoltagePerTime] = [] @Published var dataCh2: [VoltagePerTime] = [] @Published var dataCh3: [VoltagePerTime] = [] @Published var dataCh4: [VoltagePerTime] = [] @Published var windowSize: Double = 2.0 @Published var lastX1: Double = 0 @Published var lastX2: Double = 0 @Published var lastX3: Double = 0 @Published var lastX4: Double = 0 I also created a View that shows the real-time data from the different channels. ChartView( data: dataGraphService.dataCh1.filter { dataGraphService.getXAxisRange(for: dataGraphService.dataCh1, windowSize: dataGraphService.windowSize).contains($0.time) }, xAxisRange: dataGraphService.getXAxisRange(for: dataGraphService.dataCh1, windowSize: dataGraphService.windowSize), channel: "Channel 1", windowSize: dataGraphService.windowSize ) // ChartView.swift import SwiftUI import Charts struct ChartView: View { var data: [DataGraphService.VoltagePerTime] var xAxisRange: ClosedRange<Double> var channel: String var windowSize: Double var body: some View { RoundedRectangle(cornerRadius: 10) .fill(Color.gray.opacity(0.1)) .overlay( VStack{ Text("\(channel)") .foregroundColor(Color.gray) .font(.system(size: 16, weight: .semibold)) Chart(data, id: \.time) { item in LineMark( x: .value("Time [s]", item.time), y: .value("Voltage [V]", item.voltage) ) } .chartYAxisLabel(position: .leading) { Text("Voltage [V]") } .chartYScale(domain: [-1.6, 1.6]) .chartYAxis { AxisMarks(position: .leading, values: [-1.6, -0.8, 0, 0.8, 1.6]) AxisMarks(values: [-1.6, -1.2, -0.8, -0.4, 0, 0.4, 0.8, 1.2, 1.6]) { AxisGridLine() } } .chartXAxisLabel(position: .bottom, alignment: .center) { Text("Time [s]") } .chartXScale(domain: xAxisRange) .chartXAxis { AxisMarks(values: .automatic(desiredCount: Int(windowSize)*2)) AxisMarks(values: .automatic(desiredCount: 4*Int(windowSize)-2)) { AxisGridLine() } } .padding(5) } ) .padding(2.5) .padding([.leading, .trailing], 5) } } With these code I can receive and plot the data in real-time but after some time the CPU of the iPhone gets saturated and the app stop working. I have the guess that the code is designed in a way that the functions are called one inside the other one in a very fast speed that the CPU cannot handle. My doubt is if there is any other way to code this real-time plotting actions without make the iPhone's CPU power hungry. Thank you very much for your help!
Posted
by mbenomar.
Last updated
.
Post not yet marked as solved
0 Replies
237 Views
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?
Posted
by KalNyn.
Last updated
.
Post not yet marked as solved
0 Replies
258 Views
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()
Posted
by Kalmaro.
Last updated
.
Post not yet marked as solved
0 Replies
264 Views
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
Posted
by Guadoo.
Last updated
.
Post not yet marked as solved
0 Replies
460 Views
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
Posted
by yblk.
Last updated
.
Post not yet marked as solved
4 Replies
858 Views
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.
Posted Last updated
.
Post not yet marked as solved
1 Replies
549 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 Geneva0.
Last updated
.