block by harrystevens e888c9372c6b3f5006f261e3f7db6ba7

Box and Whisker

Full Screen

An implementation of a box-and-whisker plot in D3.js. From Mike Bostock’s similar block:

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.

index.html

<!DOCTYPE html>
<html>
	<head>
		<style>
		body {
			font-family: "Helvetica Neue", sans-serif;
			margin: 0;
		}

		.box, .line, .line-dotted {
			stroke: #000;
			stroke-width: 1.5px;
		}
		.box {
			fill: #fff;
		}
		.line-dotted {
			stroke-dasharray: 3,3;
		}

		.text {
			font-size: .8em;
		}
		.text.three, .text.one {
			text-anchor: end;
		}

		.label {
			text-anchor: middle;
		}
		</style>
	</head>
	<body>
		<div id="viz"></div>

		<script src="https://d3js.org/d3.v4.min.js"></script>
		<script src="https://unpkg.com/d3-marcon/build/d3-marcon.min.js"></script>
		<script src="https://unpkg.com/jeezy/lib/jeezy.min.js"></script>
		<script>
			var letters = "abcdefghij".split("");

			var setup = d3.marcon().top(30).bottom(10).left(10).right(10).width(window.innerWidth).height(window.innerHeight);
			setup.render();
			var width = setup.innerWidth(),
				height = setup.innerHeight(),
				svg = setup.svg();

			var x = d3.scaleBand().rangeRound([0, width]).padding(0.8).domain(letters);
			var y = d3.scaleLinear().range([height, 0]);

			var dy = 6;

			function generate_data(){
				
				return letters.map(function(d){

					return {
						id: d,
						max: jz.num.randBetween(900, 1000),
						min: jz.num.randBetween(0, 100),
						three: jz.num.randBetween(650, 850),
						median: jz.num.randBetween(400, 600),
						one: jz.num.randBetween(150, 350)			
					}

				});

			}

			draw(generate_data());

			d3.interval(function(){
				draw(generate_data());
			}, 2000);

			function draw(data){

				// update the y domain
				y.domain([d3.min(data, function(d){ return d.min; }), d3.max(data, function(d){ return d.max; })]);

				// JOIN
				var box = svg.selectAll(".box")
					.data(data, function(d, i){ return d.id; });

				var line_dotted_top = svg.selectAll(".line-dotted.top")
					.data(data, function(d, i){ return d.id; });

				var line_dotted_bottom = svg.selectAll(".line-dotted.bottom")
					.data(data, function(d){ return d.id; });

				var line_top = svg.selectAll(".line.top")
					.data(data, function(d){ return d.id; });

				var line_bottom = svg.selectAll(".line.bottom")
					.data(data, function(d){ return d.id; });

				var line_med = svg.selectAll(".line.med")
					.data(data, function(d){ return d.id; });

				var text_top = svg.selectAll(".text.top")
					.data(data, function(d){ return d.id; });

				var text_75 = svg.selectAll(".text.three")
					.data(data, function(d){ return d.id; });

				var text_med = svg.selectAll(".text.med")
					.data(data, function(d){ return d.id; });

				var text_25 = svg.selectAll(".text.one")
					.data(data, function(d){ return d.id; });

				var text_bottom = svg.selectAll(".text.bottom")
					.data(data, function(d){ return d.id; });

				var label = svg.selectAll(".label")
					.data(data, function(d){ return d.id; })

				// UPDATE
				box
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y", function(d){ return y(d.three); })
						.attr("height", function(d){ return y(d.one) - y(d.three); });

				line_dotted_top
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y1", function(d){ return y(d.three); })
						.attr("y2", function(d){ return y(d.max); });

				line_dotted_bottom
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y1", function(d){ return y(d.one); })
						.attr("y2", function(d){ return y(d.min); });

				line_top
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y1", function(d){ return y(d.max); })
						.attr("y2", function(d){ return y(d.max); });

				line_med
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y1", function(d){ return y(d.median); })
						.attr("y2", function(d){ return y(d.median); });

				line_bottom
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y1", function(d){ return y(d.min); })
						.attr("y2", function(d){ return y(d.min); });

				text_top
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y", function(d){ return y(d.max); })
						.text(function(d){ return d.max; });

				text_75
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y", function(d){ return y(d.three); })
						.text(function(d){ return d.three; });

				text_med
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y", function(d){ return y(d.median); })
						.text(function(d){ return d.median; });

				text_25
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y", function(d){ return y(d.one); })
						.text(function(d){ return d.one; });

				text_bottom
					.transition().delay(function(d, i){ return i * 200; })
						.attr("y", function(d){ return y(d.min); })
						.text(function(d){ return d.min; });

				// ENTER
				box.enter().append("rect")
						.attr("class", "box")
						.attr("x", function(d){ return x(d.id); })
						.attr("y", function(d){ return y(d.three); })
						.attr("width", x.bandwidth())
						.attr("height", function(d){ return y(d.one) - y(d.three); });

				line_dotted_top.enter().append("line")
						.attr("class", "line-dotted top")
						.attr("x1", function(d){ return x(d.id) + x.bandwidth() / 2; })
						.attr("x2", function(d){ return x(d.id) + x.bandwidth() / 2; })
						.attr("y1", function(d){ return y(d.three); })
						.attr("y2", function(d){ return y(d.max); });

				line_dotted_bottom.enter().append("line")
						.attr("class", "line-dotted bottom")
						.attr("x1", function(d){ return x(d.id) + x.bandwidth() / 2; })
						.attr("x2", function(d){ return x(d.id) + x.bandwidth() / 2; })
						.attr("y1", function(d){ return y(d.one); })
						.attr("y2", function(d){ return y(d.min); });

				line_top.enter().append("line")
						.attr("class", "line top")
						.attr("x1", function(d){ return x(d.id); })
						.attr("x2", function(d){ return x(d.id) + x.bandwidth(); })
						.attr("y1", function(d){ return y(d.max); })
						.attr("y2", function(d){ return y(d.max); });

				line_med.enter().append("line")
					.attr("class", "line med")
						.attr("x1", function(d){ return x(d.id); })
						.attr("x2", function(d){ return x(d.id) + x.bandwidth(); })
						.attr("y1", function(d){ return y(d.median); })
						.attr("y2", function(d){ return y(d.median); });

				line_bottom.enter().append("line")
						.attr("class", "line bottom")
						.attr("x1", function(d){ return x(d.id); })
						.attr("x2", function(d){ return x(d.id) + x.bandwidth(); })
						.attr("y1", function(d){ return y(d.min); })
						.attr("y2", function(d){ return y(d.min); });

				text_top.enter().append("text")
						.attr("class", "text top")
						.attr("x", function(d){ return x(d.id) + x.bandwidth() + dy; })
						.attr("y", function(d){ return y(d.max); })
						.attr("dy", dy)
						.text(function(d){ return d.max; });

				text_75.enter().append("text")
						.attr("class", "text three")
						.attr("x", function(d){ return x(d.id) - dy; })
						.attr("y", function(d){ return y(d.three); })
						.attr("dy", dy)
						.text(function(d){ return d.three; });

				text_med.enter().append("text")
						.attr("class", "text med")
						.attr("x", function(d){ return x(d.id) + x.bandwidth() + dy; })
						.attr("y", function(d){ return y(d.median); })
						.attr("dy", dy)
						.text(function(d){ return d.median; });

				text_25.enter().append("text")
						.attr("class", "text one")
						.attr("x", function(d){ return x(d.id) - dy; })
						.attr("y", function(d){ return y(d.one); })
						.attr("dy", dy)
					.text(function(d){ return d.one; });

				text_bottom.enter().append("text")
						.attr("class", "text bottom")
						.attr("x", function(d){ return x(d.id) + x.bandwidth() + dy; })
						.attr("y", function(d){ return y(d.min); })
						.attr("dy", dy)
						.text(function(d){ return d.min; });

				label.enter().append("text")
					.attr("class", "label")
					.attr("x", function(d){ return x(d.id) + x.bandwidth() / 2; })
					.attr("y", -10)
					.text(function(d){ return d.id; })
			}

		</script>
	</body>
</html>