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

Fixed, If the last value is the max or min, the range will be wrong #2229

Merged
merged 4 commits into from May 26, 2017

Conversation

aelam
Copy link
Contributor

@aelam aelam commented Mar 7, 2017

The last entry is ignored.
If the last value is the max or min, the range will be wrong

the last entry is ignored. If the last value is the max or min, the range will be wrong
@aelam
Copy link
Contributor Author

aelam commented Mar 7, 2017

Another problem.
How about just one entry?
The max/min are the same, if the autoScale is enabled, the charts doesn't know the range because it is 0, right?

@codecov-io
Copy link

codecov-io commented Mar 7, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@1ed1561). Click here to learn what that means.
The diff coverage is 0%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #2229   +/-   ##
=========================================
  Coverage          ?   18.44%           
=========================================
  Files             ?      124           
  Lines             ?    14619           
  Branches          ?        0           
=========================================
  Hits              ?     2696           
  Misses            ?    11923           
  Partials          ?        0
Impacted Files Coverage Δ
...s/Data/Implementations/Standard/ChartDataSet.swift 33.55% <0%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1ed1561...30518c6. Read the comment docs.

@liuxuan30
Copy link
Member

Is there any issue to track this PR? we have no context for this change.

@aelam
Copy link
Contributor Author

aelam commented Mar 10, 2017

I didn't notice other issues about this.
Let me tell you my case

  1. XAxis can scale , YAxis can autoScale
  2. ChartView just has 2 CandleStick entries(other type Data is the same, I think), and the second one
    is the larger one

Go through this case
My visible XValues is 1 ,2, my XAxis is from 0.5 to 2.5
When goes into calcMinMaxY
indexFrom = 0, indexTo = 1
and the indexFrom..<indexTo is an open range
that means it just calculate one value
if it were indexFrom...indexTo, it would work fine

Case 2: Just one entry
There is only one entry. then indexTo = 0, indexFrom = 0
when goes into if indexTo <= indexFrom { return } DONE
it will never run into the for-loop to calculate.
Then I can't get the correct Y range anyway

Case 3: Based on the case 2, Just one entry
and the YMax and YMin is the same!,
What can I do?

So the correct code to fix the first two problems I think it may be like this

open override func calcMinMaxY(fromX: Double, toX: Double)
         let indexFrom = entryIndex(x: fromX, closestToY: Double.nan, rounding: .down)
         let indexTo = entryIndex(x: toX, closestToY: Double.nan, rounding: .up)
          
          if indexTo < indexFrom { return }
          
       for i in indexFrom...indexTo {
            ...
       }


@aelam
Copy link
Contributor Author

aelam commented Mar 10, 2017

I just checked the android version .
We are different here

@Override
    public void calcMinMaxY(float fromX, float toX) {

        if (mValues == null || mValues.isEmpty())
            return;

        mYMax = -Float.MAX_VALUE;
        mYMin = Float.MAX_VALUE;

        int indexFrom = getEntryIndex(fromX, Float.NaN, Rounding.DOWN);
        int indexTo = getEntryIndex(toX, Float.NaN, Rounding.UP);

        for (int i = indexFrom; i <= indexTo; i++) {

            // only recalculate y
            calcMinMaxY(mValues.get(i));
        }
    }

@aelam
Copy link
Contributor Author

aelam commented Mar 31, 2017

@xuan @danielgindi could you please verify this

@liuxuan30
Copy link
Member

@danielgindi should be still busy.. Haven't seen him recently. As this is a foundermental change, we need to have @danielgindi to review.

@aelam
Copy link
Contributor Author

aelam commented Apr 1, 2017 via email

@liuxuan30
Copy link
Member

@danielgindi please take a look at this PR

@liuxuan30
Copy link
Member

liuxuan30 commented Apr 13, 2017

@aelam I am taking this PR right now, some thoughts:

   let indexTo = entryIndex(x: toX, closestToY: Double.nan, rounding: .up)

This is rounding .up, which means indexTo may be larger by 1, which would cause oob issue, right?

I took a look at open override func entryIndex(x xValue: Double, closestToY yValue: Double, rounding: ChartDataSetRounding) -> Int, actually quite complicated than I expect, though android use <= at the moment.

We have to check the boundary again.
In order to make sure ... works without crash, first we need to verify

       if closest != -1
        {
            let closestXValue = _values[closest].x
            
            if rounding == .up
            {
                // If rounding up, and found x-value is lower than specified x, and we can go upper...
                if closestXValue < xValue && closest < _values.count - 1
                {
                    closest += 1
                }
            }

that closest when it's the last entry, and it won't get +1 that will lead to crash.

Then, in another condition:

            // Search by closest to y-value
            if !yValue.isNaN
            {
                while closest > 0 && _values[closest - 1].x == closestXValue
                {
                    closest -= 1
                }
                
                var closestYValue = _values[closest].y
                var closestYIndex = closest
                
                while true
                {
                    closest += 1
                    if closest >= _values.count { break }
                    
                    let value = _values[closest]
                    
                    if value.x != closestXValue { break }
                    if abs(value.y - yValue) < abs(closestYValue - yValue)
                    {
                        closestYValue = yValue
                        closestYIndex = closest
                    }
                }
                
                closest = closestYIndex
            }
        }

Here

closest += 1
if closest >= _values.count { break }

I guess that's why it uses ..< in the first place.

However, in

let indexTo = entryIndex(x: toX, closestToY: Double.nan, rounding: .up)

It passes closestToY: Double.nan, so thank god the second if !yValue.isNaN is not hit. Now I think it's safe to use ... now.

Share your thoughts if you can come up any other potential risks.

I think this is positive to merge.

@liuxuan30
Copy link
Member

liuxuan30 commented Apr 24, 2017

should be safe to merge then with the analysis above and CI tests.
@danielgindi @petester42 do you want to review this? As this may impact a lot. I want to make sure we don't miss any cases

@liuxuan30 liuxuan30 merged commit c681fe5 into ChartsOrg:master May 26, 2017
@liuxuan30 liuxuan30 self-requested a review May 26, 2017 01:34
@emmaviolet
Copy link

@danielgindi @petester42 are there any plans to release a new version with the latest changes? This is a useful bugfix 🙏

@liuxuan30
Copy link
Member

It's already merged, so you can easily build one, or take the change and make a patch

PeterSrost pushed a commit to sokol8/Charts that referenced this pull request Oct 31, 2018
Fixed, If the last value is the max or min, the range will be wrong
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

Successfully merging this pull request may close these issues.

None yet

4 participants