|
1 d3.layout.histogram = function() { |
|
2 var frequency = true, |
|
3 valuer = Number, |
|
4 ranger = d3_layout_histogramRange, |
|
5 binner = d3_layout_histogramBinSturges; |
|
6 |
|
7 function histogram(data, i) { |
|
8 var bins = [], |
|
9 values = data.map(valuer, this), |
|
10 range = ranger.call(this, values, i), |
|
11 thresholds = binner.call(this, range, values, i), |
|
12 bin, |
|
13 i = -1, |
|
14 n = values.length, |
|
15 m = thresholds.length - 1, |
|
16 k = frequency ? 1 : 1 / n, |
|
17 x; |
|
18 |
|
19 // Initialize the bins. |
|
20 while (++i < m) { |
|
21 bin = bins[i] = []; |
|
22 bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); |
|
23 bin.y = 0; |
|
24 } |
|
25 |
|
26 // Fill the bins, ignoring values outside the range. |
|
27 i = -1; while(++i < n) { |
|
28 x = values[i]; |
|
29 if ((x >= range[0]) && (x <= range[1])) { |
|
30 bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; |
|
31 bin.y += k; |
|
32 bin.push(data[i]); |
|
33 } |
|
34 } |
|
35 |
|
36 return bins; |
|
37 } |
|
38 |
|
39 // Specifies how to extract a value from the associated data. The default |
|
40 // value function is `Number`, which is equivalent to the identity function. |
|
41 histogram.value = function(x) { |
|
42 if (!arguments.length) return valuer; |
|
43 valuer = x; |
|
44 return histogram; |
|
45 }; |
|
46 |
|
47 // Specifies the range of the histogram. Values outside the specified range |
|
48 // will be ignored. The argument `x` may be specified either as a two-element |
|
49 // array representing the minimum and maximum value of the range, or as a |
|
50 // function that returns the range given the array of values and the current |
|
51 // index `i`. The default range is the extent (minimum and maximum) of the |
|
52 // values. |
|
53 histogram.range = function(x) { |
|
54 if (!arguments.length) return ranger; |
|
55 ranger = d3.functor(x); |
|
56 return histogram; |
|
57 }; |
|
58 |
|
59 // Specifies how to bin values in the histogram. The argument `x` may be |
|
60 // specified as a number, in which case the range of values will be split |
|
61 // uniformly into the given number of bins. Or, `x` may be an array of |
|
62 // threshold values, defining the bins; the specified array must contain the |
|
63 // rightmost (upper) value, thus specifying n + 1 values for n bins. Or, `x` |
|
64 // may be a function which is evaluated, being passed the range, the array of |
|
65 // values, and the current index `i`, returning an array of thresholds. The |
|
66 // default bin function will divide the values into uniform bins using |
|
67 // Sturges' formula. |
|
68 histogram.bins = function(x) { |
|
69 if (!arguments.length) return binner; |
|
70 binner = typeof x === "number" |
|
71 ? function(range) { return d3_layout_histogramBinFixed(range, x); } |
|
72 : d3.functor(x); |
|
73 return histogram; |
|
74 }; |
|
75 |
|
76 // Specifies whether the histogram's `y` value is a count (frequency) or a |
|
77 // probability (density). The default value is true. |
|
78 histogram.frequency = function(x) { |
|
79 if (!arguments.length) return frequency; |
|
80 frequency = !!x; |
|
81 return histogram; |
|
82 }; |
|
83 |
|
84 return histogram; |
|
85 }; |
|
86 |
|
87 function d3_layout_histogramBinSturges(range, values) { |
|
88 return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); |
|
89 } |
|
90 |
|
91 function d3_layout_histogramBinFixed(range, n) { |
|
92 var x = -1, |
|
93 b = +range[0], |
|
94 m = (range[1] - b) / n, |
|
95 f = []; |
|
96 while (++x <= n) f[x] = m * x + b; |
|
97 return f; |
|
98 } |
|
99 |
|
100 function d3_layout_histogramRange(values) { |
|
101 return [d3.min(values), d3.max(values)]; |
|
102 } |