Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash while selecting data point in zoomed state #3486

Open
1 task done
Saranjithpk opened this issue Jun 4, 2018 · 11 comments
Open
1 task done

Crash while selecting data point in zoomed state #3486

Saranjithpk opened this issue Jun 4, 2018 · 11 comments

Comments

@Saranjithpk
Copy link

Saranjithpk commented Jun 4, 2018

What did you do?

ℹ I zoomed the charts and made a selection to one of the data point.

What did you expect to happen?

ℹ The delegate method with selected coordinates should be called.

What happened instead?

ℹ Crash happed.

Crash log:

> * thread #1, queue = 'com.apple.main-thread', stop reason = Fatal error: Double value cannot be converted to Int because it is either infinite or NaN
    frame #0: 0x0000000116b4f900 libswiftCore.dylib`_swift_runtime_on_report
    frame #1: 0x0000000116b90181 libswiftCore.dylib`_swift_stdlib_reportFatalError + 113
    frame #2: 0x0000000116b2c38f libswiftCore.dylib`partial apply forwarder for closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #2 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._fatalErrorMessage(Swift.StaticString, Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 63
    frame #3: 0x00000001168571eb libswiftCore.dylib`function signature specialization <preserving fragile attribute, Arg[1] = [Closure Propagated : reabstraction thunk helper from @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> () to @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> (@out ()), Argument Types : [@callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> ()]> of generic specialization <preserving fragile attribute, ()> of Swift.StaticString.withUTF8Buffer<A>((Swift.UnsafeBufferPointer<Swift.UInt8>) -> A) -> A + 187
    frame #4: 0x0000000116ae00f1 libswiftCore.dylib`partial apply forwarder for closure #2 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._fatalErrorMessage(Swift.StaticString, Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 113
    frame #5: 0x00000001168571eb libswiftCore.dylib`function signature specialization <preserving fragile attribute, Arg[1] = [Closure Propagated : reabstraction thunk helper from @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> () to @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> (@out ()), Argument Types : [@callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> ()]> of generic specialization <preserving fragile attribute, ()> of Swift.StaticString.withUTF8Buffer<A>((Swift.UnsafeBufferPointer<Swift.UInt8>) -> A) -> A + 187
    frame #6: 0x0000000116a0b410 libswiftCore.dylib`function signature specialization <preserving fragile attribute, Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage(Swift.StaticString, Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 96
  * frame #7: 0x000000010ffccbea Charts`AxisRendererBase.computeAxisValues(min=NaN, max=NaN, self=0x0000600000e58630) at AxisRendererBase.swift:125
    frame #8: 0x0000000110177e05 Charts`XAxisRenderer.computeAxisValues(min=NaN, max=NaN, self=0x0000600000e58630) at XAxisRenderer.swift:62
    frame #9: 0x0000000110177d3e Charts`XAxisRenderer.computeAxis(min=0, max=2.02, inverted=false, self=0x0000600000e58630) at XAxisRenderer.swift:57
    frame #10: 0x000000010fffe704 Charts`BarLineChartViewBase.notifyDataSetChanged(self=0x00007fe4bb579560) at BarLineChartViewBase.swift:332
    frame #11: 0x000000011007618a Charts`ChartViewBase.data.setter(newValue=0x0000600000a900e0, self=0x00007fe4bb579560) at ChartViewBase.swift:269
    frame #12: 0x000000010e6fc1d2 CittaDoctor.ai`GraphCell.drawGraph(values=3 values, isBPGraph=false, xArray=3 elements, minValue=0, maxValue=150, values2=3 values, graphColor=0x00006000012763c0, normalRange=(unit = "", maximum = 0, minimum = 0), optionArrays=CittaDoctor_ai.Options @ 0x00007ffee162c6f8, self=0x00007fe4bb5d5700) at GraphCell.swift:457
    frame #13: 0x000000010e784423 CittaDoctor.ai`HistoryListingCV.collectionView(collectionView=0x00007fe4b6add000, indexPath=2 indices, self=0x00007fe4b6b16c00) at HistoryListingCV.swift:177
    frame #14: 0x000000010e784bbc CittaDoctor.ai`@objc HistoryListingCV.collectionView(_:cellForItemAt:) at HistoryListingCV.swift:0
    frame #15: 0x00000001127d48b6 UIKit`-[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:notify:] + 290

