Demonstration of some the guidelines proposed by William S. Cleveland and Robert McGill, and how colour and area are useful in displays of large amounts of datapoints.
William S. Cleveland and Robert McGill, Graphical Perception: Theory, Experimentation, and Application to the Development of Graphical Methods, 1984
Paper: http://www.cs.ubc.ca/~tmm/courses/cpsc533c-04-spr/readings/cleveland.pdf
A good brief overview is available on flowingdata: http://flowingdata.com/2010/03/20/graphical-perception-learn-the-fundamentals-first/
xxxxxxxxxx
<html>
<head>
<title>Cleveland and McGill</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
rect {
cursor: pointer ;
}
</style>
</head>
<body>
<h1>Elementary perceptual tasks</h1>
<br>
<div id='viz'></div>
<h2>Cleveland and McGill, 1984</h2>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var data = [ 10, 5, 8];
var width = 1000,
height = 400
noOfCharts = 4;
var chartWidth = width / noOfCharts,
barwidth = chartWidth/data.length - 20,
barPadding = 20;
var squareWidth = 10;
var svg = d3.select("#viz").append("svg:svg")
.attr("width", width)
.attr("height", height);
var y = d3.scale.linear()
.range([height, 0])
.domain([0, d3.max(data, function(d) { return d; })]);
/*var x = d3.scale.linear()
.range(0, chartWidth);*/
var clickBoard = svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.style("fill", "white")
.on("click", change);
var squares = svg.selectAll("squares")
.data(d3.range(250).map(function() {
return {
x: width * Math.random(),
y: height * Math.random(),
dx: Math.random() - .5,
dy: Math.random() - .5,
v: Math.random() * 10
};
}))
.enter().append("svg:rect")
.attr("width", squareWidth)
.attr("height", squareWidth)
.attr("fill-opacity", 0)
.attr("x", function(d) { d.x += d.dx; if (d.x > width) d.x -= width; else if (d.x < 0) d.x += width; return d.x; })
.attr("y", function(d) { d.y += d.dy; if (d.y > height) d.y -= height; else if (d.y < 0) d.y += height; return d.y; });
//////////////////////
shadingchartPosition = (chartWidth * 1) - chartWidth;
var color = d3.scale.ordinal()
.range(['#f7fbff','#deebf7','#c6dbef','#9ecae1','#6baed6','#4292c6','#2171b5','#08519c','#08306b'])
.domain([2,3,4,5,6,7,8,9,10]);
var shadingBars = svg.selectAll(".shadingBars")
.data(data)
.enter()
.append("svg:rect")
.attr("class", "shadingBars")
.attr("x", function (d, i) { return shadingchartPosition + (i * barwidth) ; } )
.attr("y", function(d) { return y(10); })
.style("fill", function (d) { return color(d); } )
.attr("width", barwidth - barPadding)
.attr("height", function(d) { return height - y(10); });
//////////////////////
areaChartPosition = (chartWidth * 2) - chartWidth;
var circleArea = d3.scale.sqrt().domain([2, 10]).range([5, 40])
var areaCircles = svg.selectAll(".areaCircles")
.data(data)
.enter()
.append("svg:circle")
.attr("class", "areaCircles")
.attr("cx", areaChartPosition + (chartWidth/2) )
.attr("cy", function (d, i) {return (i * height/4) + 60 ;} )
.attr("r", function (d) { return circleArea(d) ;} ) ;
//////////////////////
pathchartPosition = (chartWidth * 3) - chartWidth;
var paths = svg.selectAll(".paths")
.data(data)
.enter()
.append("svg:path")
.attr("d", function (d, i) {
var startX = pathchartPosition + 20;
var startY = (height - 20) - ((height/data.length) * i);
var endX = pathchartPosition + chartWidth - 40;
var endY = startY - 7*d;
var path = "";
return path = "M" + startX + "," + startY + "L" + endX + "," + endY;
})
.attr("stroke", "black")
.attr("stroke-width",5 )
.attr("fill", "none");;
//////////////////////
barchartPosition = (chartWidth * 4) - chartWidth;
var bars = svg.selectAll(".barchart")
.data(data)
.enter()
.append("svg:rect")
.attr("class", "barchart")
.attr("x", function (d, i) { return barchartPosition + (i * barwidth) ; } )
.attr("y", function(d) { return y(d); })
.attr("width", barwidth - barPadding)
.attr("height", function(d) { return height - y(d); });
//////////////////////
var changeID = 1;
var t = 1500;
var smallScale = d3.scale.linear()
.range([0, 30])
.domain([0, d3.max(data, function(d) { return d; })]);
function change() {
switch (true)
{
case ( changeID === 1):
paths
.transition().duration(t)
.style("stroke-opacity", 0);
areaCircles
.transition().duration(t)
.style("fill-opacity", 0);
break;
case ( changeID === 2):
shadingBars
.transition().duration(t)
.attr("width", squareWidth)
.attr("height", squareWidth)
.style("fill", "black")
.style("fill-opacity", 0.8);
bars
.transition().duration(t)
.attr("width", squareWidth)
.attr("height", squareWidth)
.style("fill-opacity", 0.8);
squares
.transition().duration(t)
.delay(t)
.style("fill-opacity", 0.8);
break;
case ( changeID === 3):
shadingBars
.transition().duration(t)
.attr("height", function (d) { return smallScale(d) ;} );
bars
.transition().duration(t)
.attr("height", function (d) { return smallScale(d) ;} );
squares
.transition().duration(t)
.attr("height", function (d) { return smallScale(d.v) ;} );
break;
case ( changeID === 4):
shadingBars
.transition().duration(t)
.attr("height", squareWidth)
.style("fill", function (d) { return color(Math.round(d)) ; } );
bars
.transition().duration(t)
.attr("height", squareWidth)
.style("fill", function (d) { return color(Math.round(d)) ; } );
squares
.transition().duration(t)
.attr("height", squareWidth)
.style("fill", function (d) { return color(Math.round(d.v)) ; } );
break;
case ( changeID === 5):
shadingBars
.transition().duration(t)
.attr("height", function (d) { return smallScale(d) ;} )
.attr("width", function (d) { return smallScale(d) ;} );
bars
.transition().duration(t)
.attr("height", function (d) { return smallScale(d) ;} )
.attr("width", function (d) { return smallScale(d) ;} );
squares
.transition().duration(t)
.attr("height", function (d) { return smallScale(d.v) ;} )
.attr("width", function (d) { return smallScale(d.v) ;} );
break;
}
changeID++;
};
</script>
</body>
</html>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js