1
var margin = {top: 10, right: 50, bottom: 20, left: 50},
2
width = 120 - margin.left - margin.right,
3
height = 500 - margin.top - margin.bottom;
13
d3.csv("../data/morley.csv", function(csv) {
16
csv.forEach(function(x) {
21
if (!d) d = data[e] = [s];
27
chart.domain([min, max]);
29
var vis = d3.select("#chart").selectAll("svg")
31
.enter().append("svg")
33
.attr("width", width + margin.left + margin.right)
34
.attr("height", height + margin.bottom + margin.top)
36
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
40
window.transition = function() {
41
vis.datum(randomize).call(chart);
45
function randomize(d) {
46
if (!d.randomizer) d.randomizer = randomizer(d);
47
return d.map(d.randomizer);
50
function randomizer(d) {
51
var k = d3.max(d) * .02;
53
return Math.max(min, Math.min(max, d + k * (Math.random() - .5)));
57
// Returns a function to compute the interquartile range.
59
return function(d, i) {
60
var q1 = d.quartiles[0],
65
while (d[++i] < q1 - iqr);
66
while (d[--j] > q3 + iqr);
71
// Inspired by http://informationandvisualization.de/blog/box-plot
78
whiskers = boxWhiskers,
79
quartiles = boxQuartiles,
82
// For each small multiple…
84
g.each(function(d, i) {
85
d = d.map(value).sort(d3.ascending);
86
var g = d3.select(this),
91
// Compute quartiles. Must return exactly 3 elements.
92
var quartileData = d.quartiles = quartiles(d);
94
// Compute whiskers. Must return exactly 2 elements, or null.
95
var whiskerIndices = whiskers && whiskers.call(this, d, i),
96
whiskerData = whiskerIndices && whiskerIndices.map(function(i) { return d[i]; });
98
// Compute outliers. If no whiskers are specified, all data are "outliers".
99
// We compute the outliers as indices, so that we can join across transitions!
100
var outlierIndices = whiskerIndices
101
? d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n))
104
// Compute the new x-scale.
105
var x1 = d3.scale.linear()
106
.domain(domain && domain.call(this, d, i) || [min, max])
109
// Retrieve the old x-scale, if this is an update.
110
var x0 = this.__chart__ || d3.scale.linear()
111
.domain([0, Infinity])
114
// Stash the new scale.
117
// Note: the box, median, and box tick elements are fixed in number,
118
// so we only have to handle enter and update. In contrast, the outliers
119
// and other elements are variable, so we need to exit them! Variable
120
// elements also fade in and out.
122
// Update center line: the vertical line spanning the whiskers.
123
var center = g.selectAll("line.center")
124
.data(whiskerData ? [whiskerData] : []);
126
center.enter().insert("svg:line", "rect")
127
.attr("class", "center")
128
.attr("x1", width / 2)
129
.attr("y1", function(d) { return x0(d[0]); })
130
.attr("x2", width / 2)
131
.attr("y2", function(d) { return x0(d[1]); })
132
.style("opacity", 1e-6)
136
.attr("y1", function(d) { return x1(d[0]); })
137
.attr("y2", function(d) { return x1(d[1]); });
142
.attr("y1", function(d) { return x1(d[0]); })
143
.attr("y2", function(d) { return x1(d[1]); });
145
center.exit().transition()
147
.style("opacity", 1e-6)
148
.attr("y1", function(d) { return x1(d[0]); })
149
.attr("y2", function(d) { return x1(d[1]); })
152
// Update innerquartile box.
153
var box = g.selectAll("rect.box")
154
.data([quartileData]);
156
box.enter().append("svg:rect")
157
.attr("class", "box")
159
.attr("y", function(d) { return x0(d[2]); })
160
.attr("width", width)
161
.attr("height", function(d) { return x0(d[0]) - x0(d[2]); })
164
.attr("y", function(d) { return x1(d[2]); })
165
.attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
169
.attr("y", function(d) { return x1(d[2]); })
170
.attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
172
// Update median line.
173
var medianLine = g.selectAll("line.median")
174
.data([quartileData[1]]);
176
medianLine.enter().append("svg:line")
177
.attr("class", "median")
187
medianLine.transition()
193
var whisker = g.selectAll("line.whisker")
194
.data(whiskerData || []);
196
whisker.enter().insert("svg:line", "circle, text")
197
.attr("class", "whisker")
202
.style("opacity", 1e-6)
207
.style("opacity", 1);
213
.style("opacity", 1);
215
whisker.exit().transition()
219
.style("opacity", 1e-6)
223
var outlier = g.selectAll("circle.outlier")
224
.data(outlierIndices, Number);
226
outlier.enter().insert("svg:circle", "text")
227
.attr("class", "outlier")
229
.attr("cx", width / 2)
230
.attr("cy", function(i) { return x0(d[i]); })
231
.style("opacity", 1e-6)
234
.attr("cy", function(i) { return x1(d[i]); })
235
.style("opacity", 1);
239
.attr("cy", function(i) { return x1(d[i]); })
240
.style("opacity", 1);
242
outlier.exit().transition()
244
.attr("cy", function(i) { return x1(d[i]); })
245
.style("opacity", 1e-6)
248
// Compute the tick format.
249
var format = tickFormat || x1.tickFormat(8);
252
var boxTick = g.selectAll("text.box")
255
boxTick.enter().append("svg:text")
256
.attr("class", "box")
258
.attr("dx", function(d, i) { return i & 1 ? 6 : -6 })
259
.attr("x", function(d, i) { return i & 1 ? width : 0 })
261
.attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; })
272
// Update whisker ticks. These are handled separately from the box
273
// ticks because they may or may not exist, and we want don't want
274
// to join box ticks pre-transition with whisker ticks post-.
275
var whiskerTick = g.selectAll("text.whisker")
276
.data(whiskerData || []);
278
whiskerTick.enter().append("svg:text")
279
.attr("class", "whisker")
285
.style("opacity", 1e-6)
289
.style("opacity", 1);
291
whiskerTick.transition()
295
.style("opacity", 1);
297
whiskerTick.exit().transition()
300
.style("opacity", 1e-6)
306
box.width = function(x) {
307
if (!arguments.length) return width;
312
box.height = function(x) {
313
if (!arguments.length) return height;
318
box.tickFormat = function(x) {
319
if (!arguments.length) return tickFormat;
324
box.duration = function(x) {
325
if (!arguments.length) return duration;
330
box.domain = function(x) {
331
if (!arguments.length) return domain;
332
domain = x == null ? x : d3.functor(x);
336
box.value = function(x) {
337
if (!arguments.length) return value;
342
box.whiskers = function(x) {
343
if (!arguments.length) return whiskers;
348
box.quartiles = function(x) {
349
if (!arguments.length) return quartiles;
357
function boxWhiskers(d) {
358
return [0, d.length - 1];
361
function boxQuartiles(d) {