Charts Environment

Charts version/Branch/Commit Number:3.0.4
Xcode version:9.2
Swift version:4
Platform(s) running Charts:iOS 11.3
macOS version running Xcode: 10.13.4

Demo Project

ℹ Please link to or upload a project we can download that reproduces the issue.

@liuxuan30
Copy link
Member

liuxuan30 commented Jun 22, 2018

please take a look at

    frame #8: 0x0000000110177e05 Charts`XAxisRenderer.computeAxisValues(min=NaN, max=NaN, self=0x0000600000e58630) at XAxisRenderer.swift:62
    frame #9: 0x0000000110177d3e Charts`XAxisRenderer.computeAxis(min=0, max=2.02, inverted=false, self=0x0000600000e58630) at XAxisRenderer.swift:57

why computeAxis generate NaN. Something wrong with your matrix.

please debug and provide more debug trace so we know where goes off.

    open override func computeAxis(min: Double, max: Double, inverted: Bool)
    {
        var min = min, max = max
        
        if let transformer = self.transformer
        {
            // calculate the starting and entry point of the y-labels (depending on
            // zoom / contentrect bounds)
            if viewPortHandler.contentWidth > 10 && !viewPortHandler.isFullyZoomedOutX
            {
                let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
                let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
                
                if inverted
                {
                    min = Double(p2.x)
                    max = Double(p1.x)
                }
                else
                {
                    min = Double(p1.x)
                    max = Double(p2.x)
                }
            }
        }
        
        computeAxisValues(min: min, max: max)
    }

please debug this function and print out all values that lead min/max to NaN

@Saranjithpk
Copy link
Author

