d3_rails 2.7.4 → 2.7.5.v2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.DS_Store +0 -0
- data/README.md +16 -2
- data/lib/d3_rails/version.rb +1 -1
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/javascripts/LICENSE +12 -13
- data/vendor/assets/javascripts/chart/box.js +297 -0
- data/vendor/assets/javascripts/chart/bullet.js +237 -0
- data/vendor/assets/javascripts/chart/chart.js +1 -0
- data/vendor/assets/javascripts/chart/horizon.js +203 -0
- data/vendor/assets/javascripts/chart/qq.js +245 -0
- data/vendor/assets/javascripts/d3.chart.js +0 -0
- data/vendor/assets/javascripts/d3.geo.js +0 -0
- data/vendor/assets/javascripts/d3.geom.js +0 -0
- data/vendor/assets/javascripts/d3.js +21 -18
- data/vendor/assets/javascripts/d3.layout.js +5 -4
- data/vendor/assets/javascripts/d3.time.js +0 -0
- data/vendor/assets/javascripts/d3_chart_module.js +1 -0
- data/vendor/assets/javascripts/d3_csv.js +0 -0
- data/vendor/assets/javascripts/d3_rails.js +1 -1
- metadata +18 -12
- data/vendor/assets/javascripts/package.json +0 -33
@@ -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
|
+
}
|