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

Can we add nil values to a dataset yet? #113

Closed
AlBirdie opened this issue May 28, 2015 · 29 comments
Closed

Can we add nil values to a dataset yet? #113

AlBirdie opened this issue May 28, 2015 · 29 comments
Labels

Comments

@AlBirdie
Copy link
Contributor

Basically, I need to draw a chart that doesn't have continous data, so the y values could look like this;

nil, Entry, Entry, nil, nil, nil, Entry,... you get the idea.

The chart should then just show gaps where there's no data for the corresponding x value.
I'm pretty certain that this isn't supported yet, and I'm not sure how to that either to be honest.
Do have an idea with regards to a suitable implementation for this?

There's already a feature request for this for the Android version (PhilJay/MPAndroidChart#293).

@danielgindi
Copy link
Collaborator

Well, you don't have to insert nils. You just add yVals for whatever xIndex you want.

Suppose you have:
xIndexes ["Apples", "Oranges", "Strawberries"]

You could just set:
yVals [0 = 5, 2 = 37]

And not set value for Oranges...

@AlBirdie
Copy link
Contributor Author

AlBirdie commented Jun 1, 2015

Not sure how that would be applicable for the following implementation;

NSMutableArray *data = [self.dataSource.calculatedData objectAtIndex:0];

NSMutableArray *xVals       = [NSMutableArray new];
NSMutableArray *yVals       = [NSMutableArray new];
NSMutableArray *barVals     = [NSMutableArray new];


int i = 0;
for (ChartDataPoint *currentItem in data) {

    ChartDataEntry *lineEntry = [[ChartDataEntry alloc] initWithValue:[currentItem.yValue floatValue] xIndex:i];
    BarChartDataEntry *barEntry = [[BarChartDataEntry alloc] initWithValue:[currentItem.yValue floatValue] xIndex:i];

    [yVals addObject:lineEntry];
    [barVals addObject:barEntry];
    [xVals addObject:[self.dateFormatter stringFromDate:(NSDate *) currentItem.xValue]];

    i++;
}

Say I want to omit the first 10 y values. In that case I have to insert something so that the x values start from index 10 onwards.

@danielgindi
Copy link
Collaborator

The thing is you do not have to insert y values for xindex 0. You coulds
start from 10, but still set the array if xindexes to contain those from
0-9

‏בתאריך יום שני, 1 ביוני 2015, AlBirdie notifications@github.com כתב:

Not sure how that would be applicable for the following implementation;

NSMutableArray *data = [self.dataSource.calculatedData objectAtIndex:0];

NSMutableArray *xVals = [NSMutableArray new];
NSMutableArray *yVals = [NSMutableArray new];
NSMutableArray *barVals = [NSMutableArray new];

int i = 0;
for (ChartDataPoint *currentItem in data) {

ChartDataEntry *lineEntry = [[ChartDataEntry alloc] initWithValue:[currentItem.yValue floatValue] xIndex:i];
BarChartDataEntry *barEntry = [[BarChartDataEntry alloc] initWithValue:[currentItem.yValue floatValue] xIndex:i];

[yVals addObject:lineEntry];
[barVals addObject:barEntry];
[xVals addObject:[self.dateFormatter stringFromDate:(NSDate *) currentItem.xValue]];

i++;

}

Say I want to omit the first 10 y values. In that case I have to insert
something so that the x values start from index 10 onwards.


Reply to this email directly or view it on GitHub
#113 (comment)
.

@dorsoft
Copy link

dorsoft commented Jun 1, 2015

If autoscaling is on I get an exception when I add xValues without y values at the end of the dataset.
I'm using a combined chart with a candle and a line datasets.

I've managed to resolve this issue by changing:
1.
CandleChartDataSet - calcMinMax (line 65)
from:
endValue = end;
to
endValue = end > (entries.count - 1) ? (entries.count - 1) : end;

ChartDataSet - calcMinMax (line 99)
from:
endValue = end;
to
endValue = end > (_yVals.count - 1) ? (_yVals.count - 1) : end;

@AlBirdie
Copy link
Contributor Author

AlBirdie commented Jun 1, 2015

Interesting, for me the application crashes at _yVals.count in ChartDataSet (EXC_BAD_INSTRUCTION).

@danielgindi
Copy link
Collaborator

_yVals will try to automatically unwrap, and could crash on that. Is _yVals
nil?

On Mon, Jun 1, 2015 at 3:02 PM, AlBirdie notifications@github.com wrote:

Interesting, for me the application crashes at _yVals.count in
ChartDataSet (EXC_BAD_INSTRUCTION).


Reply to this email directly or view it on GitHub
#113 (comment)
.

