1 | Here's what it looks like:
|
2 |
|
3 | ![screen recording](smooth-plotter-p1-recording.gif)
|
4 |
|
5 | This uses cubic splines (aka bezier curves) to smooth out the lines
|
6 | between points. To draw a bezier curve between two points, you must also
|
7 | specify two control points which specify how it bends:
|
8 |
|
9 | ![bezier_curve](smooth-plotter-p2-bezier.png)
|
10 |
|
11 | The problem is to determine those control points.
|
12 |
|
13 | When you connect a bunch of bezier curves, each original point in the
|
14 | series has both a left control point and a right control point. To avoid
|
15 | forming a kink in the chart, the left control point, the series point
|
16 | and the right control point all need to fall on a line.
|
17 |
|
18 | The algorithm I wound up using follows the HighCharts implementation of
|
19 | this. Here's how it works...
|
20 |
|
21 | The setup is that you have a point whose left & right controls you're
|
22 | trying to determine. You also know the previous and next point:
|
23 |
|
24 | ![setup](smooth-plotter-p3-setup.png)
|
25 |
|
26 | Start by placing the control points α of the way along each line
|
27 | segment. This is the only parameter we'll need to control the amount of
|
28 | smoothing:
|
29 |
|
30 | ![controls on line](smooth-plotter-p4-on-line.png)
|
31 |
|
32 | But now we've broken the rule that the original point has to be on the
|
33 | line between the control points! To fix that, we shift the control
|
34 | points up by ∆y, which can be determined with some simple algebra:
|
35 |
|
36 | ![controls shifted](smooth-plotter-p5-shifted.png)
|
37 |
|
38 | But this introduces a new problem: the right control point is above the
|
39 | data points, and so it will create an impression of a false maximum to
|
40 | the right of the data point. To fix this, we cap the y-value of the
|
41 | control points:
|
42 |
|
43 | ![controls capped](smooth-plotter-p6-capped.png)
|
44 |
|
45 | But now we've re-broken that rule about being on a line. So we have to
|
46 | do the mirror-image adjustment to the left control point:
|
47 |
|
48 | ![controls capped and adjusted](smooth-plotter-p7-adjusted.png)
|
49 |
|
50 | and now we have our control points!
|
51 |
|
52 | Hopefully the algorithm makes good sense now. I implemented this as a
|
53 | separate plotter in `/extras` for now, but it might make more sense to
|
54 | move this into core dygraphs. That would make it easier to have the
|
55 | smooth plots play nicely with other options like
|
56 | `connectSeparatedPoints`, `strokePattern` and `drawPoints`.
|