I just put your code in computeAxis Function. but I can't find any bool named inverted in the same. So I just removed the if loop and kept true block only.
What I put is as below,

    @objc open func computeAxisValues(min: Double, max: Double)
    {
        guard let axis = self.axis else { return }
        var min = min, max = max
        
        if let transformer = self.transformer
       {
            // calculate the starting and entry point of the y-labels (depending on
            // zoom / contentrect bounds)
            if (viewPortHandler?.contentWidth)! > CGFloat(10.0) && !(viewPortHandler?.isFullyZoomedOutX)!
          {
               let p1 = transformer.valueForTouchPoint(CGPoint(x: (viewPortHandler?.contentLeft)!, y: (viewPortHandler?.contentTop)!))
               let p2 = transformer.valueForTouchPoint(CGPoint(x: (viewPortHandler?.contentRight)!, y: (viewPortHandler?.contentTop)!))
                
               min = Double(p2.x)
              max = Double(p1.x)
              print("p1.x:", p1.x,"p1.y:", p1.y,"p2.x:",p2.x,"p2.y:",p2.y,"Min:", min, "Max:", max)
        }

    // Rest of code here.
  }

My log before selection on selection and on crash as below,

p1.x: 0.609658677494641 p1.y: 110.0 p2.x: 3.43860364530313 p2.y: 110.0 Min: 3.43860364530313 Max: 0.609658677494641
p1.x: 0.630491120754639 p1.y: 110.0 p2.x: 3.41873694444591 p2.y: 110.0 Min: 3.41873694444591 Max: 0.630491120754639
p1.x: 0.630491120754639 p1.y: 110.0 p2.x: 3.41873694444591 p2.y: 110.0 Min: 3.41873694444591 Max: 0.630491120754639
p1.x: 0.651229249533855 p1.y: 110.0 p2.x: 3.398960185875 p2.y: 110.0 Min: 3.398960185875 Max: 0.651229249533855
p1.x: 0.651229249533855 p1.y: 110.0 p2.x: 3.398960185875 p2.y: 110.0 Min: 3.398960185875 Max: 0.651229249533855
p1.x: 0.667225140225756 p1.y: 110.0 p2.x: 3.38370582653968 p2.y: 110.0 Min: 3.38370582653968 Max: 0.667225140225756
p1.x: 0.667225140225756 p1.y: 110.0 p2.x: 3.38370582653968 p2.y: 110.0 Min: 3.38370582653968 Max: 0.667225140225756
p1.x: 0.696229955557689 p1.y: 110.0 p2.x: 3.35604560529598 p2.y: 110.0 Min: 3.35604560529598 Max: 0.696229955557689
p1.x: 0.696229955557689 p1.y: 110.0 p2.x: 3.35604560529598 p2.y: 110.0 Min: 3.35604560529598 Max: 0.696229955557689
p1.x: 0.71513346472276 p1.y: 110.0 p2.x: 3.33801841774783 p2.y: 110.0 Min: 3.33801841774783 Max: 0.71513346472276
p1.x: 0.71513346472276 p1.y: 110.0 p2.x: 3.33801841774783 p2.y: 110.0 Min: 3.33801841774783 Max: 0.71513346472276
p1.x: 0.730490532059137 p1.y: 110.0 p2.x: 3.32337326744029 p2.y: 110.0 Min: 3.32337326744029 Max: 0.730490532059137
p1.x: 0.730490532059137 p1.y: 110.0 p2.x: 3.32337326744029 p2.y: 110.0 Min: 3.32337326744029 Max: 0.730490532059137
p1.x: 0.751410107522615 p1.y: 110.0 p2.x: 3.30342347362082 p2.y: 110.0 Min: 3.30342347362082 Max: 0.751410107522615
p1.x: 0.751410107522615 p1.y: 110.0 p2.x: 3.30342347362082 p2.y: 110.0 Min: 3.30342347362082 Max: 0.751410107522615
p1.x: 0.751410107522615 p1.y: 110.0 p2.x: 3.30342347362082 p2.y: 110.0 Min: 3.30342347362082 Max: 0.751410107522615
p1.x: 0.751410107522615 p1.y: 110.0 p2.x: 3.30342347362082 p2.y: 110.0 Min: 3.30342347362082 Max: 0.751410107522615
Selected 3.0 90.0 Index) // Logged from selection delegate
p1.x: 0.751410107522615 p1.y: 110.0 p2.x: 3.30342347362082 p2.y: 110.0 Min: 3.30342347362082 Max: 0.751410107522615
p1.x: 0.751410107522615 p1.y: 101.0 p2.x: 3.30342347362082 p2.y: 101.0 Min: 3.30342347362082 Max: 0.751410107522615
p1.x: 0.751410107522615 p1.y: 110.0 p2.x: 3.30342347362082 p2.y: 110.0 Min: 3.30342347362082 Max: 0.751410107522615
p1.x: 0.751410107522615 p1.y: 1.61792382137608e+308 p2.x: 3.30342347362082 p2.y: 1.61792382137608e+308 Min: 3.30342347362082 Max: 0.751410107522615
2018-06-22 11:06:33.865541+0530 PersonalCare[72271:1394154] [Unknown process name] CGAffineTransformInvert: singular matrix.
2018-06-22 11:06:33.865712+0530 PersonalCare[72271:1394154] [Unknown process name] CGAffineTransformInvert: singular matrix.
p1.x: nan p1.y: nan p2.x: nan p2.y: nan Min: nan Max: nan
(lldb)

All variables in the scope during the crash

min	Double	78
max	Double	102
self	Charts.YAxisRenderer	0x000060400103a180
axis	Charts.YAxis	0x00007fdafdf6ddf0
Charts.AxisBase	Charts.AxisBase	
drawBottomYLabelEntryEnabled	Bool	true	
drawTopYLabelEntryEnabled	Bool	true	
inverted	Bool	false	
drawZeroLineEnabled	Bool	false	
zeroLineColor	NSUIColor?	0x0000600000443750
zeroLineWidth	CGFloat	1	
zeroLineDashPhase	CGFloat	0	
zeroLineDashLengths	[CGFloat]?	nil	none
spaceTop	CGFloat	0.10000000000000001	
native	CGFloat.NativeType	0.10000000000000001
spaceBottom	CGFloat	0.10000000000000001	
native	CGFloat.NativeType	0.10000000000000001
labelPosition	Charts.YAxis.LabelPosition	outsideChart
_axisDependency	Charts.YAxis.AxisDependency	right
minWidth	CGFloat	0	
native	CGFloat.NativeType	0
maxWidth	CGFloat	+Inf	
native	CGFloat.NativeType	+Inf
min	Double	NaN
max	Double	NaN
interval	Double	NaN
n	Int	140732830998736
yMin	Double	NaN
yMax	Double	NaN
labelCount	Int	6
range	Double	NaN
rawInterval	Double	NaN
intervalMagnitude	Double	
intervalSigDigit	Int	