@AlBirdie
Copy link
Contributor Author

AlBirdie commented Jun 1, 2015

Nope, _yVals is not nil. Debugging Swift code in an ObjC project is kind of pointless as it doesn't work properly.
However, @dorsoft 's adaptions work for the demo project, now I just need to figure out why my project already crashes on yVals.count.

@danielgindi
Copy link
Collaborator

Yeah I hope they fix it in the upcoming Xcode update. It's not showing
variables unless you dig into the "self" in the inspector

On Mon, Jun 1, 2015 at 3:38 PM, AlBirdie notifications@github.com wrote:

Nope, _yVals is not nil. Debugging Swift code in an ObjC project is kind
of pointless as it doesn't work properly.
However, @dorsoft https://github.com/dorsoft 's adaptions work for the
demo project, now I just need to figure out why my project already crashes
on yVals.count.


Reply to this email directly or view it on GitHub
#113 (comment)
.

@AlBirdie
Copy link
Contributor Author

AlBirdie commented Jun 1, 2015

Alright, got it. The problem with my project relates to the performance enhancement @dorsoft mentioned in #29;

I've managed to make a candle stick chart with 10k data points pan/zoom smoothly. by changing
CandleStickChartRenderer.swift, line 76,77 from:

var minx = max(dataSet.entryIndex(entry: entryFrom, isEqual: true), 0);
var maxx = min(dataSet.entryIndex(entry: entryTo, isEqual: true) + 1, entries.count);

to

var minx = max(_minX, 0);
var maxx = _maxX + 1;

That essentially breaks the drawLinear method for LineCharts that have "empty" x values. Go back to the original code, and the method executes normally.

@danielgindi
Copy link
Collaborator

That's why I don't accept such changes without extensive testing :-)

On Mon, Jun 1, 2015 at 4:42 PM, AlBirdie notifications@github.com wrote:

Alright, got it. The problem with my project relates to the performance
enhancement @dorsoft https://github.com/dorsoft mentioned in #29
#29;

I've managed to make a candle stick chart with 10k data points pan/zoom
smoothly. by changing
CandleStickChartRenderer.swift, line 76,77 from:

var minx = max(dataSet.entryIndex(entry: entryFrom, isEqual: true), 0);
var maxx = min(dataSet.entryIndex(entry: entryTo, isEqual: true) + 1,
entries.count);

to

var minx = max(_minX, 0);
var maxx = _maxX + 1;

That essentially breaks the drawLinear method for LineCharts that have
"empty" x values. Go back to the original code, and the method executes
normally.


Reply to this email directly or view it on GitHub
#113 (comment)
.

@dorsoft
Copy link

dorsoft commented Jun 1, 2015

Just change
var maxx = _maxX + 1;
to
var maxx = min(_maxX + 1, entries.count);

This fixes the issue

@AlBirdie
Copy link
Contributor Author

AlBirdie commented Jun 1, 2015

That fixes the issue of the source not being executable. However, there are other side effects with this. For instance, in case you omit the first say 10 values, the renderer will skip 10 values whilst panning (in case the visible range is smaller than the max range of course), even though the current x range ranges from like 30 to 70. Min / max calculations don't work properly as well.

@danielgindi
Copy link
Collaborator

@AlBirdie I didn't understand - is the issue solved for you? What is the current status on this?

@AlBirdie
Copy link
Contributor Author

AlBirdie commented Jun 2, 2015

Nah, the issue remains. I've also tried to use the 'lowestVisibileXIndex' and 'highestVisibleXIndex' instead of calculating minx and maxx manually in the renderer, but with the same results, when you zoom in on a set that omits the first 10 values and then pan the set, it will always omit the first 10 values, even if your visible range goes from 20 to 50. Couldn't figure out why this happens yet.

@danielgindi
Copy link
Collaborator

I bet it's something with min/max x values not updating correctly. I'll look into it.

@danielgindi danielgindi added the bug label Jun 2, 2015
@liuxuan30
Copy link
Member

I just use this thread to ask, can I add null values (NSNull singleton) into Y? I get your idea that only insert valid values at the xIndex. Is it a must that we have to detect if the value at xIndex is nil/Null, we should passby and continue the next?

@danielgindi
Copy link
Collaborator

@liuxuan30 you shouldn't add NSNull into the y values array. Just skip anything you do not want... The compiler is also supposed to warn when adding null values as it is not marked as nullable in Swift.

@danielgindi
Copy link
Collaborator

@AlBirdie I'm not experiencing the problem you are describing. Watch this:

ezgif com-video-to-gif

@AlBirdie
Copy link
Contributor Author

Interesting... What implementation of the library did you use for that demo? Also, can you verify your result with autoScale on the y axis enabled?

