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

30 Posts

Post

Replies

Boosts

Views

Activity

Swift charts displaying wrong theme through UIHostingController
Hi there, I'm currently using UIHostingController to display swift charts in uikit. The problem im facing is that the UIHostingController isn't outputting the intended theme. When the simulator/phone is on dark mode the view is still in light mode. Iv'e tried to force the view to use dark mode with: .environment(\.colorScheme, .dark) But it doesn't seem to help. Here's how I implement the UIHostingController to my view: let controller = UIHostingController(rootView: StatVC()) controller.view.translatesAutoresizingMaksIntoConstraints = false addChild(controller) controller.didMove(toParent: self) view.addSubview(controller.view) where StatVC() is the swiftui view which contains the swift chart.
1
0
1.2k
Feb ’25
Affiliate View Struct is probably hidden by Charts on iOS app
The problem is: As per screenshot below, one can only see the lineChart. I have another struct AffiliateView coded under this Chart: import SnapKit import Charts import DGCharts class AffiliateViewController: UIViewController { private lazy var chartView: LineChartView = { let chart = LineChartView() chart.noDataText = "No data available." chart.chartDescription.enabled = false chart.xAxis.labelPosition = .bottom chart.rightAxis.enabled = false chart.legend.enabled = true chart.backgroundColor = .lightGray // For debugging visibility return chart }() private lazy var containerView: UIView = { let view = UIView() view.backgroundColor = .white return view }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // Add container view and chart view to the main view view.addSubview(containerView) view.addSubview(chartView) // Add SwiftUI View inside the container view let affiliateView = AffiliateView() let hostingController = UIHostingController(rootView: affiliateView) addChild(hostingController) containerView.addSubview(hostingController.view) hostingController.view.frame = containerView.bounds hostingController.didMove(toParent: self) layout() setupChartData() } private func layout() { // Layout the container view (SwiftUI content) containerView.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide.snp.top) make.left.right.equalToSuperview() make.height.equalTo(350) // Increase the height for the SwiftUI content } // Layout the chart view below the container view chartView.snp.makeConstraints { make in make.top.equalTo(containerView.snp.bottom).offset(20) // Space between chart and the affiliate content make.left.equalToSuperview().offset(20) make.right.equalToSuperview().offset(-20) make.height.equalTo(200) // Set a fixed height for the chart } } private func setupChartData() { let dataEntries = [ ChartDataEntry(x: 1, y: 10), ChartDataEntry(x: 2, y: 20), ChartDataEntry(x: 3, y: 15), ChartDataEntry(x: 4, y: 30), ChartDataEntry(x: 5, y: 25) ] let dataSet = LineChartDataSet(entries: dataEntries, label: "Clicks per Day") dataSet.colors = [.blue] dataSet.valueColors = [.black] dataSet.circleColors = [.red] dataSet.circleRadius = 4.0 let data = LineChartData(dataSet: dataSet) chartView.data = data chartView.notifyDataSetChanged() } } // SwiftUI View remains in the same file struct AffiliateView: View { @State private var customMessage: String = "" @State private var uniqueLink: String = "Your unique link will appear here." @State private var clickData: [Double] = [10, 20, 15, 30, 25] // Example data var body: some View { NavigationView { VStack(spacing: 20) { // TextField for custom message input TextField("Enter your custom message...", text: $customMessage) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding(.horizontal) // Generate Link Button Button(action: generateLink) { Text("Generate Sign-Up Link") .font(.headline) .foregroundColor(.white) .frame(maxWidth: .infinity, maxHeight: 50) .background(Color.red) .cornerRadius(10) } .padding(.horizontal) // Generated Link Label Text(uniqueLink) .font(.body) .multilineTextAlignment(.center) .padding(.horizontal) // You can add a chart here if you want to show it in SwiftUI too /* LineChartView(data: clickData, title: "Clicks per Day", legend: "Daily Clicks") */ } .navigationTitle("Affiliate Marketing") .navigationBarTitleDisplayMode(.inline) } } private func generateLink() { let encodedMessage = customMessage.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" uniqueLink = "https://affiliate.example.com/referral?message=\(encodedMessage)" addClickData() } private func addClickData() { clickData.append(Double.random(in: 0...100)) } } As you see, the AffiliateView has been declared outside of Controller View class. The View content was visible before the lineChart was added into this code. Now the View content is not visible anymore. I have tried to increment/decrement values at make.height.equalTo() but to no avail. Could anyone kindly point me in the right direction?
0
0
294
Jan ’25
How to Visualize Data in a DataFrame Using Charts
I want to visualize the data stored in a DataFrame using various charts (barmark, sectormark, linemark, etc.). My questions are as follows: Can a DataFrame be used directly within a chart? If so, could you provide a simple example? If it cannot be used directly, what is the correct way to use it? Could you provide an example? Thank you for your help. Best regards.
0
1
360
Jan ’25
TabView and Swift Charts giving inconsistent behaviour when swiping between pages
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()]) } } }
10
0
1.7k
Jan ’25
SwiftUI charts, how do I align these X axis labels correctly?
Hi there, so I have this chart that's taking in a Date for it's x values and a time interval for their y values. For some reason, the labels aren't centering on each bar, the only fix I see is to add an offset to each label but that seems hacky. My code: Chart { ForEach(weekBreakdownArr, id: \.startDate) { bd in BarMark( x: .value("Date", bd.startDate), y: .value("Duration", bd.durationWorkDone), width: .fixed(15) ) .foregroundStyle(Color.redYarn) .cornerRadius(2) } //... } // shownXValues are just the start dates in an array .chartXAxis { AxisMarks(position: .automatic, values: shownXValues) { val in AxisValueLabel { Text("Th") .useAppFont(size: 12, relativeTo: .body, weight: .regular) } } }
1
0
618
Dec ’24
Swift Charts legend overflowing outside frame
I'm building an app that lets users create charts with custom values and while testing, I came up with this bug that happens when the view width forces the legend to have more than 1 line. Due to Swift trying to align the different labels vertically, it's forcing the first line to overflow. Here's the code to generate this: import SwiftUI import Charts struct DonutView: View { var countries:[(country:String, count:Int)] = [ (country: "Africa", count: 54), (country: "Asia", count: 48), (country: "Europe", count: 44), (country: "North America", count: 23), (country: "Oceania", count: 14), (country: "South America", count: 12), ] var body: some View { Chart { ForEach(0..<countries.count, id:\.self) { idx in SectorMark( angle: .value(countries[idx].country, countries[idx].count), innerRadius: .ratio(0.5) ) .foregroundStyle(by: .value("label", countries[idx].country)) } } .frame(width: 310, height: 270) .border(.blue, width: 1) } } Has anyone seen this? Is there a solution? I know about building custom legends, but SwiftUI has no wrapping HStack nor VStack, and the app allows users to change the legend position from the bottom to the top or sides. If I were to go this way, I'd have to write a very large chunk of code to bypass what seems to be a bug.
1
0
526
Dec ’24
Swift Charts: chartScrollTargetBehavior fails to snap to a day unit
I am working on a scrollable chart that displays days on the horizontal axis. As the user scrolls, I always want them to be able to snap to a specific day. I implemented the following steps described in this WWDC23 session to achieve this. I have set the chartScrollTargetBehavior to .valueAligned(matching: DateComponents(hour: 0)) I have set the x value unit on the BarMark to Calendar.Component.day I ended up with the chart code that looks like this: Chart(dates, id: \.self) { date in BarMark( x: .value("Date", date, unit: Calendar.Component.day), y: .value("Number", 1) ) .annotation { Text(date.formatted(.dateTime.day())) .font(.caption2) } } .chartXAxis { AxisMarks(format: .dateTime.day()) } .chartScrollableAxes(.horizontal) .chartScrollTargetBehavior(.valueAligned(matching: DateComponents(hour: 0))) .chartXVisibleDomain(length: fifteenDays) .chartScrollPosition(x: $selection) However, this fails to work reliably. There is often a situation where the chart scroll position lands on, for instance, Oct 20, 11:56 PM, but the chart snaps to Oct 21. I attempted to solve this problem by introducing an intermediate binding between a state value and a chart selection. This binding aims to normalize the selection always to be the first moment of any given date. But this hasn't been successful. private var selectionBinding: Binding<Date> { Binding { Calendar.current.startOfDay(for: selection) } set: { newValue in self.selection = Calendar.current.startOfDay(for: newValue) } } It's also worth mentioning that this issue also exists in Apple's sample project on Swift Charts. How would you approach solving this? How can I find a way to make the chart scroll position blind to time values and only recognize whole days? Here's the minimal reproducible example project for your reference.
1
1
571
Nov ’24
Swift UI Chart Accessibility issue
Hi Team, We are integrating SwiftUI's Charts BarMark, UI looks good but when we try setting up custom ADA it doesn't reflect/override the accessibility label/value we set manually. Is it iOS defect or is there any workaround? Thanks in advance. Sample: Chart(data) { BarMark( x: .value("Category", $0.department), y: .value("Profit", $0.profit) ) .foregroundStyle(by: .value("Product Category", $0.productCategory)) .accessibilityIdentifier("BarMark") .accessibilityLabel("Dep: \($0.department)") .accessibilityValue("Profile: \($0.profit) Category: \($0.productCategory)") }
1
2
620
Nov ’24
Tranforming a chart's origin
Hi, I'm trying to create a visualization using charts for vision pro. I want to create a line chart that connects pair of points on a donut chart. So i'm trying to draw the lines radially but it seems that the line chart always has only the bottom left corner of the view as origin. How can I tranform the origin to center of the view?
Topic: Design SubTopic: General Tags:
1
0
661
Oct ’24