Please let me know if these information is enough.

Thanks for your support.

@liuxuan30
Copy link
Member

liuxuan30 commented Jun 22, 2018

This function I post is within the library... what you mean by I just put your code in computeAxis Function.? If you really copy the code into your project, it won't matter anyway.

What you should do is to add some break points before and after transformer.valueForTouchPoint and figure out what lead to NaN.

@Saranjithpk
Copy link
Author

Saranjithpk commented Jun 22, 2018

Yeah. I got what u meant now. I have checked the same and seems issue fixed by adding these lines of code into AxisRenderBase.swift at line 125
Since interval is getting as nan.

  if !(interval > 0 || interval < 0) {
       print("Crash solved")
       return
 }

// Rest of code..
let intervalMagnitude = ChartUtils.roundToNextSignificant(number: pow(10.0, Double(Int(log10(interval)))))
        let intervalSigDigit = Int(interval / intervalMagnitude)

@liuxuan30
Copy link
Member

as I said, the point is to figure out how the NaN is created, not to avoid it after that.

@Saranjithpk
Copy link
Author

Saranjithpk commented Jul 16, 2018

I think nan is created after some calculations done inside the charts library. I can give all the datasets given to charts when crash occurs. It will be great if you can tell me what is the purpose of using this interval property, so that I can debug the same code better

Please let me know if need any further assistance to track issue.
Thanks for your help and support.

@liuxuan30
Copy link
Member

hmm, interval is used to calculate the proper 'interval' to use.. I don't remember very clearly, but the code should tell. Will you be able to know what number causes to NaN? We didn't need all data sets values, just what calculation leads to NaN

@philfi
Copy link

philfi commented Aug 15, 2018

Hi @Saranjithpk did you ever get anywhere with this?

The best I can tell atm is that the point values by transformer.valueForTouchPoint in the computeAxisValues of XAxisRenderer have x and y property values of .nan. That is what's leading to the downstream exception in AxisRendererBase computeAxisValues.
Some quick logging shows that for some reason the tx and ty values of pixelToValueMatrix are nan:

pixelToValueMatrix: CGAffineTransform(a: 19.2000124087434, b: 0.0, c: -0.0, d: -0.344167172330097, tx: nan, ty: nan)

Will continue to dig into how it got into this state and update as I learn more but if you've already made it out of the rabbit hole would appreciate any assistance!

@philfi
Copy link

philfi commented Aug 15, 2018

ok not sure if my case is the same as @Saranjithpk but I was able to trace it back to a mistake in my code that passed a duration of 0 into moveViewToAnimated(xValue: Double, yValue: Double, axis: YAxis.AxisDependency, duration: TimeInterval). This in turn led to the phase value to be set to nan in updateAnimationPhase and the rest of the dominoes fell from there.

Glad to have figured this out and would like to contribute something to hopefully keep others from falling into this same trap. @liuxuan30 given the info I've provided, I'm wondering if you think it makes more sense to enforce duration > 0 in AnimatedViewPortJob (though its default value is 0 too so would want to update that as well) or if something else should be done to protect the phase value from being set to nan i.e. if duration <= 0 { phase = 1.0 }?

@Sega-Zero
Copy link

having this issue too. pixelToValueMatrix contains nan in tx and ty.

figured out that _matrixValueToPx begin to contain nan values in prepareMatrixValuePx, because chartYMin == +Inf, which is because leftAxis.axisRange is inf.

This happens because leftAxis is disabled and never configured. Not sure if this code should even be calculated if the axis is disabled.

If i comment the line that disables leftAxis - no crash is occured.
If I set the values to leftAxis with values for rightAxis + disable leftAxis, no crash is occured.

@SURYAKANTSHARMA
Copy link

@liuxuan30 Any update on this ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants