d3_rails 2.8.0 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.DS_Store +0 -0
  2. data/README.md +27 -5
  3. data/lib/d3_rails/version.rb +1 -1
  4. data/vendor/.DS_Store +0 -0
  5. data/vendor/assets/.DS_Store +0 -0
  6. data/vendor/assets/javascripts/.DS_Store +0 -0
  7. data/vendor/assets/javascripts/d3.v2.js +99 -80
  8. data/vendor/assets/javascripts/morris.js +1 -0
  9. data/vendor/assets/javascripts/morris/.DS_Store +0 -0
  10. data/vendor/assets/javascripts/morris/Makefile +10 -0
  11. data/vendor/assets/javascripts/morris/README.md +87 -0
  12. data/vendor/assets/javascripts/morris/examples/_template.html +18 -0
  13. data/vendor/assets/javascripts/morris/examples/days.html +36 -0
  14. data/vendor/assets/javascripts/morris/examples/decimal.html +31 -0
  15. data/vendor/assets/javascripts/morris/examples/lib/example.css +13 -0
  16. data/vendor/assets/javascripts/morris/examples/lib/example.js +4 -0
  17. data/vendor/assets/javascripts/morris/examples/lib/prettify.css +1 -0
  18. data/vendor/assets/javascripts/morris/examples/lib/prettify.js +28 -0
  19. data/vendor/assets/javascripts/morris/examples/months-no-smooth.html +37 -0
  20. data/vendor/assets/javascripts/morris/examples/negative.html +35 -0
  21. data/vendor/assets/javascripts/morris/examples/non-date.html +36 -0
  22. data/vendor/assets/javascripts/morris/examples/quarters.html +53 -0
  23. data/vendor/assets/javascripts/morris/examples/timestamps.html +37 -0
  24. data/vendor/assets/javascripts/morris/examples/weeks.html +52 -0
  25. data/vendor/assets/javascripts/morris/morris.coffee +444 -0
  26. data/vendor/assets/javascripts/morris/morris.js +493 -0
  27. data/vendor/assets/javascripts/morris/morris.min.js +1 -0
  28. data/vendor/assets/javascripts/tesseract.js +1 -0
  29. data/vendor/assets/javascripts/tesseract/.gitignore +2 -0
  30. data/vendor/assets/javascripts/tesseract/LICENSE +12 -0
  31. data/vendor/assets/javascripts/tesseract/Makefile +48 -0
  32. data/vendor/assets/javascripts/tesseract/README.md +11 -0
  33. data/vendor/assets/javascripts/tesseract/index.js +1 -0
  34. data/vendor/assets/javascripts/tesseract/lib/dart/AUTHORS +9 -0
  35. data/vendor/assets/javascripts/tesseract/lib/dart/LICENSE +25 -0
  36. data/vendor/assets/javascripts/tesseract/lib/dart/dual_pivot_quicksort.dart +342 -0
  37. data/vendor/assets/javascripts/tesseract/package.json +11 -0
  38. data/vendor/assets/javascripts/tesseract/src/array.js +32 -0
  39. data/vendor/assets/javascripts/tesseract/src/bisect.js +44 -0
  40. data/vendor/assets/javascripts/tesseract/src/filter.js +19 -0
  41. data/vendor/assets/javascripts/tesseract/src/heap.js +44 -0
  42. data/vendor/assets/javascripts/tesseract/src/heapselect.js +36 -0
  43. data/vendor/assets/javascripts/tesseract/src/identity.js +3 -0
  44. data/vendor/assets/javascripts/tesseract/src/insertionsort.js +18 -0
  45. data/vendor/assets/javascripts/tesseract/src/null.js +3 -0
  46. data/vendor/assets/javascripts/tesseract/src/package.js +14 -0
  47. data/vendor/assets/javascripts/tesseract/src/permute.js +8 -0
  48. data/vendor/assets/javascripts/tesseract/src/quicksort.js +282 -0
  49. data/vendor/assets/javascripts/tesseract/src/reduce.js +19 -0
  50. data/vendor/assets/javascripts/tesseract/src/tesseract.js +663 -0
  51. data/vendor/assets/javascripts/tesseract/src/version.js +1 -0
  52. data/vendor/assets/javascripts/tesseract/src/zero.js +3 -0
  53. data/vendor/assets/javascripts/tesseract/tesseract.js +1177 -0
  54. data/vendor/assets/javascripts/tesseract/tesseract.min.js +1 -0
  55. data/vendor/assets/javascripts/tesseract/test/benchmark.js +177 -0
  56. data/vendor/assets/javascripts/tesseract/test/bisect-test.js +206 -0
  57. data/vendor/assets/javascripts/tesseract/test/heap-test.js +44 -0
  58. data/vendor/assets/javascripts/tesseract/test/permute-test.js +51 -0
  59. data/vendor/assets/javascripts/tesseract/test/select-test.js +63 -0
  60. data/vendor/assets/javascripts/tesseract/test/sort-test.js +83 -0
  61. data/vendor/assets/javascripts/tesseract/test/tesseract-test.js +655 -0
  62. data/vendor/assets/javascripts/tesseract/test/version-test.js +16 -0
  63. metadata +63 -8
@@ -0,0 +1,63 @@
1
+ var vows = require("vows"),
2
+ assert = require("assert"),
3
+ tesseract = require("../");
4
+
5
+ var suite = vows.describe("select");
6
+
7
+ suite.addBatch({
8
+ "heapselect": batch(tesseract.heapselect)
9
+ });
10
+
11
+ function batch(select, extras) {
12
+ var batch = {
13
+ topic: function() {
14
+ return select;
15
+ },
16
+ "can select from a small array of positive integers": function(select) {
17
+ var array = [6, 5, 3, 1, 8, 7, 2, 4];
18
+ assert.deepEqual(select(array, 0, array.length, 1), [8]);
19
+ assert.deepEqual(select(array, 0, array.length, 2).sort(descending), [8, 7]);
20
+ assert.deepEqual(select(array, 0, array.length, 3).sort(descending), [8, 7, 6]);
21
+ assert.deepEqual(select(array, 0, array.length, 4).sort(descending), [8, 7, 6, 5]);
22
+ assert.deepEqual(select(array, 0, array.length, 5).sort(descending), [8, 7, 6, 5, 4]);
23
+ assert.deepEqual(select(array, 0, array.length, 6).sort(descending), [8, 7, 6, 5, 4, 3]);
24
+ assert.deepEqual(select(array, 0, array.length, 7).sort(descending), [8, 7, 6, 5, 4, 3, 2]);
25
+ assert.deepEqual(select(array, 0, array.length, 8).sort(descending), [8, 7, 6, 5, 4, 3, 2, 1]);
26
+ },
27
+ "does not affect the original order; returns a copy": function(select) {
28
+ var array = [6, 5, 3, 1, 8, 7, 2, 4];
29
+ select(array, 0, array.length, 4);
30
+ assert.deepEqual(array, [6, 5, 3, 1, 8, 7, 2, 4]);
31
+ },
32
+ "returns fewer than k elements when k is too big": function(select) {
33
+ var array = [6, 5, 3, 1, 8, 7, 2, 4];
34
+ assert.deepEqual(select(array, 0, array.length, 8).sort(descending), [8, 7, 6, 5, 4, 3, 2, 1]);
35
+ },
36
+ "returns an empty array when selecting nothing": function(select) {
37
+ var array = [];
38
+ select = select.by(function(d) { return d.value; });
39
+ assert.deepEqual(select(array, 0, array.length, 1), []);
40
+ },
41
+ "the returned array is a binary heap": function(select) {
42
+ var array = [6, 5, 3, 1, 8, 7, 2, 4];
43
+ for (var i = 0; i < 10; ++i) assert(heapy(select(array, 0, array.length, i)), array + "");
44
+ }
45
+ };
46
+ for (var key in extras) batch[key] = extras[key];
47
+ return batch;
48
+ }
49
+
50
+ function descending(a, b) {
51
+ return a > b ? -1 : a < b ? 1 : 0;
52
+ }
53
+
54
+ function heapy(array) {
55
+ for (var i = 1; i < n; ++i) {
56
+ if (array[i] < array[i - 1 >> 1]) {
57
+ return false;
58
+ }
59
+ }
60
+ return true;
61
+ }
62
+
63
+ suite.export(module);
@@ -0,0 +1,83 @@
1
+ var vows = require("vows"),
2
+ assert = require("assert"),
3
+ tesseract = require("../");
4
+
5
+ var suite = vows.describe("sort");
6
+
7
+ suite.addBatch({
8
+ "insertionsort": batch(tesseract.insertionsort),
9
+ "quicksort": batch(tesseract.quicksort, {
10
+ "can sort a largeish Uint32Array quickly": function(sort) {
11
+ var n = 1e6,
12
+ typedArray = new Uint32Array(n),
13
+ start,
14
+ duration;
15
+ for (var i = 0; i < n; i++) typedArray[i] = Math.random() * (1 << 30) | 0;
16
+ start = Date.now();
17
+ sort(typedArray, 0, n);
18
+ duration = Date.now() - start;
19
+ assert.lesser(duration, 500);
20
+ for (var i = 1; i < n; i++) assert(typedArray[i - 1] <= typedArray[i]);
21
+ }
22
+ })
23
+ });
24
+
25
+ function batch(sort, extras) {
26
+ var batch = {
27
+ topic: function() {
28
+ return sort;
29
+ },
30
+ "can sort a small array of positive integers": function(sort) {
31
+ var array = [6, 5, 3, 1, 8, 7, 2, 4];
32
+ assert.strictEqual(sort(array, 0, array.length), array);
33
+ assert.deepEqual(array, [1, 2, 3, 4, 5, 6, 7, 8]);
34
+ },
35
+ "can sort a subset of a small array of positive integers": function(sort) {
36
+ var array = [6, 5, 3, 1, 8, 7, 2, 4];
37
+ assert.strictEqual(sort(array, 0, 4), array);
38
+ assert.deepEqual(array, [1, 3, 5, 6, 8, 7, 2, 4]);
39
+ assert.strictEqual(sort(array, 4, 8), array);
40
+ assert.deepEqual(array, [1, 3, 5, 6, 2, 4, 7, 8]);
41
+ },
42
+ "can sort a small array of strings": function(sort) {
43
+ var array = ["1", "2", "10"];
44
+ assert.strictEqual(sort(array, 0, array.length), array);
45
+ assert.deepEqual(array, ["1", "10", "2"]);
46
+ },
47
+ "can sort a small array of objects using an accessor": function(sort) {
48
+ var array = [{value: 6}, {value: 1}, {value: 3}, {value: 8}];
49
+ assert.strictEqual(sort.by(function(d) { return d.value; })(array, 0, array.length), array);
50
+ assert.deepEqual(array, [{value: 1}, {value: 3}, {value: 6}, {value: 8}]);
51
+ },
52
+ "can sort a small Int32Array": function(sort) {
53
+ var n = 17,
54
+ typedArray = new Int32Array(n),
55
+ untypedArray = new Array(n),
56
+ untypedActual = new Array(n);
57
+ for (var i = 0; i < n; i++) typedArray[i] = untypedArray[i] = Math.random() * (1 << 31) | 0;
58
+ assert.strictEqual(sort(typedArray, 0, n), typedArray);
59
+ assert.strictEqual(untypedArray.sort(ascending), untypedArray);
60
+ for (var i = 0; i < n; i++) untypedActual[i] = typedArray[i];
61
+ assert.deepEqual(untypedActual, untypedArray);
62
+ },
63
+ "can sort a smallish Float64Array": function(sort) {
64
+ var n = 1e4,
65
+ typedArray = new Float64Array(n),
66
+ untypedArray = new Array(n),
67
+ untypedActual = new Array(n);
68
+ for (var i = 0; i < n; i++) typedArray[i] = untypedArray[i] = Math.random();
69
+ assert.strictEqual(sort(typedArray, 0, n), typedArray);
70
+ assert.strictEqual(untypedArray.sort(ascending), untypedArray);
71
+ for (var i = 0; i < n; i++) untypedActual[i] = typedArray[i];
72
+ assert.deepEqual(untypedActual, untypedArray);
73
+ }
74
+ };
75
+ for (var key in extras) batch[key] = extras[key];
76
+ return batch;
77
+ }
78
+
79
+ function ascending(a, b) {
80
+ return a < b ? -1 : a > b ? 1 : 0;
81
+ }
82
+
83
+ suite.export(module);
@@ -0,0 +1,655 @@
1
+ var vows = require("vows"),
2
+ assert = require("assert"),
3
+ d3 = require("d3"),
4
+ tesseract = require("../");
5
+
6
+ var suite = vows.describe("tesseract");
7
+
8
+ suite.addBatch({
9
+ "tesseract": {
10
+ topic: function() {
11
+ var data = tesseract([
12
+ {date: "2011-11-14T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
13
+ {date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
14
+ {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
15
+ {date: "2011-11-14T16:30:43Z", quantity: 2, total: 90, tip: 0, type: "tab"},
16
+ {date: "2011-11-14T16:48:46Z", quantity: 2, total: 90, tip: 0, type: "tab"},
17
+ {date: "2011-11-14T16:53:41Z", quantity: 2, total: 90, tip: 0, type: "tab"},
18
+ {date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: null, type: "cash"},
19
+ {date: "2011-11-14T17:02:03Z", quantity: 2, total: 90, tip: 0, type: "tab"},
20
+ {date: "2011-11-14T17:07:21Z", quantity: 2, total: 90, tip: 0, type: "tab"},
21
+ {date: "2011-11-14T17:22:59Z", quantity: 2, total: 90, tip: 0, type: "tab"},
22
+ {date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: null, type: "cash"},
23
+ {date: "2011-11-14T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"},
24
+ {date: "2011-11-14T17:33:46Z", quantity: 2, total: 190, tip: 100, type: "tab"},
25
+ {date: "2011-11-14T17:33:59Z", quantity: 2, total: 90, tip: 0, type: "tab"},
26
+ {date: "2011-11-14T17:38:40Z", quantity: 2, total: 200, tip: 100, type: "visa"},
27
+ {date: "2011-11-14T17:52:02Z", quantity: 2, total: 90, tip: 0, type: "tab"},
28
+ {date: "2011-11-14T18:02:42Z", quantity: 2, total: 190, tip: 100, type: "tab"},
29
+ {date: "2011-11-14T18:02:51Z", quantity: 2, total: 190, tip: 100, type: "tab"},
30
+ {date: "2011-11-14T18:12:54Z", quantity: 1, total: 200, tip: 100, type: "visa"},
31
+ {date: "2011-11-14T18:14:53Z", quantity: 2, total: 100, tip: null, type: "cash"},
32
+ {date: "2011-11-14T18:45:24Z", quantity: 2, total: 90, tip: 0, type: "tab"},
33
+ {date: "2011-11-14T19:00:31Z", quantity: 2, total: 190, tip: 100, type: "tab"},
34
+ {date: "2011-11-14T19:04:22Z", quantity: 2, total: 90, tip: 0, type: "tab"},
35
+ {date: "2011-11-14T19:30:44Z", quantity: 2, total: 90, tip: 0, type: "tab"},
36
+ {date: "2011-11-14T20:06:33Z", quantity: 1, total: 100, tip: null, type: "cash"},
37
+ {date: "2011-11-14T20:49:07Z", quantity: 2, total: 290, tip: 200, type: "tab"},
38
+ {date: "2011-11-14T21:05:36Z", quantity: 2, total: 90, tip: 0, type: "tab"},
39
+ {date: "2011-11-14T21:18:48Z", quantity: 4, total: 270, tip: 0, type: "tab"},
40
+ {date: "2011-11-14T21:22:31Z", quantity: 1, total: 200, tip: 100, type: "visa"},
41
+ {date: "2011-11-14T21:26:30Z", quantity: 2, total: 190, tip: 100, type: "tab"},
42
+ {date: "2011-11-14T21:30:55Z", quantity: 2, total: 190, tip: 100, type: "tab"},
43
+ {date: "2011-11-14T21:31:05Z", quantity: 2, total: 90, tip: 0, type: "tab"},
44
+ {date: "2011-11-14T22:30:22Z", quantity: 2, total: 90, tip: 0, type: "tab"},
45
+ {date: "2011-11-14T22:34:28Z", quantity: 2, total: 190, tip: 100, type: "tab"},
46
+ {date: "2011-11-14T22:48:05Z", quantity: 2, total: 90, tip: 0, type: "tab"},
47
+ {date: "2011-11-14T22:51:40Z", quantity: 2, total: 190, tip: 100, type: "tab"},
48
+ {date: "2011-11-14T22:58:54Z", quantity: 2, total: 100, tip: 0, type: "visa"},
49
+ {date: "2011-11-14T23:06:25Z", quantity: 2, total: 190, tip: 100, type: "tab"},
50
+ {date: "2011-11-14T23:07:58Z", quantity: 2, total: 190, tip: 100, type: "tab"},
51
+ {date: "2011-11-14T23:16:09Z", quantity: 1, total: 200, tip: 100, type: "visa"},
52
+ {date: "2011-11-14T23:21:22Z", quantity: 2, total: 190, tip: 100, type: "tab"},
53
+ {date: "2011-11-14T23:23:29Z", quantity: 2, total: 190, tip: 100, type: "tab"},
54
+ {date: "2011-11-14T23:28:54Z", quantity: 2, total: 190, tip: 100, type: "tab"}
55
+ ]);
56
+
57
+ // be sure you don't clobber a built-in method if you do this!
58
+ try {
59
+ data.date = data.dimension(function(d) { return new Date(d.date); });
60
+ data.quantity = data.dimension(function(d) { return d.quantity; });
61
+ data.tip = data.dimension(function(d) { return d.tip; });
62
+ data.total = data.dimension(function(d) { return d.total; });
63
+ data.type = data.dimension(function(d) { return d.type; });
64
+ } catch (e) {
65
+ console.log(e.stack);
66
+ }
67
+
68
+ return data;
69
+ },
70
+
71
+ "up to 32 dimensions supported": function() {
72
+ var data = tesseract([]);
73
+ for (var i = 0; i < 32; i++) data.dimension(function() { return 0; });
74
+ assert.throws(function() { data.dimension(function() { return 0; }); }, Error);
75
+ },
76
+
77
+ "dimension": {
78
+
79
+ "top": {
80
+ "returns the top k records by value, in descending order": function(data) {
81
+ assert.deepEqual(data.total.top(3), [
82
+ {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
83
+ {date: "2011-11-14T20:49:07Z", quantity: 2, total: 290, tip: 200, type: "tab"},
84
+ {date: "2011-11-14T21:18:48Z", quantity: 4, total: 270, tip: 0, type: "tab"}
85
+ ]);
86
+ assert.deepEqual(data.date.top(3), [
87
+ {date: "2011-11-14T23:28:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
88
+ {date: "2011-11-14T23:23:29Z", quantity: 2, total: 190, tip: 100, type: "tab"},
89
+ {date: "2011-11-14T23:21:22Z", quantity: 2, total: 190, tip: 100, type: "tab"}
90
+ ]);
91
+ },
92
+ "observes the associated dimension's filters": function(data) {
93
+ try {
94
+ data.quantity.filterExact(4);
95
+ assert.deepEqual(data.total.top(3), [
96
+ {date: "2011-11-14T21:18:48Z", quantity: 4, total: 270, tip: 0, type: "tab"}
97
+ ]);
98
+ } finally {
99
+ data.quantity.filterAll();
100
+ }
101
+ try {
102
+ data.date.filterRange([new Date(Date.UTC(2011, 10, 14, 19)), new Date(Date.UTC(2011, 10, 14, 20))]);
103
+ assert.deepEqual(data.date.top(10), [
104
+ {date: "2011-11-14T19:30:44Z", quantity: 2, total: 90, tip: 0, type: "tab"},
105
+ {date: "2011-11-14T19:04:22Z", quantity: 2, total: 90, tip: 0, type: "tab"},
106
+ {date: "2011-11-14T19:00:31Z", quantity: 2, total: 190, tip: 100, type: "tab"}
107
+ ]);
108
+ data.date.filterRange([Date.UTC(2011, 10, 14, 19), Date.UTC(2011, 10, 14, 20)]); // also comparable
109
+ assert.deepEqual(data.date.top(10), [
110
+ {date: "2011-11-14T19:30:44Z", quantity: 2, total: 90, tip: 0, type: "tab"},
111
+ {date: "2011-11-14T19:04:22Z", quantity: 2, total: 90, tip: 0, type: "tab"},
112
+ {date: "2011-11-14T19:00:31Z", quantity: 2, total: 190, tip: 100, type: "tab"}
113
+ ]);
114
+ } finally {
115
+ data.date.filterAll();
116
+ }
117
+ },
118
+ "observes other dimensions' filters": function(data) {
119
+ try {
120
+ data.type.filterExact("tab");
121
+ assert.deepEqual(data.total.top(2), [
122
+ {date: "2011-11-14T20:49:07Z", quantity: 2, total: 290, tip: 200, type: "tab"},
123
+ {date: "2011-11-14T21:18:48Z", quantity: 4, total: 270, tip: 0, type: "tab"}
124
+ ]);
125
+ data.type.filterExact("visa");
126
+ assert.deepEqual(data.total.top(1), [
127
+ {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"}
128
+ ]);
129
+ data.quantity.filterExact(2);
130
+ assert.deepEqual(data.tip.top(1), [
131
+ {date: "2011-11-14T17:38:40Z", quantity: 2, total: 200, tip: 100, type: "visa"}
132
+ ]);
133
+ } finally {
134
+ data.type.filterAll();
135
+ data.quantity.filterAll();
136
+ }
137
+ try {
138
+ data.type.filterExact("tab");
139
+ assert.deepEqual(data.date.top(2), [
140
+ {date: "2011-11-14T23:28:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
141
+ {date: "2011-11-14T23:23:29Z", quantity: 2, total: 190, tip: 100, type: "tab"}
142
+ ]);
143
+ data.type.filterExact("visa");
144
+ assert.deepEqual(data.date.top(1), [
145
+ {date: "2011-11-14T23:16:09Z", quantity: 1, total: 200, tip: 100, type: "visa"}
146
+ ]);
147
+ data.quantity.filterExact(2);
148
+ assert.deepEqual(data.date.top(1), [
149
+ {date: "2011-11-14T22:58:54Z", quantity: 2, total: 100, tip: 0, type: "visa"}
150
+ ]);
151
+ } finally {
152
+ data.type.filterAll();
153
+ data.quantity.filterAll();
154
+ }
155
+ },
156
+ "negative or zero k returns an empty array": function(data) {
157
+ assert.deepEqual(data.quantity.top(0), []);
158
+ assert.deepEqual(data.quantity.top(-1), []);
159
+ assert.deepEqual(data.quantity.top(NaN), []);
160
+ assert.deepEqual(data.quantity.top(-Infinity), []);
161
+ assert.deepEqual(data.date.top(0), []);
162
+ assert.deepEqual(data.date.top(-1), []);
163
+ assert.deepEqual(data.date.top(NaN), []);
164
+ assert.deepEqual(data.date.top(-Infinity), []);
165
+ }
166
+ },
167
+
168
+ "filterExact": {
169
+ "selects records that match the specified value exactly": function(data) {
170
+ try {
171
+ data.tip.filterExact(100);
172
+ assert.deepEqual(data.date.top(2), [
173
+ {date: "2011-11-14T23:28:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
174
+ {date: "2011-11-14T23:23:29Z", quantity: 2, total: 190, tip: 100, type: "tab"}
175
+ ]);
176
+ } finally {
177
+ data.tip.filterAll();
178
+ }
179
+ },
180
+ "allows the filter value to be null": function(data) {
181
+ try {
182
+ data.tip.filterExact(null); // equivalent to 0 by natural ordering
183
+ assert.deepEqual(data.date.top(2), [
184
+ {date: "2011-11-14T22:58:54Z", quantity: 2, total: 100, tip: 0, type: "visa"},
185
+ {date: "2011-11-14T22:48:05Z", quantity: 2, total: 90, tip: 0, type: "tab"}
186
+ ]);
187
+ } finally {
188
+ data.tip.filterAll();
189
+ }
190
+ }
191
+ },
192
+
193
+ "filterRange": {
194
+ "selects records greater than or equal to the inclusive lower bound": function(data) {
195
+ try {
196
+ data.total.filterRange([100, 190]);
197
+ assert.isTrue(data.date.top(Infinity).every(function(d) { return d.total >= 100; }));
198
+ data.total.filterRange([110, 190]);
199
+ assert.isTrue(data.date.top(Infinity).every(function(d) { return d.total >= 110; }));
200
+ } finally {
201
+ data.total.filterAll();
202
+ }
203
+ },
204
+ "selects records less than the exclusive lower bound": function(data) {
205
+ try {
206
+ data.total.filterRange([100, 200]);
207
+ assert.isTrue(data.date.top(Infinity).every(function(d) { return d.total < 200; }));
208
+ data.total.filterRange([100, 190]);
209
+ assert.isTrue(data.date.top(Infinity).every(function(d) { return d.total < 190; }));
210
+ } finally {
211
+ data.total.filterAll();
212
+ }
213
+ }
214
+ },
215
+
216
+ "filterAll": {
217
+ "clears the filter": function(data) {
218
+ data.total.filterRange([100, 200]);
219
+ assert.lesser(data.date.top(Infinity).length, 43);
220
+ data.total.filterAll();
221
+ assert.equal(data.date.top(Infinity).length, 43);
222
+ }
223
+ },
224
+
225
+ "filter": {
226
+ "is equivalent to filterRange when passed an array": function(data) {
227
+ try {
228
+ data.total.filter([100, 190]);
229
+ assert.isTrue(data.date.top(Infinity).every(function(d) { return d.total >= 100; }));
230
+ } finally {
231
+ data.total.filter(null);
232
+ }
233
+ },
234
+ "is equivalent to filterExact when passed a single value": function(data) {
235
+ try {
236
+ data.total.filter(100);
237
+ assert.isTrue(data.date.top(Infinity).every(function(d) { return d.total == 100; }));
238
+ } finally {
239
+ data.total.filter(null);
240
+ }
241
+ },
242
+ "is equivalent to filterAll when passed null": function(data) {
243
+ data.total.filter([100, 200]);
244
+ assert.lesser(data.date.top(Infinity).length, 43);
245
+ data.total.filter(null);
246
+ assert.equal(data.date.top(Infinity).length, 43);
247
+ }
248
+ },
249
+
250
+ "groupAll (count, the default)": {
251
+ topic: function(data) {
252
+ data.quantity.count = data.quantity.groupAll();
253
+ return data;
254
+ },
255
+
256
+ "does not have top and order methods": function(data) {
257
+ assert.isFalse("top" in data.quantity.count);
258
+ assert.isFalse("order" in data.quantity.count);
259
+ },
260
+
261
+ "reduce": {
262
+ "reduces by add, remove, and initial": function(data) {
263
+ try {
264
+ data.quantity.count.reduce(
265
+ function(p, v) { return p + v.total; },
266
+ function(p, v) { return p - v.total; },
267
+ function() { return 0; });
268
+ assert.strictEqual(data.quantity.count.value(), 6660);
269
+ } finally {
270
+ data.quantity.count.reduceCount();
271
+ }
272
+ }
273
+ },
274
+
275
+ "reduceCount": {
276
+ "reduces by count": function(data) {
277
+ data.quantity.count.reduceSum(function(d) { return d.total; });
278
+ assert.strictEqual(data.quantity.count.value(), 6660);
279
+ data.quantity.count.reduceCount();
280
+ assert.strictEqual(data.quantity.count.value(), 43);
281
+ }
282
+ },
283
+
284
+ "reduceSum": {
285
+ "reduces by sum of accessor function": function(data) {
286
+ try {
287
+ data.quantity.count.reduceSum(function(d) { return d.total; });
288
+ assert.strictEqual(data.quantity.count.value(), 6660);
289
+ data.quantity.count.reduceSum(function() { return 1; });
290
+ assert.strictEqual(data.quantity.count.value(), 43);
291
+ } finally {
292
+ data.quantity.count.reduceCount();
293
+ }
294
+ }
295
+ },
296
+
297
+ "value": {
298
+ "returns the count of matching records": function(data) {
299
+ assert.strictEqual(data.quantity.count.value(), 43);
300
+ },
301
+ "does not observe the associated dimension's filters": function(data) {
302
+ try {
303
+ data.quantity.filterRange([100, 200]);
304
+ assert.strictEqual(data.quantity.count.value(), 43);
305
+ } finally {
306
+ data.quantity.filterAll();
307
+ }
308
+ },
309
+ "observes other dimensions' filters": function(data) {
310
+ try {
311
+ data.type.filterExact("tab");
312
+ assert.strictEqual(data.quantity.count.value(), 32);
313
+ data.type.filterExact("visa");
314
+ assert.strictEqual(data.quantity.count.value(), 7);
315
+ data.tip.filterExact(100);
316
+ assert.strictEqual(data.quantity.count.value(), 5);
317
+ } finally {
318
+ data.type.filterAll();
319
+ data.tip.filterAll();
320
+ }
321
+ }
322
+ }
323
+ },
324
+
325
+ "groupAll (sum of total)": {
326
+ topic: function(data) {
327
+ data.quantity.total = data.quantity.groupAll().reduceSum(function(d) { return d.total; });
328
+ return data;
329
+ },
330
+
331
+ "does not have top and order methods": function(data) {
332
+ assert.isFalse("top" in data.quantity.total);
333
+ assert.isFalse("order" in data.quantity.total);
334
+ },
335
+
336
+ "reduce": {
337
+ "determines the computed reduce value": function(data) {
338
+ try {
339
+ data.quantity.total.reduce(
340
+ function(p) { return p + 1; },
341
+ function(p) { return p - 1; },
342
+ function() { return 0; });
343
+ assert.strictEqual(data.quantity.total.value(), 43);
344
+ } finally {
345
+ data.quantity.total.reduceSum(function(d) { return d.total; });
346
+ }
347
+ }
348
+ },
349
+
350
+ "value": {
351
+ "returns the sum total of matching records": function(data) {
352
+ assert.strictEqual(data.quantity.total.value(), 6660);
353
+ },
354
+ "does not observe the associated dimension's filters": function(data) {
355
+ try {
356
+ data.quantity.filterRange([100, 200]);
357
+ assert.strictEqual(data.quantity.total.value(), 6660);
358
+ } finally {
359
+ data.quantity.filterAll();
360
+ }
361
+ },
362
+ "observes other dimensions' filters": function(data) {
363
+ try {
364
+ data.type.filterExact("tab");
365
+ assert.strictEqual(data.quantity.total.value(), 4760);
366
+ data.type.filterExact("visa");
367
+ assert.strictEqual(data.quantity.total.value(), 1400);
368
+ data.tip.filterExact(100);
369
+ assert.strictEqual(data.quantity.total.value(), 1000);
370
+ } finally {
371
+ data.type.filterAll();
372
+ data.tip.filterAll();
373
+ }
374
+ }
375
+ }
376
+ },
377
+
378
+ "group": {
379
+ topic: function(data) {
380
+ data.date.hours = data.date.group(function(d) { d = new Date(+d); d.setHours(d.getHours(), 0, 0, 0); return d; });
381
+ data.type.types = data.type.group();
382
+ return data;
383
+ },
384
+
385
+ "key defaults to value": function(data) {
386
+ assert.deepEqual(data.type.types.top(Infinity), [
387
+ {key: "tab", value: 32},
388
+ {key: "visa", value: 7},
389
+ {key: "cash", value: 4}
390
+ ]);
391
+ },
392
+
393
+ "cardinality may be greater than 256": function() {
394
+ var data = tesseract(d3.range(256).concat(256, 256)),
395
+ index = data.dimension(function(d) { return d; }),
396
+ indexes = index.group();
397
+ assert.deepEqual(index.top(2), [256, 256]);
398
+ assert.deepEqual(indexes.top(1), [{key: 256, value: 2}]);
399
+ assert.equal(indexes.size(), 257);
400
+ },
401
+
402
+ "cardinality may be greater than 65536": function() {
403
+ var data = tesseract(d3.range(65536).concat(65536, 65536)),
404
+ index = data.dimension(function(d) { return d; }),
405
+ indexes = index.group();
406
+ assert.deepEqual(index.top(2), [65536, 65536]);
407
+ assert.deepEqual(indexes.top(1), [{key: 65536, value: 2}]);
408
+ assert.equal(indexes.size(), 65537);
409
+ },
410
+
411
+ "size": {
412
+ "returns the cardinality": function(data) {
413
+ assert.equal(data.date.hours.size(), 8);
414
+ assert.equal(data.type.types.size(), 3);
415
+ },
416
+ "ignores any filters": function(data) {
417
+ try {
418
+ data.type.filterExact("tab");
419
+ data.quantity.filterRange([100, 200]);
420
+ assert.equal(data.date.hours.size(), 8);
421
+ assert.equal(data.type.types.size(), 3);
422
+ } finally {
423
+ data.quantity.filterAll();
424
+ data.type.filterAll();
425
+ }
426
+ }
427
+ },
428
+
429
+ "reduce": {
430
+ "defaults to count": function(data) {
431
+ assert.deepEqual(data.date.hours.top(1), [
432
+ {key: new Date(Date.UTC(2011, 10, 14, 17, 00, 00)), value: 9}
433
+ ]);
434
+ },
435
+ "determines the computed reduce value": function(data) {
436
+ try {
437
+ data.date.hours.reduceSum(function(d) { return d.total; });
438
+ assert.deepEqual(data.date.hours.top(1), [
439
+ {key: new Date(Date.UTC(2011, 10, 14, 17, 00, 00)), value: 1240}
440
+ ]);
441
+ } finally {
442
+ data.date.hours.reduceCount();
443
+ }
444
+ }
445
+ },
446
+
447
+ "top": {
448
+ "returns the top k groups by reduce value, in descending order": function(data) {
449
+ assert.deepEqual(data.date.hours.top(3), [
450
+ {key: new Date(Date.UTC(2011, 10, 14, 17, 00, 00)), value: 9},
451
+ {key: new Date(Date.UTC(2011, 10, 14, 16, 00, 00)), value: 7},
452
+ {key: new Date(Date.UTC(2011, 10, 14, 21, 00, 00)), value: 6}
453
+ ]);
454
+ },
455
+ "observes the specified order": function(data) {
456
+ try {
457
+ data.date.hours.order(function(v) { return -v; });
458
+ assert.deepEqual(data.date.hours.top(3), [
459
+ {key: new Date(Date.UTC(2011, 10, 14, 20, 00, 00)), value: 2},
460
+ {key: new Date(Date.UTC(2011, 10, 14, 19, 00, 00)), value: 3},
461
+ {key: new Date(Date.UTC(2011, 10, 14, 18, 00, 00)), value: 5}
462
+ ]);
463
+ } finally {
464
+ data.date.hours.order(function(v) { return v; });
465
+ }
466
+ }
467
+ },
468
+
469
+ "order": {
470
+ "defaults to the identity function": function(data) {
471
+ assert.deepEqual(data.date.hours.top(1), [
472
+ {key: new Date(Date.UTC(2011, 10, 14, 17, 00, 00)), value: 9}
473
+ ]);
474
+ },
475
+ "is useful in conjunction with a compound reduce value": function(data) {
476
+ try {
477
+ data.date.hours.reduce(
478
+ function(p, v) { ++p.count; p.total += v.total; return p; },
479
+ function(p, v) { --p.count; p.total -= v.total; return p; },
480
+ function() { return {count: 0, total: 0}; })
481
+ .order(function(v) { return v.total; });
482
+ assert.deepEqual(data.date.hours.top(1), [
483
+ {key: new Date(Date.UTC(2011, 10, 14, 17, 00, 00)), value: {count: 9, total: 1240}}
484
+ ]);
485
+ } finally {
486
+ data.date.hours.reduceCount().orderNatural();
487
+ }
488
+ }
489
+ }
490
+ }
491
+ },
492
+
493
+ "groupAll": {
494
+ topic: function(data) {
495
+ data.all = data.groupAll().reduceSum(function(d) { return d.total; });
496
+ return data;
497
+ },
498
+
499
+ "does not have top and order methods": function(data) {
500
+ assert.isFalse("top" in data.all);
501
+ assert.isFalse("order" in data.all);
502
+ },
503
+
504
+ "reduce": {
505
+ "determines the computed reduce value": function(data) {
506
+ try {
507
+ data.all.reduceCount();
508
+ assert.strictEqual(data.all.value(), 43);
509
+ } finally {
510
+ data.all.reduceSum(function(d) { return d.total; });
511
+ }
512
+ }
513
+ },
514
+
515
+ "value": {
516
+ "returns the sum total of matching records": function(data) {
517
+ assert.strictEqual(data.all.value(), 6660);
518
+ },
519
+ "observes all dimension's filters": function(data) {
520
+ try {
521
+ data.type.filterExact("tab");
522
+ assert.strictEqual(data.all.value(), 4760);
523
+ data.type.filterExact("visa");
524
+ assert.strictEqual(data.all.value(), 1400);
525
+ data.tip.filterExact(100);
526
+ assert.strictEqual(data.all.value(), 1000);
527
+ } finally {
528
+ data.type.filterAll();
529
+ data.tip.filterAll();
530
+ }
531
+ }
532
+ }
533
+ },
534
+
535
+ "size": {
536
+ "returns the total number of elements": function(data) {
537
+ assert.equal(data.size(), 43);
538
+ },
539
+ "is not affected by any dimension filters": function(data) {
540
+ try {
541
+ data.quantity.filterExact(4);
542
+ assert.equal(data.size(), 43);
543
+ } finally {
544
+ data.quantity.filterAll();
545
+ }
546
+ }
547
+ },
548
+
549
+ "add": {
550
+ "increases the size of the tesseract": function() {
551
+ var data = tesseract([]);
552
+ assert.equal(data.size(), 0);
553
+ data.add([0, 1, 2, 3, 4, 5, 6, 6, 6, 7]);
554
+ assert.equal(data.size(), 10);
555
+ data.add([]);
556
+ assert.equal(data.size(), 10);
557
+ },
558
+ "existing filters are consistent with new records": function(data) {
559
+ var data = tesseract([]),
560
+ foo = data.dimension(function(d) { return +d; }),
561
+ bar = data.dimension(function(d) { return -d; });
562
+ assert.deepEqual(foo.top(Infinity), []);
563
+ foo.filterExact(42);
564
+ data.add([43, 42, 41]);
565
+ assert.deepEqual(foo.top(Infinity), [42]);
566
+ assert.deepEqual(bar.top(Infinity), [42]);
567
+ data.add([43, 42]);
568
+ assert.deepEqual(foo.top(Infinity), [42, 42]);
569
+ assert.deepEqual(bar.top(Infinity), [42, 42]);
570
+ foo.filterRange([42, 44]);
571
+ data.add([43]);
572
+ assert.deepEqual(foo.top(Infinity), [43, 43, 43, 42, 42]);
573
+ assert.deepEqual(bar.top(Infinity), [42, 42, 43, 43, 43]);
574
+ bar.filterExact([-43]);
575
+ assert.deepEqual(bar.top(Infinity), [43, 43, 43]);
576
+ data.add([43]);
577
+ assert.deepEqual(bar.top(Infinity), [43, 43, 43, 43]);
578
+ bar.filterAll();
579
+ data.add([0]);
580
+ assert.deepEqual(bar.top(Infinity), [42, 42, 43, 43, 43, 43]);
581
+ foo.filterAll();
582
+ assert.deepEqual(bar.top(Infinity), [0, 41, 42, 42, 43, 43, 43, 43]);
583
+ },
584
+ "existing groups are consistent with new records": function(data) {
585
+ var data = tesseract([]),
586
+ foo = data.dimension(function(d) { return +d; }),
587
+ bar = data.dimension(function(d) { return -d; }),
588
+ foos = foo.group(),
589
+ all = data.groupAll();
590
+ assert.equal(all.value(), 0);
591
+ assert.deepEqual(foos.all(), []);
592
+ foo.filterExact(42);
593
+ data.add([43, 42, 41]);
594
+ assert.equal(all.value(), 1);
595
+ assert.deepEqual(foos.all(), [{key: 41, value: 1}, {key: 42, value: 1}, {key: 43, value: 1}]);
596
+ bar.filterExact(-42);
597
+ assert.equal(all.value(), 1);
598
+ assert.deepEqual(foos.all(), [{key: 41, value: 0}, {key: 42, value: 1}, {key: 43, value: 0}]);
599
+ data.add([43, 42, 41]);
600
+ assert.equal(all.value(), 2);
601
+ assert.deepEqual(foos.all(), [{key: 41, value: 0}, {key: 42, value: 2}, {key: 43, value: 0}]);
602
+ bar.filterAll();
603
+ assert.equal(all.value(), 2);
604
+ assert.deepEqual(foos.all(), [{key: 41, value: 2}, {key: 42, value: 2}, {key: 43, value: 2}]);
605
+ foo.filterAll();
606
+ assert.equal(all.value(), 6);
607
+ },
608
+ "can add new groups that are before existing groups": function(data) {
609
+ var data = tesseract(),
610
+ foo = data.dimension(function(d) { return +d; }),
611
+ foos = foo.group().reduce(add, remove, initial).order(order);
612
+ data.add([2]).add([1, 1, 1]);
613
+ assert.deepEqual(foos.top(2), [{key: 1, value: {foo: 3}}, {key: 2, value: {foo: 1}}]);
614
+ function order(p) { return p.foo; }
615
+ function add(p, v) { ++p.foo; return p; }
616
+ function remove(p, v) { --p.foo; return p; }
617
+ function initial() { return {foo: 0}; }
618
+ },
619
+ "can add more than 256 groups": function(data) {
620
+ var data = tesseract(),
621
+ foo = data.dimension(function(d) { return +d; }),
622
+ bar = data.dimension(function(d) { return +d; }),
623
+ foos = foo.group();
624
+ data.add(d3.range(0, 256));
625
+ assert.deepEqual(foos.all().map(function(d) { return d.key; }), d3.range(0, 256));
626
+ assert(foos.all().every(function(d) { return d.value == 1; }));
627
+ data.add([128]);
628
+ assert.deepEqual(foos.top(1), [{key: 128, value: 2}]);
629
+ bar.filterExact(0);
630
+ data.add(d3.range(-256, 0));
631
+ assert.deepEqual(foos.all().map(function(d) { return d.key; }), d3.range(-256, 256));
632
+ assert.deepEqual(foos.top(1), [{key: 0, value: 1}]);
633
+ },
634
+ "can add lots of groups in reverse order": function(data) {
635
+ var data = tesseract(),
636
+ foo = data.dimension(function(d) { return -d.foo; }),
637
+ bar = data.dimension(function(d) { return d.bar; }),
638
+ foos = foo.group(Math.floor).reduceSum(function(d) { return d.foo; });
639
+ bar.filterExact(1);
640
+ for (var i = 0; i < 1000; i++) {
641
+ data.add(d3.range(10).map(function(d) {
642
+ return {foo: i + d / 10, bar: i % 4, baz: d + i * 10};
643
+ }));
644
+ }
645
+ assert.deepEqual(foos.top(1), [{key: -998, value: 8977.5}]);
646
+ }
647
+ }
648
+ }
649
+ });
650
+
651
+ function key(d) {
652
+ return d.key;
653
+ }
654
+
655
+ suite.export(module);