-
Notifications
You must be signed in to change notification settings - Fork 312
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
d3.curveMonotoneX may be unsuitable for stacked areas. #81
Comments
I’ve posted a reproduction that gives a better sense of what’s going on: The problem is that the top line crosses over the bottom line. My guess is that this isn’t fixable, in the sense that when you use a monotone curve on an area, the curves are computed independently and so there’s no way to guarantee that the top line doesn’t cross over the bottom line. And even if you fixed it for an area’s top and bottom line, you’d still have the problem that the top line of the lower series (in orange) would presumably be drawn above the bottom line of the higher series (in blue). |
Another way of thinking about this is that d3.curveMonotoneX preserves monotonicity in y (given monotonicity in x). So if you take the problematic series and shift it to the baseline (y0 = 0, i.e., not stacked), it works fine because the top line y1 never crosses y = 0: But preserving y1 ≥ y0 does not happen if you shift the area to make it stacked, because now you must preserve monotonicity in y1 - y0 (the difference between the top and bottom lines), not y. I suppose what you might want here is a new curve type that preserves this other sort of monotonicity. It could use the same algorithm in d3.curveMonotoneX, except the input points would be shifted such that y0 = 0 when computing the tangents, and then after the resulting curves would be shifted back to the original y0 and y1. This probably isn’t too hard, but the downside is that there’d be no way to use such a curve type with d3.line to draw the top and bottom line independently. Other solutions would be to use d3.curveBasis instead of d3.curveMonotoneX, which produces a smooth curve and is guaranteed to not cause crossover. However, this has the effect of smoothing the data, which may be undesirable. You could also explicitly smooth the data yourself before constructing the area shape. |
What are you referring to as the “first” solution? The new monotone curve type? That wouldn’t change your code much; you’d just replace d3.curveMonotoneX with d3.curveMonotoneDeltaX or some such. (The shifting approach I mentioned would happen inside the curve, when the tangents are computed.) I have no immediate plans to implement such a feature, but I’d review a pull request if someone wants to contribute it. It works on the other side by coincidence: the point at which the top and bottom lines meet is an inflection point. That’s not true on the right side: when the lines meet, they are both sloping down. If you want an immediate solution, your choices are to use a linear or basis curve, to implement a new curve type, or to smooth the input data before computing the curve. |
Creating stacked area chart with
.curve(d3.curveLinear)
produced correct interpolation:Creating the same chart with
.curve(d3.curveMonotoneX)
produced strange convexity for the highest area (between 3 and 2 points (X) from the end):Last 4 items from the series for the LOWEST area are:
[0, 0] [0, 186] [0, 2294] [0, 2812.11]
Last 4 items from the series for the HIGHEST area are:
[0, 0] [186, 186] [2294, 2294] [2812.11, 21312.11]
The text was updated successfully, but these errors were encountered: