d3_rails 2.7.4 → 2.7.5.v2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ d3.chart = {};
@@ -0,0 +1,203 @@
1
+ // Implements a horizon layout, which is a variation of a single-series
2
+ // area chart where the area is folded into multiple bands. Color is used to
3
+ // encode band, allowing the size of the chart to be reduced significantly
4
+ // without impeding readability. This layout algorithm is based on the work of
5
+ // J. Heer, N. Kong and M. Agrawala in "Sizing the Horizon: The Effects of Chart
6
+ // Size and Layering on the Graphical Perception of Time Series Visualizations",
7
+ // CHI 2009. http://hci.stanford.edu/publications/2009/heer-horizon-chi09.pdf
8
+ d3.chart.horizon = function() {
9
+ var bands = 1, // between 1 and 5, typically
10
+ mode = "offset", // or mirror
11
+ interpolate = "linear", // or basis, monotone, step-before, etc.
12
+ x = d3_chart_horizonX,
13
+ y = d3_chart_horizonY,
14
+ w = 960,
15
+ h = 40,
16
+ duration = 0;
17
+
18
+ var color = d3.scale.linear()
19
+ .domain([-1, 0, 1])
20
+ .range(["#d62728", "#fff", "#1f77b4"]);
21
+
22
+ // For each small multiple…
23
+ function horizon(g) {
24
+ g.each(function(d, i) {
25
+ var g = d3.select(this),
26
+ n = 2 * bands + 1,
27
+ xMin = Infinity,
28
+ xMax = -Infinity,
29
+ yMax = -Infinity,
30
+ x0, // old x-scale
31
+ y0, // old y-scale
32
+ id; // unique id for paths
33
+
34
+ // Compute x- and y-values along with extents.
35
+ var data = d.map(function(d, i) {
36
+ var xv = x.call(this, d, i),
37
+ yv = y.call(this, d, i);
38
+ if (xv < xMin) xMin = xv;
39
+ if (xv > xMax) xMax = xv;
40
+ if (-yv > yMax) yMax = -yv;
41
+ if (yv > yMax) yMax = yv;
42
+ return [xv, yv];
43
+ });
44
+
45
+ // Compute the new x- and y-scales.
46
+ var x1 = d3.scale.linear().domain([xMin, xMax]).range([0, w]),
47
+ y1 = d3.scale.linear().domain([0, yMax]).range([0, h * bands]);
48
+
49
+ // Retrieve the old scales, if this is an update.
50
+ if (this.__chart__) {
51
+ x0 = this.__chart__.x;
52
+ y0 = this.__chart__.y;
53
+ id = this.__chart__.id;
54
+ } else {
55
+ x0 = d3.scale.linear().domain([0, Infinity]).range(x1.range());
56
+ y0 = d3.scale.linear().domain([0, Infinity]).range(y1.range());
57
+ id = ++d3_chart_horizonId;
58
+ }
59
+
60
+ // We'll use a defs to store the area path and the clip path.
61
+ var defs = g.selectAll("defs")
62
+ .data([data]);
63
+
64
+ var defsEnter = defs.enter().append("svg:defs");
65
+
66
+ // The clip path is a simple rect.
67
+ defsEnter.append("svg:clipPath")
68
+ .attr("id", "d3_chart_horizon_clip" + id)
69
+ .append("svg:rect")
70
+ .attr("width", w)
71
+ .attr("height", h);
72
+
73
+ defs.select("rect").transition()
74
+ .duration(duration)
75
+ .attr("width", w)
76
+ .attr("height", h);
77
+
78
+ // The area path is rendered with our resuable d3.svg.area.
79
+ defsEnter.append("svg:path")
80
+ .attr("id", "d3_chart_horizon_path" + id)
81
+ .attr("d", d3_chart_horizonArea
82
+ .interpolate(interpolate)
83
+ .x(function(d) { return x0(d[0]); })
84
+ .y0(h * bands)
85
+ .y1(function(d) { return h * bands - y0(d[1]); }))
86
+ .transition()
87
+ .duration(duration)
88
+ .attr("d", d3_chart_horizonArea
89
+ .x(function(d) { return x1(d[0]); })
90
+ .y1(function(d) { return h * bands - y1(d[1]); }));
91
+
92
+ defs.select("path").transition()
93
+ .duration(duration)
94
+ .attr("d", d3_chart_horizonArea);
95
+
96
+ // We'll use a container to clip all horizon layers at once.
97
+ g.selectAll("g")
98
+ .data([null])
99
+ .enter().append("svg:g")
100
+ .attr("clip-path", "url(#d3_chart_horizon_clip" + id + ")");
101
+
102
+ // Define the transform function based on the mode.
103
+ var transform = mode == "offset"
104
+ ? function(d) { return "translate(0," + (d + (d < 0) - bands) * h + ")"; }
105
+ : function(d) { return (d < 0 ? "scale(1,-1)" : "") + "translate(0," + (d - bands) * h + ")"; };
106
+
107
+ // Instantiate each copy of the path with different transforms.
108
+ var u = g.select("g").selectAll("use")
109
+ .data(d3.range(-1, -bands - 1, -1).concat(d3.range(1, bands + 1)), Number);
110
+
111
+ // TODO don't fudge the enter transition
112
+ u.enter().append("svg:use")
113
+ .attr("xlink:href", "#d3_chart_horizon_path" + id)
114
+ .attr("transform", function(d) { return transform(d + (d > 0 ? 1 : -1)); })
115
+ .style("fill", color)
116
+ .transition()
117
+ .duration(duration)
118
+ .attr("transform", transform);
119
+
120
+ u.transition()
121
+ .duration(duration)
122
+ .attr("transform", transform)
123
+ .style("fill", color);
124
+
125
+ u.exit().transition()
126
+ .duration(duration)
127
+ .attr("transform", transform)
128
+ .remove();
129
+
130
+ // Stash the new scales.
131
+ this.__chart__ = {x: x1, y: y1, id: id};
132
+ });
133
+ d3.timer.flush();
134
+ }
135
+
136
+ horizon.duration = function(x) {
137
+ if (!arguments.length) return duration;
138
+ duration = +x;
139
+ return horizon;
140
+ };
141
+
142
+ horizon.bands = function(x) {
143
+ if (!arguments.length) return bands;
144
+ bands = +x;
145
+ color.domain([-bands, 0, bands]);
146
+ return horizon;
147
+ };
148
+
149
+ horizon.mode = function(x) {
150
+ if (!arguments.length) return mode;
151
+ mode = x + "";
152
+ return horizon;
153
+ };
154
+
155
+ horizon.colors = function(x) {
156
+ if (!arguments.length) return color.range();
157
+ color.range(x);
158
+ return horizon;
159
+ };
160
+
161
+ horizon.interpolate = function(x) {
162
+ if (!arguments.length) return interpolate;
163
+ interpolate = x + "";
164
+ return horizon;
165
+ };
166
+
167
+ horizon.x = function(z) {
168
+ if (!arguments.length) return x;
169
+ x = z;
170
+ return horizon;
171
+ };
172
+
173
+ horizon.y = function(z) {
174
+ if (!arguments.length) return y;
175
+ y = z;
176
+ return horizon;
177
+ };
178
+
179
+ horizon.width = function(x) {
180
+ if (!arguments.length) return w;
181
+ w = +x;
182
+ return horizon;
183
+ };
184
+
185
+ horizon.height = function(x) {
186
+ if (!arguments.length) return h;
187
+ h = +x;
188
+ return horizon;
189
+ };
190
+
191
+ return horizon;
192
+ };
193
+
194
+ var d3_chart_horizonArea = d3.svg.area(),
195
+ d3_chart_horizonId = 0;
196
+
197
+ function d3_chart_horizonX(d) {
198
+ return d[0];
199
+ }
200
+
201
+ function d3_chart_horizonY(d) {
202
+ return d[1];
203
+ }
@@ -0,0 +1,245 @@
1
+ // Based on http://vis.stanford.edu/protovis/ex/qqplot.html
2
+ d3.chart.qq = function() {
3
+ var width = 1,
4
+ height = 1,
5
+ duration = 0,
6
+ domain = null,
7
+ tickFormat = null,
8
+ n = 100,
9
+ x = d3_chart_qqX,
10
+ y = d3_chart_qqY;
11
+
12
+ // For each small multiple…
13
+ function qq(g) {
14
+ g.each(function(d, i) {
15
+ var g = d3.select(this),
16
+ qx = d3_chart_qqQuantiles(n, x.call(this, d, i)),
17
+ qy = d3_chart_qqQuantiles(n, y.call(this, d, i)),
18
+ xd = domain && domain.call(this, d, i) || [d3.min(qx), d3.max(qx)], // new x-domain
19
+ yd = domain && domain.call(this, d, i) || [d3.min(qy), d3.max(qy)], // new y-domain
20
+ x0, // old x-scale
21
+ y0; // old y-scale
22
+
23
+ // Compute the new x-scale.
24
+ var x1 = d3.scale.linear()
25
+ .domain(xd)
26
+ .range([0, width]);
27
+
28
+ // Compute the new y-scale.
29
+ var y1 = d3.scale.linear()
30
+ .domain(yd)
31
+ .range([height, 0]);
32
+
33
+ // Retrieve the old scales, if this is an update.
34
+ if (this.__chart__) {
35
+ x0 = this.__chart__.x;
36
+ y0 = this.__chart__.y;
37
+ } else {
38
+ x0 = d3.scale.linear().domain([0, Infinity]).range(x1.range());
39
+ y0 = d3.scale.linear().domain([0, Infinity]).range(y1.range());
40
+ }
41
+
42
+ // Stash the new scales.
43
+ this.__chart__ = {x: x1, y: y1};
44
+
45
+ // Update diagonal line.
46
+ var diagonal = g.selectAll("line.diagonal")
47
+ .data([null]);
48
+
49
+ diagonal.enter().append("svg:line")
50
+ .attr("class", "diagonal")
51
+ .attr("x1", x1(yd[0]))
52
+ .attr("y1", y1(xd[0]))
53
+ .attr("x2", x1(yd[1]))
54
+ .attr("y2", y1(xd[1]));
55
+
56
+ diagonal.transition()
57
+ .duration(duration)
58
+ .attr("x1", x1(yd[0]))
59
+ .attr("y1", y1(xd[0]))
60
+ .attr("x2", x1(yd[1]))
61
+ .attr("y2", y1(xd[1]));
62
+
63
+ // Update quantile plots.
64
+ var circle = g.selectAll("circle")
65
+ .data(d3.range(n).map(function(i) {
66
+ return {x: qx[i], y: qy[i]};
67
+ }));
68
+
69
+ circle.enter().append("svg:circle")
70
+ .attr("class", "quantile")
71
+ .attr("r", 4.5)
72
+ .attr("cx", function(d) { return x0(d.x); })
73
+ .attr("cy", function(d) { return y0(d.y); })
74
+ .style("opacity", 1e-6)
75
+ .transition()
76
+ .duration(duration)
77
+ .attr("cx", function(d) { return x1(d.x); })
78
+ .attr("cy", function(d) { return y1(d.y); })
79
+ .style("opacity", 1);
80
+
81
+ circle.transition()
82
+ .duration(duration)
83
+ .attr("cx", function(d) { return x1(d.x); })
84
+ .attr("cy", function(d) { return y1(d.y); })
85
+ .style("opacity", 1);
86
+
87
+ circle.exit().transition()
88
+ .duration(duration)
89
+ .attr("cx", function(d) { return x1(d.x); })
90
+ .attr("cy", function(d) { return y1(d.y); })
91
+ .style("opacity", 1e-6)
92
+ .remove();
93
+
94
+ var xformat = tickFormat || x1.tickFormat(4),
95
+ yformat = tickFormat || y1.tickFormat(4),
96
+ tx = function(d) { return "translate(" + x1(d) + "," + height + ")"; },
97
+ ty = function(d) { return "translate(0," + y1(d) + ")"; };
98
+
99
+ // Update x-ticks.
100
+ var xtick = g.selectAll("g.x.tick")
101
+ .data(x1.ticks(4), function(d) {
102
+ return this.textContent || xformat(d);
103
+ });
104
+
105
+ var xtickEnter = xtick.enter().append("svg:g")
106
+ .attr("class", "x tick")
107
+ .attr("transform", function(d) { return "translate(" + x0(d) + "," + height + ")"; })
108
+ .style("opacity", 1e-6);
109
+
110
+ xtickEnter.append("svg:line")
111
+ .attr("y1", 0)
112
+ .attr("y2", -6);
113
+
114
+ xtickEnter.append("svg:text")
115
+ .attr("text-anchor", "middle")
116
+ .attr("dy", "1em")
117
+ .text(xformat);
118
+
119
+ // Transition the entering ticks to the new scale, x1.
120
+ xtickEnter.transition()
121
+ .duration(duration)
122
+ .attr("transform", tx)
123
+ .style("opacity", 1);
124
+
125
+ // Transition the updating ticks to the new scale, x1.
126
+ xtick.transition()
127
+ .duration(duration)
128
+ .attr("transform", tx)
129
+ .style("opacity", 1);
130
+
131
+ // Transition the exiting ticks to the new scale, x1.
132
+ xtick.exit().transition()
133
+ .duration(duration)
134
+ .attr("transform", tx)
135
+ .style("opacity", 1e-6)
136
+ .remove();
137
+
138
+ // Update ticks.
139
+ var ytick = g.selectAll("g.y.tick")
140
+ .data(y1.ticks(4), function(d) {
141
+ return this.textContent || yformat(d);
142
+ });
143
+
144
+ var ytickEnter = ytick.enter().append("svg:g")
145
+ .attr("class", "y tick")
146
+ .attr("transform", function(d) { return "translate(0," + y0(d) + ")"; })
147
+ .style("opacity", 1e-6);
148
+
149
+ ytickEnter.append("svg:line")
150
+ .attr("x1", 0)
151
+ .attr("x2", 6);
152
+
153
+ ytickEnter.append("svg:text")
154
+ .attr("text-anchor", "end")
155
+ .attr("dx", "-.5em")
156
+ .attr("dy", ".3em")
157
+ .text(yformat);
158
+
159
+ // Transition the entering ticks to the new scale, y1.
160
+ ytickEnter.transition()
161
+ .duration(duration)
162
+ .attr("transform", ty)
163
+ .style("opacity", 1);
164
+
165
+ // Transition the updating ticks to the new scale, y1.
166
+ ytick.transition()
167
+ .duration(duration)
168
+ .attr("transform", ty)
169
+ .style("opacity", 1);
170
+
171
+ // Transition the exiting ticks to the new scale, y1.
172
+ ytick.exit().transition()
173
+ .duration(duration)
174
+ .attr("transform", ty)
175
+ .style("opacity", 1e-6)
176
+ .remove();
177
+ });
178
+ }
179
+
180
+ qq.width = function(x) {
181
+ if (!arguments.length) return width;
182
+ width = x;
183
+ return qq;
184
+ };
185
+
186
+ qq.height = function(x) {
187
+ if (!arguments.length) return height;
188
+ height = x;
189
+ return qq;
190
+ };
191
+
192
+ qq.duration = function(x) {
193
+ if (!arguments.length) return duration;
194
+ duration = x;
195
+ return qq;
196
+ };
197
+
198
+ qq.domain = function(x) {
199
+ if (!arguments.length) return domain;
200
+ domain = x == null ? x : d3.functor(x);
201
+ return qq;
202
+ };
203
+
204
+ qq.count = function(z) {
205
+ if (!arguments.length) return n;
206
+ n = z;
207
+ return qq;
208
+ };
209
+
210
+ qq.x = function(z) {
211
+ if (!arguments.length) return x;
212
+ x = z;
213
+ return qq;
214
+ };
215
+
216
+ qq.y = function(z) {
217
+ if (!arguments.length) return y;
218
+ y = z;
219
+ return qq;
220
+ };
221
+
222
+ qq.tickFormat = function(x) {
223
+ if (!arguments.length) return tickFormat;
224
+ tickFormat = x;
225
+ return qq;
226
+ };
227
+
228
+ return qq;
229
+ };
230
+
231
+ function d3_chart_qqQuantiles(n, values) {
232
+ var m = values.length - 1;
233
+ values = values.slice().sort(d3.ascending);
234
+ return d3.range(n).map(function(i) {
235
+ return values[~~(i * m / n)];
236
+ });
237
+ }
238
+
239
+ function d3_chart_qqX(d) {
240
+ return d.x;
241
+ }
242
+
243
+ function d3_chart_qqY(d) {
244
+ return d.y;
245
+ }