Instantly share code, notes, and snippets.

# mbostock/.block

Last active February 26, 2019 22:40
Show Gist options
• Save mbostock/4061502 to your computer and use it in GitHub Desktop.
Box Plots
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

A box-and-whisker plot uses simple glyphs that summarize a quantitative distribution with five standard statistics: the smallest value, lower quartile, median, upper quartile, and largest value. This summary approach allows the viewer to easily recognize differences between distributions. Data from the Michelson–Morley experiment. Implementation contributed by Jason Davies. This example periodically randomizes the values to demonstrate transitions.

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (function() { // Inspired by http://informationandvisualization.de/blog/box-plot d3.box = function() { var width = 1, height = 1, duration = 0, domain = null, value = Number, whiskers = boxWhiskers, quartiles = boxQuartiles, tickFormat = null; // For each small multiple… function box(g) { g.each(function(d, i) { d = d.map(value).sort(d3.ascending); var g = d3.select(this), n = d.length, min = d[0], max = d[n - 1]; // Compute quartiles. Must return exactly 3 elements. var quartileData = d.quartiles = quartiles(d); // Compute whiskers. Must return exactly 2 elements, or null. var whiskerIndices = whiskers && whiskers.call(this, d, i), whiskerData = whiskerIndices && whiskerIndices.map(function(i) { return d[i]; }); // Compute outliers. If no whiskers are specified, all data are "outliers". // We compute the outliers as indices, so that we can join across transitions! var outlierIndices = whiskerIndices ? d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n)) : d3.range(n); // Compute the new x-scale. var x1 = d3.scale.linear() .domain(domain && domain.call(this, d, i) || [min, max]) .range([height, 0]); // Retrieve the old x-scale, if this is an update. var x0 = this.__chart__ || d3.scale.linear() .domain([0, Infinity]) .range(x1.range()); // Stash the new scale. this.__chart__ = x1; // Note: the box, median, and box tick elements are fixed in number, // so we only have to handle enter and update. In contrast, the outliers // and other elements are variable, so we need to exit them! Variable // elements also fade in and out. // Update center line: the vertical line spanning the whiskers. var center = g.selectAll("line.center") .data(whiskerData ? [whiskerData] : []); center.enter().insert("line", "rect") .attr("class", "center") .attr("x1", width / 2) .attr("y1", function(d) { return x0(d[0]); }) .attr("x2", width / 2) .attr("y2", function(d) { return x0(d[1]); }) .style("opacity", 1e-6) .transition() .duration(duration) .style("opacity", 1) .attr("y1", function(d) { return x1(d[0]); }) .attr("y2", function(d) { return x1(d[1]); }); center.transition() .duration(duration) .style("opacity", 1) .attr("y1", function(d) { return x1(d[0]); }) .attr("y2", function(d) { return x1(d[1]); }); center.exit().transition() .duration(duration) .style("opacity", 1e-6) .attr("y1", function(d) { return x1(d[0]); }) .attr("y2", function(d) { return x1(d[1]); }) .remove(); // Update innerquartile box. var box = g.selectAll("rect.box") .data([quartileData]); box.enter().append("rect") .attr("class", "box") .attr("x", 0) .attr("y", function(d) { return x0(d[2]); }) .attr("width", width) .attr("height", function(d) { return x0(d[0]) - x0(d[2]); }) .transition() .duration(duration) .attr("y", function(d) { return x1(d[2]); }) .attr("height", function(d) { return x1(d[0]) - x1(d[2]); }); box.transition() .duration(duration) .attr("y", function(d) { return x1(d[2]); }) .attr("height", function(d) { return x1(d[0]) - x1(d[2]); }); // Update median line. var medianLine = g.selectAll("line.median") .data([quartileData[1]]); medianLine.enter().append("line") .attr("class", "median") .attr("x1", 0) .attr("y1", x0) .attr("x2", width) .attr("y2", x0) .transition() .duration(duration) .attr("y1", x1) .attr("y2", x1); medianLine.transition() .duration(duration) .attr("y1", x1) .attr("y2", x1); // Update whiskers. var whisker = g.selectAll("line.whisker") .data(whiskerData || []); whisker.enter().insert("line", "circle, text") .attr("class", "whisker") .attr("x1", 0) .attr("y1", x0) .attr("x2", width) .attr("y2", x0) .style("opacity", 1e-6) .transition() .duration(duration) .attr("y1", x1) .attr("y2", x1) .style("opacity", 1); whisker.transition() .duration(duration) .attr("y1", x1) .attr("y2", x1) .style("opacity", 1); whisker.exit().transition() .duration(duration) .attr("y1", x1) .attr("y2", x1) .style("opacity", 1e-6) .remove(); // Update outliers. var outlier = g.selectAll("circle.outlier") .data(outlierIndices, Number); outlier.enter().insert("circle", "text") .attr("class", "outlier") .attr("r", 5) .attr("cx", width / 2) .attr("cy", function(i) { return x0(d[i]); }) .style("opacity", 1e-6) .transition() .duration(duration) .attr("cy", function(i) { return x1(d[i]); }) .style("opacity", 1); outlier.transition() .duration(duration) .attr("cy", function(i) { return x1(d[i]); }) .style("opacity", 1); outlier.exit().transition() .duration(duration) .attr("cy", function(i) { return x1(d[i]); }) .style("opacity", 1e-6) .remove(); // Compute the tick format. var format = tickFormat || x1.tickFormat(8); // Update box ticks. var boxTick = g.selectAll("text.box") .data(quartileData); boxTick.enter().append("text") .attr("class", "box") .attr("dy", ".3em") .attr("dx", function(d, i) { return i & 1 ? 6 : -6 }) .attr("x", function(d, i) { return i & 1 ? width : 0 }) .attr("y", x0) .attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; }) .text(format) .transition() .duration(duration) .attr("y", x1); boxTick.transition() .duration(duration) .text(format) .attr("y", x1); // Update whisker ticks. These are handled separately from the box // ticks because they may or may not exist, and we want don't want // to join box ticks pre-transition with whisker ticks post-. var whiskerTick = g.selectAll("text.whisker") .data(whiskerData || []); whiskerTick.enter().append("text") .attr("class", "whisker") .attr("dy", ".3em") .attr("dx", 6) .attr("x", width) .attr("y", x0) .text(format) .style("opacity", 1e-6) .transition() .duration(duration) .attr("y", x1) .style("opacity", 1); whiskerTick.transition() .duration(duration) .text(format) .attr("y", x1) .style("opacity", 1); whiskerTick.exit().transition() .duration(duration) .attr("y", x1) .style("opacity", 1e-6) .remove(); }); d3.timer.flush(); } box.width = function(x) { if (!arguments.length) return width; width = x; return box; }; box.height = function(x) { if (!arguments.length) return height; height = x; return box; }; box.tickFormat = function(x) { if (!arguments.length) return tickFormat; tickFormat = x; return box; }; box.duration = function(x) { if (!arguments.length) return duration; duration = x; return box; }; box.domain = function(x) { if (!arguments.length) return domain; domain = x == null ? x : d3.functor(x); return box; }; box.value = function(x) { if (!arguments.length) return value; value = x; return box; }; box.whiskers = function(x) { if (!arguments.length) return whiskers; whiskers = x; return box; }; box.quartiles = function(x) { if (!arguments.length) return quartiles; quartiles = x; return box; }; return box; }; function boxWhiskers(d) { return [0, d.length - 1]; } function boxQuartiles(d) { return [ d3.quantile(d, .25), d3.quantile(d, .5), d3.quantile(d, .75) ]; } })();
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Expt Run Speed 1 1 850 1 2 740 1 3 900 1 4 1070 1 5 930 1 6 850 1 7 950 1 8 980 1 9 980 1 10 880 1 11 1000 1 12 980 1 13 930 1 14 650 1 15 760 1 16 810 1 17 1000 1 18 1000 1 19 960 1 20 960 2 1 960 2 2 940 2 3 960 2 4 940 2 5 880 2 6 800 2 7 850 2 8 880 2 9 900 2 10 840 2 11 830 2 12 790 2 13 810 2 14 880 2 15 880 2 16 830 2 17 800 2 18 790 2 19 760 2 20 800 3 1 880 3 2 880 3 3 880 3 4 860 3 5 720 3 6 720 3 7 620 3 8 860 3 9 970 3 10 950 3 11 880 3 12 910 3 13 850 3 14 870 3 15 840 3 16 840 3 17 850 3 18 840 3 19 840 3 20 840 4 1 890 4 2 810 4 3 810 4 4 820 4 5 800 4 6 770 4 7 760 4 8 740 4 9 750 4 10 760 4 11 910 4 12 920 4 13 890 4 14 860 4 15 880 4 16 720 4 17 840 4 18 850 4 19 850 4 20 780 5 1 890 5 2 840 5 3 780 5 4 810 5 5 760 5 6 810 5 7 790 5 8 810 5 9 820 5 10 850 5 11 870 5 12 870 5 13 810 5 14 740 5 15 810 5 16 940 5 17 950 5 18 800 5 19 810 5 20 870

### salok64 commented Oct 4, 2015

d3 box plot showing utf-8 problem. i am already add utf -8 in meta. still i am facing this problem, i m using djnago frameworks

### MFlores2021 commented Sep 19, 2016

Where is this for d3.v4?

### SATHYARAJU commented Jul 13, 2017

Where can I find this for d3.v4 version?