I'm using SwiftUI Charts to make a LineMark chart. Everything seems to work, except I'm getting this error in the console for every data point that the chart tries to plot.
"Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem."
I've setup a backtrace in the scheme but I can't make any sense of it.
Here's my code for the chart:
private var chart: some View {
Chart(viewModel.weatherArray, id: \.DATETIME) {
LineMark(
x: .value("Date", $0.DATETIME),
y: .value("Temp", $0.TMP)
)
.lineStyle(StrokeStyle(lineWidth: lineWidth))
.foregroundStyle(chartColor.gradient)
// .interpolationMethod(interpolationMethod.mode)
.symbol(Circle().strokeBorder(lineWidth: lineWidth))
.symbolSize(showSymbols ? 60 : 0)
}
//the chart overlay uses the tap gesture to to define the selected element on the chart
.chartOverlay { proxy in
GeometryReader { geo in
Rectangle().fill(.clear).contentShape(Rectangle())
.gesture(
SpatialTapGesture()
.onEnded { value in
let element = findElement(location: value.location, proxy: proxy, geometry: geo)
if selectedElement?.DATETIME == element?.DATETIME {
// If tapping the same element, clear the selection.
selectedElement = nil
} else {
selectedElement = element
}
}
.exclusively(
before: DragGesture()
.onChanged { value in
selectedElement = findElement(location: value.location, proxy: proxy, geometry: geo)
}
)
)
}
}
.chartBackground { proxy in
ZStack(alignment: .topLeading) {
GeometryReader { geo in
//if showlolipop is the toggle, i dont need that but its simpler to keep it.
if showLollipop,
let selectedElement {
let dateInterval = Calendar.current.dateInterval(of: .hour, for: selectedElement.DATETIME)!
let startPositionX1 = proxy.position(forX: dateInterval.start) ?? 0
let lineX = startPositionX1 + geo[proxy.plotAreaFrame].origin.x
let lineHeight = geo[proxy.plotAreaFrame].maxY
let boxWidth: CGFloat = 100
let boxOffset = max(0, min(geo.size.width - boxWidth, lineX - boxWidth / 2))
//this is the part that defines how the lolipop looks
//lolipop stem
Rectangle()
.fill(.red)
.frame(width: 2, height: lineHeight)
.position(x: lineX, y: lineHeight / 2)
//lolipop head
VStack(alignment: .center) {
Text("\(selectedElement.DATETIME, format: .dateTime.year(.twoDigits).month(.twoDigits).day().hour())")
.font(.callout)
.foregroundStyle(.secondary)
Text("\(selectedElement.TMP, format: .number) °C")
.font(.title2.bold())
.foregroundColor(.primary)
}
//This is the background of the lolipop head
.background {
ZStack {
RoundedRectangle(cornerRadius: 8)
.fill(.background)
RoundedRectangle(cornerRadius: 8)
.fill(.quaternary.opacity(0.7))
}
.padding(.horizontal, -8)
.padding(.vertical, -4)
}
.offset(x: boxOffset)
}
}
}
}
}
//This function is what makes the lolipop work. It finds the info for the labels
func findElement(location: CGPoint, proxy: ChartProxy, geometry: GeometryProxy) -> WeatherForecastClass? {
let data = viewModel.weatherArray
let relativeXPosition = location.x - geometry[proxy.plotAreaFrame].origin.x
if let date = proxy.value(atX: relativeXPosition) as Date? {
// Find the closest date element.
var minDistance: TimeInterval = .infinity
var index: Int? = nil
for weatherDataIndex in data.indices {
let nthWeatherDataDistance = data[weatherDataIndex].DATETIME.distance(to: date)
if abs(nthWeatherDataDistance) < minDistance {
minDistance = abs(nthWeatherDataDistance)
index = weatherDataIndex
}
}
if let index {
return data[index]
}
}
return nil
}
}
Here's the Backtrace:
Backtrace:
<CGPathAddLineToPoint+78>
<$sSo16CGMutablePathRefa12CoreGraphicsE4move2to9transformySo7CGPointV_So17CGAffineTransformVtFTm+113>
<_Charts_getAxisMarkWitnessTable+3021427>
<_Charts_getAxisMarkWitnessTable+3022243>
<_Charts_getAxisMarkWitnessTable+3022291>
<__CGPathApplyWithBlock_block_invoke+63>
<_ZNK2CG4Path5applyEU13block_pointerFv17CGPathElementTypePK7CGPointPbE+246>
<CGPathApplyWithBlock+114>
<_Charts_getAxisMarkWitnessTable+3016835>
<_Charts_getAxisMarkWitnessTable+428626>
<_Charts_getAxisMarkWitnessTable+464967>
<__swift_memcpy33_4+28201>
<_Charts_getAxisMarkWitnessTable+425557>
<_Charts_getAxisMarkWitnessTable+415811>
<_Charts_getAxisMarkWitnessTable+462771>
<_Charts_getAxisMarkWitnessTable+416756>
<_Charts_getAxisMarkWitnessTable+416214>
<_Charts_getAxisMarkWitnessTable+413871>
<_Charts_getAxisMarkWitnessTable+462275>
<_Charts_getAxisMarkWitnessTable+416756>
<_Charts_getAxisMarkWitnessTable+412741>
<_Charts_getAxisMarkWitnessTable+422521>
<_Charts_getAxisMarkWitnessTable+464073>
<_Charts_getAxisMarkWitnessTable+417649>
<_Charts_getAxisMarkWitnessTable+421314>
<_Charts_getAxisMarkWitnessTable+432881>
<_Charts_getAxisMarkWitnessTable+434361>
<_Charts_getAxisMarkWitnessTable+434361>
<_Charts_getAxisMarkWitnessTable+434361>
<_Charts_getAxisMarkWitnessTable+444893>
<_callVisitTableColumnType2+31236>
<__swift_memcpy108_8+1328>
<__swift_memcpy12_4+43911>
<__swift_memcpy12_4+34396>
<_callVisitTableColumnType2+30317>
<block_destroy_helper.6215+63949>
<_ZN2AG5Graph11UpdateStack6updateEv+537>
<_ZN2AG5Graph16update_attributeENS_4data3ptrINS_4NodeEEEj+443>
<_ZN2AG5Graph9value_refENS_11AttributeIDEPK15AGSwiftMetadataRh+123>
<AGGraphGetValue+287>
<__swift_memcpy38_4+28770>
<get_witness_table 7SwiftUI19WidgetConfigurationRzAA13PreferenceKeyRd__r__lAA15Modif
<get_witness_table 7SwiftUI19WidgetConfigurationRzAA13PreferenceKeyRd__r__lAA15Modi
<__swift_memcpy106_8+51272>
<__swift_memcpy106_8+51342>
<-[UIView(CALayerDelegate) layoutSublayersOfLayer:]+2305>
<_ZN2CA5Layer16layout_if_neededEPNS_11TransactionE+526>
<-[UIView(Hierarchy) layoutBelowIfNeeded]+1447>
<__swift_memcpy64_4+166111>
<block_destroy_helper.23+59728>
<block_destroy_helper.23+59750>
<+[UIView(Animation) performWithoutAnimation:]+84>
<__swift_memcpy64_4+161134>
<block_destroy_helper.23+59728>
<block_destroy_helper.23+59750>
<+[UIView(Animation) performWithoutAnimation:]+84>
<__swift_memcpy64_4+166410>
<objectdestroy.142Tm+41107>
<block_destroy_helper+36990>
<block_destroy_helper+35295>
<get_witness_table 7SwiftUI19WidgetConfigurationRzAA13PreferenceKeyRd__r__lAA15M
<__swift_memcpy89_8+19524>
<dynamic_cast_existential_0_superclass_conditional+6323>
<block_destroy_helper.89+25608>
<_callVisitStyleContextType2+33683>
<block_destroy_helper.130+8663>
<block_destroy_helper.130+8519>
<-[UIViewController _setViewAppearState:isAnimating:]+1061>
<-[UIViewController __viewDidAppear:]+146>
<-[UINavigationController viewDidAppear:]+173>
<-[UIViewController _setViewAppearState:isAnimating:]+1061>
<__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke_2+189>
<__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke+185>
<__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__+7>
<-[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:]+80>
<-[UIViewController _setViewAppearState:isAnimating:]+2066>
<__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke_2+189>
<__52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke+185>
<__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__+7>
<-[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:]+80>
<-[UIViewController _setViewAppearState:isAnimating:]+2066>
<-[UIViewController __viewDidAppear:]+146>
<-[UINavigationController viewDidAppear:]+173>
<-[UIViewController _setViewAppearState:isAnimating:]+1061>
<-[UIViewController __viewDidAppear:]+146>
<-[UIViewController _endAppearanceTransition:]+232>
<-[UINavigationController navigationTransitionView:didEndTransition:fromView:toV
<__49-[UINavigationController _startCustomTransition:]_block_invoke+620>
<-[_UIViewControllerTransitionContext completeTransition:]+101>
<__53-[_UINavigationParallaxTransition animateTransition:]_block_invoke.163+841>
<__UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__+15>
<-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:]+797>
<-[UIViewAnimationState sendDelegateAnimationDidStop:finished:]+190>
<-[UIViewAnimationState animationDidStop:finished:]+263>
<-[UIViewAnimationState animationDidStop:finished:]+648>
<_ZN2CA5Layer23run_animation_callbacksEPv+318>
<_dispatch_client_callout+8>
<_dispatch_main_queue_drain+1463>
<_dispatch_main_queue_callback_4CF+31>
<__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__+9>
<__CFRunLoopRun+2482>
<CFRunLoopRunSpecific+560>
<GSEventRunModal+139>
<-[UIApplication _run]+994>
<UIApplicationMain+123>
<__swift_memcpy93_8+11936>
<__swift_memcpy93_8+11597>
<__swift_memcpy195_8+12255>
<$s27SpotWx_MergeBackendFrontend0ab1_cdE3AppV5$mainyyFZ+30>
<main+9>
1079162bf
[Unknown process name] CGPathCloseSubpath: no current point.
I think I've narrowed the problem down to the interactivity of the chart. When I simplify the chart down to this the errors go away:
private var chart: some View {
Chart(viewModel.weatherArray, id: \.DATETIME) {
LineMark(
x: .value("Date", $0.DATETIME),
y: .value("Temp", $0.TMP)
)
}
}