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

Cubic Line goes too much over the top or below bottom. Needs flattening. #407

Closed
zxy198717 opened this issue Sep 22, 2015 · 33 comments
Closed

Comments

@zxy198717
Copy link

snip20150922_1

Like the picture, broken sometimes, anyone can help?

set1 = [[LineChartDataSet alloc] initWithYVals:yVals label:@"DataSet 1"];
set1.drawCubicEnabled = YES;
set1.cubicIntensity = 0.5;

When I set drawCubicEnabled is NO, The chart seems ok.

@liuxuan30
Copy link
Member

have you set any customAxisMax/Min? It seems it is being clipped?

@zxy198717
Copy link
Author

No set any max/min.
Test code:

    _lineChartView.delegate = self;
    //_lineChartView.backgroundColor = [UIColor yellowColor];

    _lineChartView.descriptionText = @"";
    _lineChartView.noDataTextDescription = @"You need to provide data for the chart.";

    _lineChartView.drawGridBackgroundEnabled = YES;
    _lineChartView.dragEnabled = NO;
    [_lineChartView setScaleEnabled:NO];
    _lineChartView.pinchZoomEnabled = NO;
    //[_lineChartView setViewPortOffsetsWithLeft:10.0 top:0.0 right:10.0 bottom:0.0];

    _lineChartView.legend.enabled = NO;

    _lineChartView.leftAxis.enabled = NO;
    _lineChartView.rightAxis.enabled = NO;
    _lineChartView.xAxis.enabled = NO;

    NSMutableArray *xVals = [[NSMutableArray alloc] init];

    [xVals addObject:@"1442246400000"];
    [xVals addObject:@"1442419200000"];
    [xVals addObject:@"1442505600000"];
    [xVals addObject:@"1442764800000"];
    [xVals addObject:@"1442851200000"];


    NSMutableArray *yVals = [[NSMutableArray alloc] init];

    [yVals addObject:[[ChartDataEntry alloc] initWithValue:0 xIndex:0]];
    [yVals addObject:[[ChartDataEntry alloc] initWithValue:-1 xIndex:1]];
    [yVals addObject:[[ChartDataEntry alloc] initWithValue:0.01170003414154053 xIndex:2]];
    [yVals addObject:[[ChartDataEntry alloc] initWithValue:0.04190003871917725 xIndex:3]];
    [yVals addObject:[[ChartDataEntry alloc] initWithValue:0.05540001392364502 xIndex:4]];

    LineChartDataSet *set1 = [[LineChartDataSet alloc] initWithYVals:yVals label:@"DataSet 1"];

    set1.lineWidth = 1.75;
    set1.circleRadius = 3.0;
    [set1 setColor:[UIColor orangeColor]]; 
    [set1 setCircleColor:UIColor.whiteColor];
    set1.highlightColor = UIColor.whiteColor;
    set1.drawValuesEnabled = NO;
    set1.drawCubicEnabled = YES;
    set1.cubicIntensity = 0.5;

    _lineChartView.data = [[LineChartData alloc] initWithXVals:xVals dataSet:set1];

Result:
snip20150922_3

@liuxuan30
Copy link
Member

I just saw a very flat line with your data, what did I miss
flat

@danielgindi
Copy link
Collaborator

It looks like a dashed line...

@liuxuan30
Copy link
Member

The dataSet is quite small:
[yVals addObject:[[ChartDataEntry alloc] initWithValue:0 xIndex:0]];
[yVals addObject:[[ChartDataEntry alloc] initWithValue:-1 xIndex:1]];
[yVals addObject:[[ChartDataEntry alloc] initWithValue:0.01170003414154053 xIndex:2]];
[yVals addObject:[[ChartDataEntry alloc] initWithValue:0.04190003871917725 xIndex:3]];
[yVals addObject:[[ChartDataEntry alloc] initWithValue:0.05540001392364502 xIndex:4]];
So I only see the flat line. Ignore the dashed line, it's limitLine from the ChartsDemo code.

BTW, #330 is also talking about missing data points, though it is for drawLinear. Will it be same issue?

@danielgindi
Copy link
Collaborator

