source: Dev/trunk/d3/src/layout/stack.js @ 76

Last change on this file since 76 was 76, checked in by fpvanagthoven, 14 years ago

d3

File size: 5.1 KB
Line 
1// data is two-dimensional array of x,y; we populate y0
2d3.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
87function d3_layout_stackX(d) {
88  return d.x;
89}
90
91function d3_layout_stackY(d) {
92  return d.y;
93}
94
95function d3_layout_stackOut(d, y0, y) {
96  d.y0 = y0;
97  d.y = y;
98}
99
100var 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
136var 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
216function 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
231function d3_layout_stackReduceSum(d) {
232  return d.reduce(d3_layout_stackSum, 0);
233}
234
235function d3_layout_stackSum(p, d) {
236  return p + d[1];
237}
Note: See TracBrowser for help on using the repository browser.