Merge branch 'master' into per_series
[dygraphs.git] / tests / linear-regression-addseries.html
1 <html>
2 <head>
3 <title>Linear Regression</title>
4 <!--[if IE]>
5 <script type="text/javascript" src="excanvas.js"></script>
6 <![endif]-->
7 <script type="text/javascript" src="../strftime/strftime-min.js"></script>
8 <script type="text/javascript" src="../rgbcolor/rgbcolor.js"></script>
9 <script type="text/javascript" src="../dygraph-canvas.js"></script>
10 <script type="text/javascript" src="../dygraph.js"></script>
11 <style type="text/css">
12 body { max-width: 640 px; }
13 </style>
14 </head>
15 <body>
16 <h2>Linear Regression Demo</h2>
17 <p>Click the buttons to generate linear regressions over either data
18 series. If you zoom in and click the regression button, the regression will
19 only be run over visible points. Zoom back out to see what the local
20 regression looks like over the full data.</p>
21
22 <div id="demodiv" style="width: 480px; height: 320px;"></div>
23
24 <script type="text/javascript">
25 var data = [];
26 for (var i = 0; i < 120; i++) {
27 data.push([i,
28 i / 5.0 + 10.0 * Math.sin(i / 3.0),
29 30.0 - i / 5.0 - 10.0 * Math.sin(i / 3.0 + 1.0)]);
30 }
31 var labels = ['X', 'Y1', 'Y2'];
32 var orig_colors = [];
33
34 g = new Dygraph(
35 document.getElementById("demodiv"),
36 data,
37 {
38 labels: labels,
39 drawPoints: true,
40 drawCallback: function(g, is_initial) {
41 if (!is_initial) return;
42 var c = g.getColors();
43 for (var i = 0; i < c.length; i++) orig_colors.push(c[i]);
44 }
45 }
46 );
47
48 // coefficients of regression for each series.
49 // if coeffs = [ null, [1, 2], null ] then we draw a regression for series 1
50 // only. The regression line is y = 1 + 2 * x.
51 var coeffs = [ null, null, null ];
52 function regression(series) {
53 // Only run the regression over visible points.
54 var range = g.xAxisRange();
55
56 var sum_xy = 0.0, sum_x = 0.0, sum_y = 0.0, sum_x2 = 0.0, num = 0;
57 for (var i = 0; i < data.length; i++) {
58 var x = data[i][0];
59 if (x < range[0] || x > range[1]) continue;
60
61 var y = data[i][series];
62 if (y == null) continue;
63
64 num++;
65 sum_x += x;
66 sum_y += y;
67 sum_xy += x * y;
68 sum_x2 += x * x;
69 }
70
71 var a = (sum_xy - sum_x * sum_y / num) / (sum_x2 - sum_x * sum_x / num);
72 var b = (sum_y - a * sum_x) / num;
73
74 coeffs[series] = [b, a];
75 if (console) {
76 console.log("coeffs(" + series + "): [" + b + ", " + a + "]");
77 }
78
79 updateChart();
80 }
81
82 function updateChart() {
83 // Generate a new data set with the regression lines.
84 var new_labels = [];
85 var new_colors = [];
86 for (var i = 0; i < labels.length; i++) {
87 new_labels.push(labels[i]);
88 if (i) new_colors.push(orig_colors[i - 1]);
89 if (coeffs[i]) {
90 // Darken the series by 50% to generate its regression.
91 new_labels.push(labels[i] + " Regression");
92 var c = new RGBColor(orig_colors[i - 1]);
93 c.r = Math.floor(255 - 0.5 * (255 - c.r));
94 c.g = Math.floor(255 - 0.5 * (255 - c.g));
95 c.b = Math.floor(255 - 0.5 * (255 - c.b));
96 new_colors.push(c.toHex());
97 }
98 }
99
100 var new_data = [];
101 for (var i = 0; i < data.length; i++) {
102 new_data.push([]);
103 for (var j = 0; j < data[i].length; j++) {
104 new_data[i].push(data[i][j]);
105 if (coeffs[j]) {
106 new_data[i].push(coeffs[j][0] + coeffs[j][1] * data[i][0]);
107 }
108 }
109 }
110
111 // TODO(danvk): set colors intelligently.
112
113 g.updateOptions({
114 file: new_data,
115 labels: new_labels,
116 colors: new_colors
117 });
118 }
119
120 function clearLines() {
121 for (var i = 0; i < coeffs.length; i++) coeffs[i] = null;
122 updateChart();
123 }
124
125 // function drawLines(ctx, area, layout) {
126 // if (typeof(g) == 'undefined') return; // won't be set on the initial draw.
127
128 // var range = g.xAxisRange();
129 // for (var i = 0; i < coeffs.length; i++) {
130 // if (!coeffs[i]) continue;
131 // var a = coeffs[i][1];
132 // var b = coeffs[i][0];
133
134 // var x1 = range[0];
135 // var y1 = a * x1 + b;
136 // var x2 = range[1];
137 // var y2 = a * x2 + b;
138
139 // var p1 = g.toDomCoords(x1, y1);
140 // var p2 = g.toDomCoords(x2, y2);
141
142 // var color = g.getColors()[i - 1];
143 // ctx.save();
144 // ctx.strokeStyle = color;
145 // ctx.lineWidth = 1.0;
146 // ctx.beginPath();
147 // ctx.moveTo(p1[0], p1[1]);
148 // ctx.lineTo(p2[0], p2[1]);
149 // ctx.closePath();
150 // ctx.stroke();
151 // ctx.restore();
152 // }
153 // }
154
155 </script>
156
157 <div style="position: absolute; left: 500px; top: 150px;">
158 <input type=button style="color: green;" value="Regression (Y1)" onClick="regression(1)" />
159 <br/><br/>
160 <input type=button style="color: blue;" value="Regression (Y2)" onClick="regression(2)" />
161 <br/><br/>
162 <input type=button value="Clear Lines" onClick="clearLines()" />
163 </div>
164 </body>
165 </html>