@zxy198717 any new info?

@zxy198717
Copy link
Author

@danielgindi @liuxuan30 I created one test project(https://github.com/zxy198717/iOS-Chart-Test), maybe it can help you find the root cause.

@liuxuan30 liuxuan30 added the bug label Nov 14, 2015
@liuxuan30
Copy link
Member

OK But I guess no one is spare to look into it right now.. Mark as bug

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

I have the same problem here.

Here's the same graph with cubic lines disabled and enabled:

captura de tela 2015-11-18 as 03 15 52

captura de tela 2015-11-18 as 03 13 06

At first I thought this was just a matter of changing the padding of the chart or something like that, it's like the cubic rendering makes some bits of the line dip below the visible part of the graph, but I couldn't find anything that helped me solve this, and then I ran into this post.

@danielgindi
Copy link
Collaborator

danielgindi commented Nov 18, 2015 via email

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

That was fast, thanks. I'm new at this, I'll try to figure out how to do that then… but to avoid a lot of white space below the graph depending on the users' data I'll have to find the minimum value in their data set and always set that custom Y minimum a little bellow that, right? It'll do for now if I can get it to work, but it's not very elegant.

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

Ok, that solved the first problem, but now I have another:

captura de tela 2015-11-18 as 04 20 02

It looks like the data dip below zero sometimes, which doesn't make sense for my app… or maybe it seems like the data are more than zero with those bumps down there when they should actually be straight lines.

@danielgindi
Copy link
Collaborator

Well that's because it's a Cubic Bezier line, not a straight line. That's
how Beziers works...

Maybe someone with more expertise in charts with bezier lines could offer
some insight here.

On Wed, Nov 18, 2015 at 8:24 AM, danielbmarques [email protected]
wrote:

Ok, that solved the first problem, but now I have another:

[image: captura de tela 2015-11-18 as 04 20 02]
https://cloud.githubusercontent.com/assets/15813674/11234080/b4dba5b8-8dab-11e5-9619-6b5a12b68bc8.png

It looks like the data dips below zero sometimes, which doesn't make sense
for my app… or maybe it seems like the data is more than zero with those
bumps down there when they should actually be straight lines.


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

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

I also tried this library and the bezier lines look great, so it's certainly possible:

captura de tela 2015-11-18 as 04 34 14

I'd rather use your library for the features, though. :(

@danielgindi
Copy link
Collaborator

We'll look into it

@PhilJay ?

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

Thanks a lot!
Great work, by the way. :)

@PhilJay
Copy link
Collaborator

PhilJay commented Nov 18, 2015

Well this looks like zero values are simply rendered as normal lines?

@danielgindi
Copy link
Collaborator

Yes, like when the values reach the real minimum value (not custom min value) - we need to trim them to straight lines.
But then we have a problem with the line being part bezier part straight...
I'm assuming there's some kind of trick, maybe duplicating points to force the bezier to draw straight?

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

I think that's probably the case, duplicating points.
If you compare the two examples I posted you can see that in the last one the line is more curved at its extremes… like if it were coming from a straight line and going to a straight line, and we can see the curves in the chart prepare to do that. So it's not just that zero values are normal lines, the rest of the graph also adjusts to make up for that.
And that shouldn't happen just when points are close to the minimum… if you have a curved line between two points, the curve should never go above or below either of those two points, it doesn't matter what their values are.

@dbmrq
Copy link

dbmrq commented Nov 18, 2015

Look at this example from that other library:
image

The line between "sab" and "dom" doesn't go above nor below the values for "sab" and "dom", even though the huge bump at "sex" should make it do that. So some points must be duplicated to account for this, regardless of whether it's at the minimum or maximum value or neither.

@HannahCarney
Copy link

Anyone solve this issue? My chart is dipping below zero too, and it's so ugly. @danielbmarques did you end up using a better library?

@danielgindi
Copy link
Collaborator

We will solve it soon. We are working hard on other things.
You are most welcome to try to solve it and create a PR too!

On Tue, Nov 24, 2015 at 1:34 PM, Hannah Carney [email protected]
wrote:

