[76] | 1 | // data is two-dimensional array of x,y; we populate y0 |
---|
| 2 | d3.layout.stack = function() { |
---|
| 3 | var values = Object, |
---|
| 4 | order = d3_layout_stackOrders["default"], |
---|
| 5 | offset = d3_layout_stackOffsets["zero"], |
---|
| 6 | out = d3_layout_stackOut, |
---|
| 7 | x = d3_layout_stackX, |
---|
| 8 | y = d3_layout_stackY; |
---|
| 9 | |
---|
| 10 | function stack(data, index) { |
---|
| 11 | |
---|
| 12 | // Convert series to canonical two-dimensional representation. |
---|
| 13 | var series = data.map(function(d, i) { |
---|
| 14 | return values.call(stack, d, i); |
---|
| 15 | }); |
---|
| 16 | |
---|
| 17 | // Convert each series to canonical [[x,y]] representation. |
---|
| 18 | var points = series.map(function(d, i) { |
---|
| 19 | return d.map(function(v, i) { |
---|
| 20 | return [x.call(stack, v, i), y.call(stack, v, i)]; |
---|
| 21 | }); |
---|
| 22 | }); |
---|
| 23 | |
---|
| 24 | // Compute the order of series, and permute them. |
---|
| 25 | var orders = order.call(stack, points, index); |
---|
| 26 | series = d3.permute(series, orders); |
---|
| 27 | points = d3.permute(points, orders); |
---|
| 28 | |
---|
| 29 | // Compute the baseline⊠|
---|
| 30 | var offsets = offset.call(stack, points, index); |
---|
| 31 | |
---|
| 32 | // And propagate it to other series. |
---|
| 33 | var n = series.length, |
---|
| 34 | m = series[0].length, |
---|
| 35 | i, |
---|
| 36 | j, |
---|
| 37 | o; |
---|
| 38 | for (j = 0; j < m; ++j) { |
---|
| 39 | out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); |
---|
| 40 | for (i = 1; i < n; ++i) { |
---|
| 41 | out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); |
---|
| 42 | } |
---|
| 43 | } |
---|
| 44 | |
---|
| 45 | return data; |
---|
| 46 | } |
---|
| 47 | |
---|
| 48 | stack.values = function(x) { |
---|
| 49 | if (!arguments.length) return values; |
---|
| 50 | values = x; |
---|
| 51 | return stack; |
---|
| 52 | }; |
---|
| 53 | |
---|
| 54 | stack.order = function(x) { |
---|
| 55 | if (!arguments.length) return order; |
---|
| 56 | order = typeof x === "function" ? x : d3_layout_stackOrders[x]; |
---|
| 57 | return stack; |
---|
| 58 | }; |
---|
| 59 | |
---|
| 60 | stack.offset = function(x) { |
---|
| 61 | if (!arguments.length) return offset; |
---|
| 62 | offset = typeof x === "function" ? x : d3_layout_stackOffsets[x]; |
---|
| 63 | return stack; |
---|
| 64 | }; |
---|
| 65 | |
---|
| 66 | stack.x = function(z) { |
---|
| 67 | if (!arguments.length) return x; |
---|
| 68 | x = z; |
---|
| 69 | return stack; |
---|
| 70 | }; |
---|
| 71 | |
---|
| 72 | stack.y = function(z) { |
---|
| 73 | if (!arguments.length) return y; |
---|
| 74 | y = z; |
---|
| 75 | return stack; |
---|
| 76 | }; |
---|
| 77 | |
---|
| 78 | stack.out = function(z) { |
---|
| 79 | if (!arguments.length) return out; |
---|
| 80 | out = z; |
---|
| 81 | return stack; |
---|
| 82 | }; |
---|
| 83 | |
---|
| 84 | return stack; |
---|
| 85 | } |
---|
| 86 | |
---|
| 87 | function d3_layout_stackX(d) { |
---|
| 88 | return d.x; |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | function d3_layout_stackY(d) { |
---|
| 92 | return d.y; |
---|
| 93 | } |
---|
| 94 | |
---|
| 95 | function d3_layout_stackOut(d, y0, y) { |
---|
| 96 | d.y0 = y0; |
---|
| 97 | d.y = y; |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | var d3_layout_stackOrders = { |
---|
| 101 | |
---|
| 102 | "inside-out": function(data) { |
---|
| 103 | var n = data.length, |
---|
| 104 | i, |
---|
| 105 | j, |
---|
| 106 | max = data.map(d3_layout_stackMaxIndex), |
---|
| 107 | sums = data.map(d3_layout_stackReduceSum), |
---|
| 108 | index = d3.range(n).sort(function(a, b) { return max[a] - max[b]; }), |
---|
| 109 | top = 0, |
---|
| 110 | bottom = 0, |
---|
| 111 | tops = [], |
---|
| 112 | bottoms = []; |
---|
| 113 | for (i = 0; i < n; ++i) { |
---|
| 114 | j = index[i]; |
---|
| 115 | if (top < bottom) { |
---|
| 116 | top += sums[j]; |
---|
| 117 | tops.push(j); |
---|
| 118 | } else { |
---|
| 119 | bottom += sums[j]; |
---|
| 120 | bottoms.push(j); |
---|
| 121 | } |
---|
| 122 | } |
---|
| 123 | return bottoms.reverse().concat(tops); |
---|
| 124 | }, |
---|
| 125 | |
---|
| 126 | "reverse": function(data) { |
---|
| 127 | return d3.range(data.length).reverse(); |
---|
| 128 | }, |
---|
| 129 | |
---|
| 130 | "default": function(data) { |
---|
| 131 | return d3.range(data.length); |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | }; |
---|
| 135 | |
---|
| 136 | var d3_layout_stackOffsets = { |
---|
| 137 | |
---|
| 138 | "silhouette": function(data) { |
---|
| 139 | var n = data.length, |
---|
| 140 | m = data[0].length, |
---|
| 141 | sums = [], |
---|
| 142 | max = 0, |
---|
| 143 | i, |
---|
| 144 | j, |
---|
| 145 | o, |
---|
| 146 | y0 = []; |
---|
| 147 | for (j = 0; j < m; ++j) { |
---|
| 148 | for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; |
---|
| 149 | if (o > max) max = o; |
---|
| 150 | sums.push(o); |
---|
| 151 | } |
---|
| 152 | for (j = 0; j < m; ++j) { |
---|
| 153 | y0[j] = (max - sums[j]) / 2; |
---|
| 154 | } |
---|
| 155 | return y0; |
---|
| 156 | }, |
---|
| 157 | |
---|
| 158 | "wiggle": function(data) { |
---|
| 159 | var n = data.length, |
---|
| 160 | x = data[0], |
---|
| 161 | m = x.length, |
---|
| 162 | max = 0, |
---|
| 163 | i, |
---|
| 164 | j, |
---|
| 165 | k, |
---|
| 166 | s1, |
---|
| 167 | s2, |
---|
| 168 | s3, |
---|
| 169 | dx, |
---|
| 170 | o, |
---|
| 171 | o0, |
---|
| 172 | y0 = []; |
---|
| 173 | y0[0] = o = o0 = 0; |
---|
| 174 | for (j = 1; j < m; ++j) { |
---|
| 175 | for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; |
---|
| 176 | for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { |
---|
| 177 | for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { |
---|
| 178 | s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; |
---|
| 179 | } |
---|
| 180 | s2 += s3 * data[i][j][1]; |
---|
| 181 | } |
---|
| 182 | y0[j] = o -= s1 ? s2 / s1 * dx : 0; |
---|
| 183 | if (o < o0) o0 = o; |
---|
| 184 | } |
---|
| 185 | for (j = 0; j < m; ++j) y0[j] -= o0; |
---|
| 186 | return y0; |
---|
| 187 | }, |
---|
| 188 | |
---|
| 189 | "expand": function(data) { |
---|
| 190 | var n = data.length, |
---|
| 191 | m = data[0].length, |
---|
| 192 | k = 1 / n, |
---|
| 193 | i, |
---|
| 194 | j, |
---|
| 195 | o, |
---|
| 196 | y0 = []; |
---|
| 197 | for (j = 0; j < m; ++j) { |
---|
| 198 | for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; |
---|
| 199 | if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; |
---|
| 200 | else for (i = 0; i < n; i++) data[i][j][1] = k; |
---|
| 201 | } |
---|
| 202 | for (j = 0; j < m; ++j) y0[j] = 0; |
---|
| 203 | return y0; |
---|
| 204 | }, |
---|
| 205 | |
---|
| 206 | "zero": function(data) { |
---|
| 207 | var j = -1, |
---|
| 208 | m = data[0].length, |
---|
| 209 | y0 = []; |
---|
| 210 | while (++j < m) y0[j] = 0; |
---|
| 211 | return y0; |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | }; |
---|
| 215 | |
---|
| 216 | function d3_layout_stackMaxIndex(array) { |
---|
| 217 | var i = 1, |
---|
| 218 | j = 0, |
---|
| 219 | v = array[0][1], |
---|
| 220 | k, |
---|
| 221 | n = array.length; |
---|
| 222 | for (; i < n; ++i) { |
---|
| 223 | if ((k = array[i][1]) > v) { |
---|
| 224 | j = i; |
---|
| 225 | v = k; |
---|
| 226 | } |
---|
| 227 | } |
---|
| 228 | return j; |
---|
| 229 | } |
---|
| 230 | |
---|
| 231 | function d3_layout_stackReduceSum(d) { |
---|
| 232 | return d.reduce(d3_layout_stackSum, 0); |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | function d3_layout_stackSum(p, d) { |
---|
| 236 | return p + d[1]; |
---|
| 237 | } |
---|