@danielgindi
Copy link
Collaborator

Well it's the latest version, with Bar chart demo, setting the first y
value to be added at 10 instead of 0 (you can see the code), and autoScale
was disabled. Is this happening specifically with autoscale?

On Thu, Jun 11, 2015 at 12:31 PM, AlBirdie notifications@github.com wrote:

Interesting... What implementation of the library did you use for that
demo? Also, can you verify your result with autoScale on the y axis enabled?


Reply to this email directly or view it on GitHub
#113 (comment)
.

@AlBirdie
Copy link
Contributor Author

I haven't tested this without autoScale, so I suppose that that's the origin of the issue, yes. I'm currently not in the office to confirm this, but I'll get back to you as soon as possible.

@liuxuan30
Copy link
Member

@danielgindi for RadarChart, say we have two dataSets, and the x is [a,b,c,d,e], while dataSet 1 is [1,2,nil,nil,5] and dataSet 2 is [10,11,12,13,14], if we drop the two nil valus in dataSet 1, the radar chart shape is strange then... How should I deal with it?

@danielgindi
Copy link
Collaborator

It makes no sense to skip values in RadarChart

On Mon, Jun 15, 2015 at 9:27 AM, Xuan notifications@github.com wrote:

@danielgindi https://github.com/danielgindi for RadarChart, say we have
two dataSets, and the x is [a,b,c,d,e], while dataSet 1 is [1,2,nil,nil,5]
and dataSet 2 is [10,11,12,13,14], if we drop the two nil valus in dataSet
1, the radar chart shape is strange then... How should I deal with it?


Reply to this email directly or view it on GitHub
#113 (comment)
.

@liuxuan30
Copy link
Member

can radar chart support different size for xAxis and yAxis, say at xIndex 3, I have only have nil values. but other xIndex had valid data

@danielgindi
Copy link
Collaborator

I'm actually not an expert on radar charts. I don't understand them. You
might want to ask Phil...

On Mon, Jun 15, 2015 at 9:51 AM, Xuan notifications@github.com wrote:

can radar chart support different size for xAxis and yAxis, say at xIndex
3, I have only have nil values. but other xIndex had valid data


Reply to this email directly or view it on GitHub
#113 (comment)
.

@liuxuan30
Copy link
Member

Alright, but I think it's a serious topic ragards radar chart. Because I have run into some corner cases while doing unit tests. All about invalid data. What I am asking is, how you deal with the invalid data in radar chart? Simply ignore it and draw the line to next point? I tried to read the code, but a little hard to understand.

Looks like I need to create some test case so we can move forward

@AlBirdie
Copy link
Contributor Author

Daniel, I've tested your case and I'm seeing the same as you do. However, that's only the case for the BarChartRenderer. The LineRenderer behaves as I've described earlier (always omitting the first values during panning/zooming). This has nothing to do with the autoScaling, though.

Actually, nevermind. Using the "correct" implementation of minx and maxx in the LineChartRenderer's drawLinear, the error is gone. @dorsoft 's solution regarding minx and maxx calculations won't work with this, unfortunately. Hopefully we can find a way to still introduce the performance boost of his changes into the line renderer.

@danielgindi
Copy link
Collaborator

So I guess we can close this - and we'll look into a way to introduce @dorsoft's changes correctly :-)

@RomanoB
Copy link

RomanoB commented Jan 15, 2016

Hi all,

This topic is some months old now and closed, but I had a similar issue than
AlBirdie while visualising CandleSticks with gaps and found the way to solve it. And I suspect the solution is very similar for other type of Charts too.

I wanted to visualize a CandleSticks Chart with gaps, i.e. yVals not necessarily containing a DataEntry for each x-index, and when panning in a zoomed Chart I had rendering issues, like candlesticks after gaps not always drawn, depending on how much I was panning on the right.

I figured out implementation of CandleStickChartRenderer’s drawDataSet is incorrect.

In the for loop, the actual intention at line

// get the entry
let e = entries[j]

is to get the entry with xIndex == j, but it is wrong when yVals does not contain a value for each x-index.

If you have gaps in charts, you can be sure that

entries.count != entries[entries.count-1].xIndex

So my approach was to use entryForXIndex :

Before the loop :

let maxx = min(_maxX + 1, entries.last!.xIndex+1)

and in the loop

let e = dataSet.entryForXIndex(j) as! CandleChartDataEntry

You then need an extra condition, as "If no Entry at the specifed x-index is found, entryForXIndex method returns the Entry at the closest x-index"

So

if (e.xIndex != j)
{
continue
}

This worked for me.

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

No branches or pull requests

5 participants