Anyone solve this issue? My chart is dipping below zero too, and it's so
ugly. @danielbmarques https://github.com/danielbmarques did you end up
using a better library?


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

@dbmrq
Copy link

dbmrq commented Nov 25, 2015

@HannahCarney If all you're interested in is the line itself, I think the best option is this, but you won't even get labels for the axes, you have to set them up yourself. For now I just resorted to doing this:

simulator screen shot 23 de nov de 2015 20 19 46

@dbmrq
Copy link

dbmrq commented Nov 25, 2015

@danielgindi Apparently duplicating points isn't the best way to do this after all. I think the way to go is to use UIBezierPath and control points instead of CGPathCreateMutable. It seems pretty straightforward, but I won't have the time to figure out how to add it to the rest of the code for now.

You can check this out if you don't mind cheating.

@danielgindi danielgindi changed the title Cubic Line chart broken Cubic Line goes too much over the top or below bottom. Needs flattening. Feb 23, 2016
@mslazynski
Copy link

@danielbmarques IMHO UIBezierPath is not relevant, it works almost exactly like the CGPathCreateMutable. The problem is that there is no (at least i don't know any) spline interpolation method which takes into consideration the relevant constraints. I haven't studied the JBChartView approach, but the BEMSimpleLineGraph library mitigates the error by not using any interpolation, it simply draws bezier curves between points. It works for very simple data, but in most cases it creates ugly "bumpy" plots.

Can anyone confirm that JBChartView doesn't have the same problem? I will test in my free time, but AFAIK it should have exactly the same issues.

@dbmrq
Copy link

dbmrq commented Mar 10, 2016

@mslazynski Whether it's using CGPathCreateMutable or UIBezierPath, I think the main point is to use control points. I don't really know much about anything like this, though, so I may be completely off the mark. I barely know what interpolation is, for instance, haha… but from what I gathered I don't think JBChartView uses independent discrete segments, if that's what you mean. The link I posted before was broken, I think the relevant part is this.

Apple's iTunes Connect app has charts that don't have this problem, I wonder how they do it:
img_7208

@mslazynski
Copy link

@danielbmarques BEMSimpleLineGraph uses separate segments. JBChartView use some kind of interpolation for sure (it's enough to look at the code you've linked to), however I didn't have time to test whether their interpolation method mitigates the problem. If it is confirmed that JBCharView solved the problem, porting their code should be a 1h piece of work :) I'm sure that there exists the proper way of choosing control points -> I've tried some naive methods, however the resulting plot was always ugly :(

@dbmrq
Copy link

dbmrq commented Mar 10, 2016

@mslazynski A while ago, when I first mentioned JBChartView, I tried it with my code and it did fix the problem. I didn't test it really extensively, though; my charts are relatively simple.

@danielgindi
Copy link
Collaborator

Okay so I went through the code of the other libaries - and it seems like they do a lot of weird and unnecessary calculations. I've managed to deduce the core algorithm for control points, and create a CodePen:
http://codepen.io/danielgindi/pen/eZGxzr

The code contains both quad and cubic bezier methods, as I had to simplify and then build to cubic control points.
This seems sufficient, though this removes the option to control the intensity of the bezier.
So I guess what I'll do is introduce an enum for the way that the line chart will draw it's line (linear, stepped, bezier, trimmed bezier).

@PhilJay what do you think?

@PhilJay
Copy link
Collaborator

PhilJay commented Apr 3, 2016

Looks good. How about performance? Does this new way of drawing e.g. cubic improve performance as well? (it kind of looks like it does)

I don't think its too bad if you cannot control intensity anymore, but if we still want that feature, an enum or flag could be sufficient.

@danielgindi
Copy link
Collaborator

From my tests- it does. If I use the final cubic method- then I'm making the same amount of AddCurveTo calls but with less mathmatics.

I think that the cubicIntensity is a nice property to have, and some people might actually want to draw a real cubic, not a trimmed one :)

@dbmrq
Copy link

dbmrq commented Apr 5, 2016

@danielgindi Awesome, thank you!

@YangHang
Copy link

Awesome, thanks a lot!

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

No branches or pull requests

8 participants