Hello Swift Charts

RSS for tag

Discuss the WWDC22 Session Hello Swift Charts

Posts under wwdc2022-10136 tag

12 Posts

Post

Replies

Boosts

Views

Activity

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
How can I include a function (or calculation) in the values that Charts receives to draw the chart, and overcome this bug?
Charts fails when a function or ternary condition is added to the values to be plotted. Charts. When a function is received as a value in the ForEach loop, the application crashes (Thread 1: signal SIGABRT), or if it is a ternary operator (condition ? true: false) it does not show the graph. The function should convert the value/attribute of the Core Data entity only if necessary, the data is stored in a common unit and depending on the display condition in an AppStorage variable it should be seen converted to another unit or displayed. This error occurs with any type of chart. It fails with both RulerMark and other charts like LineMark. The function works fine with Text and other similar views. The Chart @AppStorage("unitView") var unitView: String = "Celsius" ... // CHART Chart { if statsByUser.takens > 1 { RuleMark(y: .value("AVG", getViewDegrees(statsByUser.avg, unitView))) .lineStyle(StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round, dash: [4, 6])) .foregroundStyle(.white.opacity(0.8)) } ForEach(0..<temperatureByUserId.count, id:\.self) { item in LineMark(x: .value("Date", item + 1), y: .value("Temperature", getViewDegrees(temperatureByUserId[item].degress, unitView))) .lineStyle(.init(lineWidth: 2, lineCap: .round, lineJoin: .round)) .foregroundStyle(.white) //.mint [.pink, .purple, .mint] } .interpolationMethod(.cardinal) } // X-Axis .chartXScale(domain: 1 ... statsByUser.takens) .chartXAxis(.hidden) // Y-Axis .chartYScale(domain: statsByUser.min ... statsByUser.max) .chartYAxis { AxisMarks{ _ in AxisGridLine().foregroundStyle(.white) AxisValueLabel(centered: true).foregroundStyle(.white) } } } The Functions let unitDegress: [String] = ["Celsius", "Fahrenheit"] func getViewDegrees(_ value: Double, _ unit: String) -> Double { var returnValue = value if unit == unitDegress[1] { // is Fahrenheit let t = Measurement(value: value, unit: UnitTemperature.celsius) returnValue = t.converted(to: .fahrenheit).value } return returnValue } Text works properly. Text("\(getViewDegrees(temperatureByUser.last, unitView), specifier: decimalSpecifier)")
2
0
1.1k
Oct ’22
foregroundStyle(by: does not maintain consistent colour with limited series
When using foregroundStyle(by: and symbol(by: with a series of data using Multi-series Line Mark and limited with a pickerView, the colour/symbol changes depending on the number of series selected and is not consistent. enum Hand {     case left, right, both } struct HandSample: Identifiable {     var hand: String    // Series     var count: Double     var date: Date     var id = UUID() }     var data: [HandSample] {         switch hand {         case .both:             return loadData(samples: samples, days: days, left: true, right: true)         case .left:             return loadData(samples: samples, days: days, left: true, right: false)         case .right:             return loadData(samples: samples, days: days, left: false, right: true)         }     }     func loadData(samples: FetchedResults<Sample>, days: Int, left: Bool, right: Bool) -> [HandSample] {         var series: Array<HandSample> = Array()         let sinceDate = Calendar.current.date(byAdding: .day, value: -days, to: Date())         for sample in samples {             if sample.sampleDate > sinceDate! {                 if left {                     let leftSamples = HandSample(hand: "Left", count: sample.left.doubleValue, date: sample.sampleDate)                     series.append(leftSamples)                 }                 if right {                     let rightSamples = HandSample(hand: "Right", count: sample.right.doubleValue, date: sample.sampleDate)                     series.append(rightSamples)                 }             }         }         return series     }     var body: some View {         VStack {             Picker ("Hand", selection: $hand.animation(.easeOut)) {                 Text("Both Hands")                     .tag(Hand.both)                 Text("Left Hand")                     .tag(Hand.left)                 Text("Right Hand")                     .tag(Hand.right)             }             .pickerStyle(.segmented)             Chart (data) {                 LineMark(                     x: .value("Date", $0.date),                     y: .value("Count", $0.count),                     series: .value("Hand", $0.hand)                 )                 .foregroundStyle(by: $0.hand)                 PointMark(                     x: .value("Date", $0.date),                     y: .value("Count", $0.count)                 )                 .foregroundStyle(by: $0.hand)                 .symbol(by: .value("Hand", $0.hand))             }         }     } In the attached sample, shows Right as a Green Cross when Both Hands series are shown, but shows Right as a Blue Circle when only the Right Hand series is shown. iOS 16 Beta 4 (20A5328h) Xcode 14.0 beta 4 (14A5284g)
6
0
1.8k
Sep ’22
"font" and "foregroundstyle" modifier on AxisValueLabel don't work!
Hi, I use a barmark/linemark SwiftUI chart in my app and when i want to change the fontsize and color of the AxisValueLabel for the x-axis then it does not seem to work properly. When i set the following: AxisValueLabel() .foregroundStyle(.red) or AxisValueLabel() .font(.system(size: 30)) it doesn't show up. Kind regards, Tom
1
0
1.8k
Jul ’22
SwiftCharts: how to manage colors and groupings
I want to draw a chart where I have two line marks (one for each child each) and behind it area marks for percentiles. If I don't add any foregroundStyle then the line marks get connected. struct GrowthChart: View { @ChartContentBuilder func oneSlice(row: PercentileRow, slice: Slice) -> some ChartContent { AreaMark( x: .value("Day", row.month), yStart: .value("Max", row.dictionary[slice.startKey]!), yEnd: .value("Min", row.dictionary[slice.endKey]!) ) .foregroundStyle(by: .value("Percentile", slice.number)) } let percentileColors: [Color] = [ .blue.opacity(0.1),   .blue.opacity(0.2),   .blue.opacity(0.3),   .blue.opacity(0.4),   .blue.opacity(0.5),   .blue.opacity(0.4),   .blue.opacity(0.3),   .blue.opacity(0.2),   .blue.opacity(0.1)   ] var body: some View { VStack { Chart { ForEach(percentiles.rows) { row in ForEach(slices) { slice in oneSlice(row: row, slice: slice) } } ForEach(children) { child in ForEach(child.data) { dataPoint in LineMark( x: .value("Month", dataPoint.month), y: .value("Height", dataPoint.height) ) .foregroundStyle(by: .value("Name", child.name)) } } } .chartForegroundStyleScale( range: Gradient (colors: percentileColors) ) .aspectRatio(contentMode: .fit) .padding() Spacer() }.padding() } } I don't understand how to group the individual marks. Apparently you have to add a foregroundStyle to each with a .by specifying a category. I found this chartForegroundStyleScale in an example on the internet, but I can only get it to show this gradient. But how do I specify different colors for the LineMarks?
1
0
2.3k
Jun ’22
Orientation (vertical, angle) in Swift Charts is not working
Hi! I want to use the new SwiftUI Charts (iOS 16) in my app and it seems that the orientation does not work. I want to make the AxisLabels vertical oder verticalReversed or give it a certain angle but all three methods don't seem to work. AxisMarks() { _ in AxisValueLabel(orientation: .angle(Angle.degrees(45.0))) } } Am i doing something wrong or is it a bug in the beta framework? Kind regards, Tom
0
0
942
Jun ’22
LineMark Does Not Respect .foregroundStyle Color choice
Working through the new Swift Chart framework and I am noticing LineMark does not seem to want to respect .foregroundStyle(.pink) (or any respective color) for more than one line. Apple's own Chart page lists an example that, when copied into Xcode 14 (beta 1) it does not render in preview as it does in their screenshot Data used: struct ProfitOverTime { var week: Int var profit: Double } let departmentAProfile: [ProfitOverTime] = [ .init(week: 1, profit: 21.5), .init(week: 2, profit: 19.2), .init(week: 3, profit: 18.4), .init(week: 4, profit: 21.0), .init(week: 5, profit: 19.7), .init(week: 6, profit: 14.7), .init(week: 7, profit: 22.1), .init(week: 8, profit: 18.0) ] let departmentBProfile: [ProfitOverTime] = [ .init(week: 1, profit: 5.7), .init(week: 2, profit: 12.0), .init(week: 3, profit: 11.9), .init(week: 4, profit: 18.0), .init(week: 5, profit: 15.9), .init(week: 6, profit: 16.7), .init(week: 7, profit: 12.1), .init(week: 8, profit: 19.0) ] Content View: struct ContentView: View {     var body: some View { Chart { ForEach(departmentAProfile, id: \.week) { LineMark( x: .value("Week", $0.week), y: .value("Profit A", $0.profit) ).foregroundStyle(.green) } ForEach(departmentBProfile, id: \.week) { LineMark( x: .value("Week", $0.week), y: .value("Profit B", $0.profit) ) .foregroundStyle(.green) } RuleMark( y: .value("Threshold", 20.0) ) .foregroundStyle(.teal) }     } } Produces
2
0
2.2k
Jun ’22
Auto zooming on data variation chart type & Axis breaks symbols
A lot of time when you plot a chart (say a bar chart here) for business you wants to emphasize the small variation between data, say daily you have roughly 5 millions messages sent but you need to visualize the 3k variations common each days. To utilize the landscape it's best for one to visualize not from zero but zooming in between 4.9m ~ 5.2m range instead of showing a slightly wiggling line. While we could likely (I haven't get to it) to customize our chart to do that it'd be a good and handy option for the standard charts and Swift Chart would auto-adjust the range. On top of it, being able to add standard axis break symbols would be a great help to keep it visualized and keep the chart honest.
0
0
893
Jun ’22
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
How can I include a function (or calculation) in the values that Charts receives to draw the chart, and overcome this bug?
Charts fails when a function or ternary condition is added to the values to be plotted. Charts. When a function is received as a value in the ForEach loop, the application crashes (Thread 1: signal SIGABRT), or if it is a ternary operator (condition ? true: false) it does not show the graph. The function should convert the value/attribute of the Core Data entity only if necessary, the data is stored in a common unit and depending on the display condition in an AppStorage variable it should be seen converted to another unit or displayed. This error occurs with any type of chart. It fails with both RulerMark and other charts like LineMark. The function works fine with Text and other similar views. The Chart @AppStorage("unitView") var unitView: String = "Celsius" ... // CHART Chart { if statsByUser.takens > 1 { RuleMark(y: .value("AVG", getViewDegrees(statsByUser.avg, unitView))) .lineStyle(StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round, dash: [4, 6])) .foregroundStyle(.white.opacity(0.8)) } ForEach(0..<temperatureByUserId.count, id:\.self) { item in LineMark(x: .value("Date", item + 1), y: .value("Temperature", getViewDegrees(temperatureByUserId[item].degress, unitView))) .lineStyle(.init(lineWidth: 2, lineCap: .round, lineJoin: .round)) .foregroundStyle(.white) //.mint [.pink, .purple, .mint] } .interpolationMethod(.cardinal) } // X-Axis .chartXScale(domain: 1 ... statsByUser.takens) .chartXAxis(.hidden) // Y-Axis .chartYScale(domain: statsByUser.min ... statsByUser.max) .chartYAxis { AxisMarks{ _ in AxisGridLine().foregroundStyle(.white) AxisValueLabel(centered: true).foregroundStyle(.white) } } } The Functions let unitDegress: [String] = ["Celsius", "Fahrenheit"] func getViewDegrees(_ value: Double, _ unit: String) -> Double { var returnValue = value if unit == unitDegress[1] { // is Fahrenheit let t = Measurement(value: value, unit: UnitTemperature.celsius) returnValue = t.converted(to: .fahrenheit).value } return returnValue } Text works properly. Text("\(getViewDegrees(temperatureByUser.last, unitView), specifier: decimalSpecifier)")
Replies
2
Boosts
0
Views
1.1k
Activity
Oct ’22
Is it possible to have secondary y axis with different scale?
Environment : macOS Ventura Xcode beta 14.1: I have the following chart I was using to learn about SwifUI Charts: I wanted to have different scales on the leading and trailing yaxis as well as have the first 3 bars to use leading scale and the last two bars use the trailing scale. Can this be done? If so, how? Thanks
Replies
1
Boosts
0
Views
1.2k
Activity
Oct ’22
foregroundStyle(by: does not maintain consistent colour with limited series
When using foregroundStyle(by: and symbol(by: with a series of data using Multi-series Line Mark and limited with a pickerView, the colour/symbol changes depending on the number of series selected and is not consistent. enum Hand {     case left, right, both } struct HandSample: Identifiable {     var hand: String    // Series     var count: Double     var date: Date     var id = UUID() }     var data: [HandSample] {         switch hand {         case .both:             return loadData(samples: samples, days: days, left: true, right: true)         case .left:             return loadData(samples: samples, days: days, left: true, right: false)         case .right:             return loadData(samples: samples, days: days, left: false, right: true)         }     }     func loadData(samples: FetchedResults<Sample>, days: Int, left: Bool, right: Bool) -> [HandSample] {         var series: Array<HandSample> = Array()         let sinceDate = Calendar.current.date(byAdding: .day, value: -days, to: Date())         for sample in samples {             if sample.sampleDate > sinceDate! {                 if left {                     let leftSamples = HandSample(hand: "Left", count: sample.left.doubleValue, date: sample.sampleDate)                     series.append(leftSamples)                 }                 if right {                     let rightSamples = HandSample(hand: "Right", count: sample.right.doubleValue, date: sample.sampleDate)                     series.append(rightSamples)                 }             }         }         return series     }     var body: some View {         VStack {             Picker ("Hand", selection: $hand.animation(.easeOut)) {                 Text("Both Hands")                     .tag(Hand.both)                 Text("Left Hand")                     .tag(Hand.left)                 Text("Right Hand")                     .tag(Hand.right)             }             .pickerStyle(.segmented)             Chart (data) {                 LineMark(                     x: .value("Date", $0.date),                     y: .value("Count", $0.count),                     series: .value("Hand", $0.hand)                 )                 .foregroundStyle(by: $0.hand)                 PointMark(                     x: .value("Date", $0.date),                     y: .value("Count", $0.count)                 )                 .foregroundStyle(by: $0.hand)                 .symbol(by: .value("Hand", $0.hand))             }         }     } In the attached sample, shows Right as a Green Cross when Both Hands series are shown, but shows Right as a Blue Circle when only the Right Hand series is shown. iOS 16 Beta 4 (20A5328h) Xcode 14.0 beta 4 (14A5284g)
Replies
6
Boosts
0
Views
1.8k
Activity
Sep ’22
Little question
Is it possible to have a custom symbol just at the head of the line chart? EX: Live line chart where the head is a little circle
Replies
0
Boosts
0
Views
1k
Activity
Aug ’22
can i use Swift Charts with ios 15?
i can't find a solution to install this, so i thought that maybe i have to have xcode 14 and sdk set to 16, can someone give me a solution for using this library please?
Replies
1
Boosts
0
Views
1.1k
Activity
Aug ’22
"font" and "foregroundstyle" modifier on AxisValueLabel don't work!
Hi, I use a barmark/linemark SwiftUI chart in my app and when i want to change the fontsize and color of the AxisValueLabel for the x-axis then it does not seem to work properly. When i set the following: AxisValueLabel() .foregroundStyle(.red) or AxisValueLabel() .font(.system(size: 30)) it doesn't show up. Kind regards, Tom
Replies
1
Boosts
0
Views
1.8k
Activity
Jul ’22
SwiftCharts: How do I make PointMarks only a dot?
Is there a way to have a point mark only come out as a very small circle? I want PointMarks that are basically just 1 point large black dots.
Replies
1
Boosts
0
Views
1.6k
Activity
Jun ’22
SwiftCharts: how to manage colors and groupings
I want to draw a chart where I have two line marks (one for each child each) and behind it area marks for percentiles. If I don't add any foregroundStyle then the line marks get connected. struct GrowthChart: View { @ChartContentBuilder func oneSlice(row: PercentileRow, slice: Slice) -> some ChartContent { AreaMark( x: .value("Day", row.month), yStart: .value("Max", row.dictionary[slice.startKey]!), yEnd: .value("Min", row.dictionary[slice.endKey]!) ) .foregroundStyle(by: .value("Percentile", slice.number)) } let percentileColors: [Color] = [ .blue.opacity(0.1),   .blue.opacity(0.2),   .blue.opacity(0.3),   .blue.opacity(0.4),   .blue.opacity(0.5),   .blue.opacity(0.4),   .blue.opacity(0.3),   .blue.opacity(0.2),   .blue.opacity(0.1)   ] var body: some View { VStack { Chart { ForEach(percentiles.rows) { row in ForEach(slices) { slice in oneSlice(row: row, slice: slice) } } ForEach(children) { child in ForEach(child.data) { dataPoint in LineMark( x: .value("Month", dataPoint.month), y: .value("Height", dataPoint.height) ) .foregroundStyle(by: .value("Name", child.name)) } } } .chartForegroundStyleScale( range: Gradient (colors: percentileColors) ) .aspectRatio(contentMode: .fit) .padding() Spacer() }.padding() } } I don't understand how to group the individual marks. Apparently you have to add a foregroundStyle to each with a .by specifying a category. I found this chartForegroundStyleScale in an example on the internet, but I can only get it to show this gradient. But how do I specify different colors for the LineMarks?
Replies
1
Boosts
0
Views
2.3k
Activity
Jun ’22
Orientation (vertical, angle) in Swift Charts is not working
Hi! I want to use the new SwiftUI Charts (iOS 16) in my app and it seems that the orientation does not work. I want to make the AxisLabels vertical oder verticalReversed or give it a certain angle but all three methods don't seem to work. AxisMarks() { _ in AxisValueLabel(orientation: .angle(Angle.degrees(45.0))) } } Am i doing something wrong or is it a bug in the beta framework? Kind regards, Tom
Replies
0
Boosts
0
Views
942
Activity
Jun ’22
LineMark Does Not Respect .foregroundStyle Color choice
Working through the new Swift Chart framework and I am noticing LineMark does not seem to want to respect .foregroundStyle(.pink) (or any respective color) for more than one line. Apple's own Chart page lists an example that, when copied into Xcode 14 (beta 1) it does not render in preview as it does in their screenshot Data used: struct ProfitOverTime { var week: Int var profit: Double } let departmentAProfile: [ProfitOverTime] = [ .init(week: 1, profit: 21.5), .init(week: 2, profit: 19.2), .init(week: 3, profit: 18.4), .init(week: 4, profit: 21.0), .init(week: 5, profit: 19.7), .init(week: 6, profit: 14.7), .init(week: 7, profit: 22.1), .init(week: 8, profit: 18.0) ] let departmentBProfile: [ProfitOverTime] = [ .init(week: 1, profit: 5.7), .init(week: 2, profit: 12.0), .init(week: 3, profit: 11.9), .init(week: 4, profit: 18.0), .init(week: 5, profit: 15.9), .init(week: 6, profit: 16.7), .init(week: 7, profit: 12.1), .init(week: 8, profit: 19.0) ] Content View: struct ContentView: View {     var body: some View { Chart { ForEach(departmentAProfile, id: \.week) { LineMark( x: .value("Week", $0.week), y: .value("Profit A", $0.profit) ).foregroundStyle(.green) } ForEach(departmentBProfile, id: \.week) { LineMark( x: .value("Week", $0.week), y: .value("Profit B", $0.profit) ) .foregroundStyle(.green) } RuleMark( y: .value("Threshold", 20.0) ) .foregroundStyle(.teal) }     } } Produces
Replies
2
Boosts
0
Views
2.2k
Activity
Jun ’22
Auto zooming on data variation chart type & Axis breaks symbols
A lot of time when you plot a chart (say a bar chart here) for business you wants to emphasize the small variation between data, say daily you have roughly 5 millions messages sent but you need to visualize the 3k variations common each days. To utilize the landscape it's best for one to visualize not from zero but zooming in between 4.9m ~ 5.2m range instead of showing a slightly wiggling line. While we could likely (I haven't get to it) to customize our chart to do that it'd be a good and handy option for the standard charts and Swift Chart would auto-adjust the range. On top of it, being able to add standard axis break symbols would be a great help to keep it visualized and keep the chart honest.
Replies
0
Boosts
0
Views
893
Activity
Jun ’22