The following post is a portion of the D3 Tips and Tricks document which it free to download. To use this post in context, consider it with the others in the blog or just download the pdf and / or the examples from the
downloads page:-)
--------------------------------------------------------
When you draw a line graph, what you're doing is taking two (or more) sets of coordinates and connecting them with a line (or lines). I know that sounds simplistic, but bear with me. When you connect these points, you're telling the viewer of the graph that in between the individual points, you expect the value to vary in keeping with the points that the line passes through. So in a way, you're trying to interpret the change in values that are not shown.
Now this is not strictly true for all graph types, but it does hold for a lot of line graphs.
So... when connecting these known coordinated together, you want to make the best estimate of how the values would be represented. In this respect, sometimes a straight line between points is not the best representation.
For instance. Earlier, when demonstrating the extent function for graphing we showed a graph of the varying values with the y axis showing a narrow range.
The resulting variation of the graph shows a fair amount of extremes and you could be forgiven for thinking that if this represented a smoothly flowing analog system of some kind then some of those sharp peaks and troughs would not be a true representation of how the system or figures varied.
So how should it look? Ahh... The $64,000 question. I don't know :-). You will have a better idea since you are the person who will know your data best. However, what I do know is that D3 has some tricks up its sleeve to help.
We can easily change what we see above into;
How about that? And the massive amount of code required to carry out what must be a ridiculously difficult set of calculations?
.interpolate("basis")
Now, that is slightly unfair because that's the code that YOU need to put in your script, but Mike Bostock probably had to do the mental equivalent of walking across hot coals to get it to work so nicely.
So where does this neat piece of code go? Here;
var valueline = d3.svg.line()
.interpolate("basis") // <=== THERE IT IS!
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
So is that it? Nooooo........ There's more! This
is one form of interpolation effect that can be applied to your data,
but there is a range and depending on your data you can select the
one that is appropriate.
Here's the list of available options and for more
about them head on over to the
D3 wiki and look for 'line.interpolate'.
linear – Normal line (jagged).
step-before – a stepping graph alternating
between vertical and horizontal segments.
step-after - a stepping graph alternating
between horizontal and vertical segments.
basis - a B-spline, with control point
duplication on the ends (that's the one above).
basis-open - an open B-spline; may not
intersect the start or end.
basis-closed - a closed B-spline, with the
start and the end closed in a loop.
bundle - equivalent to basis, except a
separate tension parameter is used to straighten the spline. This
could be really cool with varying tension.
cardinal - a Cardinal spline, with control
point duplication on the ends. It looks slightly more 'jagged' than
basis.
cardinal-open - an open Cardinal spline; may
not intersect the start or end, but will intersect other control
points. So kind of shorter than 'cardinal'.
cardinal-closed - a closed Cardinal spline,
looped back on itself.
monotone - cubic interpolation that makes the
graph only slightly smoother.
Because in the course of writing this I took an
opportunity to play with each of them, I was pleasantly surprised to
see some of the effects and it seems like a shame to deprive the
reader of the same joy :-). So at the risk of deforesting the planet
(so I hope you are reading this in electronic format) here is each of
the above interpolation types applied to the same data.
This is also an opportunity to add some reader feedback awesomeness. Many thanks to 'enjalot' for the great suggestion (in the comments below) to plot the points of the data as separate circles on the graphs. Since the process of interpolation has the effect of 'interpreting' the trends of the data to the extent that in some cases, the lines don't intersect the actual data much at all.
Each of the following shows the smoothing curve and the data that is used to plot the graph.
|
Linear |
|
step-before |
|
step-after |
|
basis |
|
basis-open |
|
basis-closed |
|
bundle |
|
cardinal |
|
cardinal-open |
|
cardinal-closed |
|
monotone |
Thank you - exactly what I was looking for explained clearly and succinctly
ReplyDeleteGreat to hear. I think that everyone has a different way that they prefer to learn information, and when you find a good 'fit' it just makes it easier :-) Good luck with D3.
DeleteHey, this is great!
ReplyDeleteIt would be really helpful if you also plotted the points of the data as circles so that it was readily apparent that some of these interpolations do not accurately represent the data.
thanks again!
Wow! That is such a great idea! I will do it! Cheers
DeleteCool! Done. I figured you wouldn't mind me giving you credit by name (enjalot) in the text. If you'd rather not, just let me know. I've also updated the book. (https://leanpub.com/D3-Tips-and-Tricks). Many thanks. Great suggestion. I don't think I've seen this illustrated this way before.
DeleteIs it also possible to combine the methods?
ReplyDeleteAhh... Interesting question.
DeleteYes it is.
All you need to do is add in an additional block like the 'var valueline = blah bal blah...' but name it something different (like valueline2) and then add another block that adds the valueline2 path. That way you have two different paths and you can change the interpolations on either to suit.
Thanks for the question
Thank you !! :) very very thank you.
ReplyDeletethank you .. this is exact what i need .. :)
ReplyDeleteNice explanation, but your step-before and step-after examples are inversed.
ReplyDeleteThanks. But I don't quite get what you mean. The captions on the graphs above are correct and they appear to be in the same order as the description. I just ran a quick test to make sure that the steps actually do go in the direction that I thought they did so I'm a bit flummoxed. Could you describe the problem in a slightly different way? Thanks for the feedback.
DeleteHow did you managed to get circles aligned with curved line?
ReplyDeleteI only have them aligned for those interpolation types that have the lives running directly through the data points. So I'm afraid that it just happens that way depending on the interpolation type.
DeleteThanks for explanation.
ReplyDeleteCan I adjust line chart by holding the curve.
Not for the example as shown here. What you would be referring to would be a level of interactivness that would be pretty advanced (I haven't tried it before sorry)
DeleteThanks! `interpolate: 'monotone'` is awesome!
ReplyDeleteHello, i would like to ask that how can i find local max and local min values and also if there is a plateau ? I have a graph to measure tension according to values. I have to check for bumps if exist ? Thank you for your interest.
ReplyDeleteGood question. There will obviously be a bit of work involved here. I assume that we are looking for a way to find areas where the change in gradient means the line that is tangent to the curve changes relative to points before and after it. I have never played with this before, but the following pages may be of use; http://www.thesoftwaresimpleton.com/blog/2016/01/26/tangent/, http://www.d3geometry.com/functions?uid=8888, https://bl.ocks.org/andresin87/4c5a34136c9a543d68de
Delete