-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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
Line goes below zero #424
Comments
noticed this also. using bezier curves with points that go from anything > 0 to 0 then up again, with a bezierCurveTension > 0 (i think i'm on default 0.4) the line goes under the 0 on the X axis |
That's a bit of a tricky one. I've been working a bit on bezier curving this weekend for another issue regarding sparse datasets, mentioned above (#435). To provide a smooth bezier curve between a set of pre-described points, by its very nature the line may have to go above / below some of the points, especially when you have large then small values next to each other. Try playing around with the demo here and you'll see what I mean: http://www.particleincell.com/blog/2012/bezier-splines/ All ears if someone can come up with some logic / maths around how Chart.js should provide bezier curving between points. Just capping the curve tension at zero isn't really a solution because as the demo above shows the bottom of the chart may not be zero. We might also be dealing with numbers at the top of the chart, so there's also that to consider. Comparing with previous values doesn't work either because in cases like this: http://jsbin.com/licunala/3/edit we'd have no bezier curve at all - just a straight line. I'm not sure if there is actually a solution to this other than reducing the bezier curve tension. |
Hi nnnick, First of all: thanks for the library, great work! I have the same problem. I believe a lot of graphs don't need to go below zero and then it would be perfectly fine to just flatten the line at zero instead of going under zero. For example the following chart now looks weird because nobody can work negative hours. I think having an option in the chart (the global options) to flatten out zero's or to have a value under which no line should be drawn would fix this for a lot of users. |
Interesting solution, it might be worthwhile setting the x to the same as the point itself as well, not sure. I'd be really interested to see how other charting libraries deal with this particular issue. Anyone got any insight on that? We'd certainly need to repeat that same capping logic for the top of the scale, as the same effect could occur. |
I've been using custom Y scales for my particular project so I just have it automatically building in a buffer, ie: If the highest plotted value is 100 and the steps are 25 then the top value shown on the Y axis is 125. It would definitely work to bound the top just like the bottom, just not something that's an issue for what I'm doing right now. I actually spent a couple of days looking into Bezier curves and various formulas for them and approaches to drawing them before I tackled this issue. This tutorial: http://pomax.github.io/bezierinfo/ -- specifically section 13 on Bounding Boxes -- is what helped me narrow in on a solution. My algebra skills weren't necessarily up to re-coding the control points formula to keep the bounding boxes within the proper bounds, but it did prompt me to come up with my hacky little workaround. |
Oh, and btw, thanks for all of your work on this. Fighting my way through your code is definitely teaching me a few things about javascript! |
Hi Nick, From the screenshot it looks like the fix of wunderdojo is good. Will this be integrated in the regular version? Kind regards. |
As for other libraries, morris.js seems to deal OK with this issue. From the looks of it, it does same thing as suggested by wunderdojo: cap the control points to some "bottom" value: https://github.com/morrisjs/morris.js/blob/master/lib/morris.line.coffee#L272 |
👍 I'm also seeing this. |
This was resolved in 179d80a, forgot to close this. @jivinivan which version are you using? |
@nnnick thanks for the response! Was relying on https://github.com/lgsilver/angles for the chart.js version. I've added to our own list of dependencies with the latest version and also opened an issue for them to update. gonewandering/angles#57 |
I'm leaving this bit here as this is where I landed when searching how to limit the curve from going above the value when sequential values are the same. if (this.options.bezierCurve){
helpers.each(pointsWithValues, function(point, index){
var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0;
// My Changes
var previousPointObj = previousPoint(point, pointsWithValues, index);
var nextPointObj = nextPoint(point, pointsWithValues, index)
point.controlPoints = helpers.splineCurve(
previousPointObj,
point,
nextPointObj,
tension
);
// Prevent curve from going over the value and "flatten" the bezier handles
if ( point.value == nextPointObj.value ) {
point.controlPoints.outer.y = nextPointObj.y;
point.controlPoints.inner.y = nextPointObj.y;
}
if ( point.value == previousPointObj.value ) {
point.controlPoints.outer.y = previousPointObj.y;
point.controlPoints.inner.y = previousPointObj.y;
}
// end My Changes
// Prevent the bezier going outside of the bounds of the graph
// Cap outer bezier handles to the upper/lower scale bounds
if (point.controlPoints.outer.y > this.scale.endPoint){
point.controlPoints.outer.y = this.scale.endPoint;
}
else if (point.controlPoints.outer.y < this.scale.startPoint){
point.controlPoints.outer.y = this.scale.startPoint;
}
// Cap inner bezier handles to the upper/lower scale bounds
if (point.controlPoints.inner.y > this.scale.endPoint){
point.controlPoints.inner.y = this.scale.endPoint;
}
else if (point.controlPoints.inner.y < this.scale.startPoint){
point.controlPoints.inner.y = this.scale.startPoint;
}
},this);
} |
Still have the same issue on the latest version, how to fix it? |
Setting tension: 0 took much of the aesthetic out so I edited the non-minified version of Chart.js v2.9.4 Find at at line 2498: Basically checks start and end points. If they are on the same y height, just draw a straight line. |
You should use |
Thanks so much for that. I didnt see that anywhere on my hunt for a solution. For anyone else, this was the setting that achieved the same result as my hack: |
who will be use library react-native-gifted-charts and have same problem use in your LineChart like this: |
See screenshot:
http://prntscr.com/3zmwat
To solve it I did change in my app to control tension, but is not good solution. I think something is wrong with spline realization.
point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,dataset.points[index+1],
//if coordinates are the same - tension is zero
dataset.points[index-1].value == dataset.points[index].value ? 0 :
//and reduce tension
dataset.points[index-1].value == 0 ? this.options.bezierCurveTension : this.options.bezierCurveTension * dataset.points[index+1].value / dataset.points[index-1].value);
The text was updated successfully, but these errors were encountered: