A hexbin correlation matrix (or pairs plot, if you prefer)
This iteration experiments with a white background and a color scale that starts at a faint shade of gray.
we declare a scale colors
for picking the theme colors of the small charts and assign the faintGray
hex color to an eponymous variable:
colors = d3.scale.ordinal()
.range(["#827abf", "#f62150", "#6f89b6", "#f5e0b7", "#5b1e37", "#b9e3c5"]);
var faintGray = "#f0f0f0";
then we declare a different scale helpfully named color
to color each hex on a scale of faint gray to the theme color for the current small chart. We use d3’s handy d3.interpolateLab
L*a*b* color space interpolator.
var color = d3.scale.linear()
.domain([0, d3.max(hexbinData, function(d) {
return d.length;
})])
.range([faintGray, colors(row + col)])
.interpolate(d3.interpolateLab);
This example also adds thin borders to the small multiple plots to distinguish them from the white background of the larger chart area.
Forked from Correlation Matrix VI by micahstubbs
Originally inspired by the Simple Correlation Matrix block from emeeks
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Correlation Matrix VII</title>
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<body>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8" type="text/javascript"></script>
<script src="d3.hexbin.min.js"></script>
<script>
//These attributes could be derived from the data
attributes = ["carat","depth","table","price","x","y","z"];
attributeMatrix = [];
attributes.forEach(function (a, x) {
attributes.forEach(function (b, y) {
//create an n-by-n matrix based on pairs of attributes
attributeMatrix.push({a: a, b: b, x: x, y: y})
})
})
colors = d3.scale.ordinal()
.range(["#827abf", "#f62150", "#6f89b6", "#f5e0b7", "#5b1e37", "#b9e3c5"]);
var faintGray = "#f0f0f0";
d3.select("body")
.append("svg")
.attr("height", 1140)
.attr("width", 1140)
d3.json("diamonds.json", small_scatterplots);
function small_scatterplots(data) {
console.log("data", data);
console.log("attributeMatrix", attributeMatrix);
//format data as numbers
data.forEach(function (d) {
attributes.forEach(function (att) {
d[att] = Number(d[att])
})
})
//create scales dynamically for each attribute's extent
scale = {};
attributes.forEach(function (att) {
scale[att] = d3.scale.linear();
attExtent = d3.extent(data, function (d) {return d[att]});
scale[att].domain(attExtent).range([5,95]);
})
var height = 100;
var width = 100;
var padding = 7;
var rows = attributes.length;
var columns = rows;
console.log('rows', rows);
//bind the matrix array to a grid of g elements
d3.select("svg")
.selectAll("g")
.data(attributeMatrix)
.enter()
.append("g")
.attr("transform", function (d) {
return "translate(" +
((d.x * (width + padding)) + padding) + "," +
((d.y * (height + padding)) + padding) +
")"
});
////////////////////////////////////////////////////////////
// setup the hexbin layout
var hexbin = d3.hexbin()
.size([width, height])
.radius(5);
var x = d3.scale.identity()
.domain([0, width]);
var y = d3.scale.linear()
.domain([0, height])
.range([height, 0]);
////////////////////////////////////////////////////////////
// draw the grid of small multiples charts
d3.selectAll("g")
.each(function (matrix, i) {
//index i is only used for coloring
var row = Math.floor(i % rows);
var col = Math.floor(i / rows);
//background/border
d3.select(this).append("rect")
.style("fill", "white")
.style("stroke", "silver")
.style("stroke-width", 1)
.attr("height", height)
.attr("width", width);
// if we are comparing an attribute with itself
if (matrix.a === matrix.b) {
// show a label
d3.select(this)
.append("text")
.attr("x", 50)
.style("text-anchor", "middle")
.attr("y", 50)
.style("font-family", "Roboto")
.style("font-weight", 400)
.text(matrix.a)
} else {
d3.select(this).select("rect")
.style("fill", "white")
.style("stroke", "silver");
/*
// draw scatterplot points
d3.select(this).selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 2)
.style("fill", colors(row + col))
.attr("cx", function (d) {return scale[matrix.a](d[matrix.a])})
.attr("cy", function (d) {return height - scale[matrix.b](d[matrix.b])})
*/
////////////////////////////////////////////////////////////
// draw hexbin scatterplot
// create the points for the hexbin layout
var points = data.map(function(d) {
return [
scale[matrix.a](d[matrix.a]),
height - scale[matrix.b](d[matrix.b])
];
})
var hexbinData = hexbin(points);
var color = d3.scale.linear()
.domain([0, d3.max(hexbinData, function(d) {
return d.length;
})])
.range([faintGray, colors(row + col)])
.interpolate(d3.interpolateLab);
d3.select(this).append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("class", "mesh")
.attr("width", width)
.attr("height", height);
d3.select(this)
.append("g")
.attr("clip-path", "url(#clip)")
.selectAll(".hexagon")
.data(hexbinData)
.enter().append("path")
.attr("class", "hexagon")
.attr("d", hexbin.hexagon())
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.style("fill", function(d) {
return color(d.length)
})
.style("stroke", faintGray);
}
})
}
</script>
</body>
</html>
!function(){d3.hexbin=function(){function u(n){var r={};return n.forEach(function(n,t){var a=s.call(u,n,t)/o,e=Math.round(a),c=h.call(u,n,t)/i-(1&e?.5:0),f=Math.round(c),l=a-e;if(3*Math.abs(l)>1){var v=c-f,g=f+(f>c?-1:1)/2,m=e+(e>a?-1:1),M=c-g,d=a-m;v*v+l*l>M*M+d*d&&(f=g+(1&e?1:-1)/2,e=m)}var j=f+"-"+e,p=r[j];p?p.push(n):(p=r[j]=[n],p.i=f,p.j=e,p.x=(f+(1&e?.5:0))*i,p.y=e*o)}),d3.values(r)}function a(r){var t=0,u=0;return n.map(function(n){var a=Math.sin(n)*r,e=-Math.cos(n)*r,i=a-t,o=e-u;return t=a,u=e,[i,o]})}var e,i,o,c=1,f=1,h=r,s=t;return u.x=function(n){return arguments.length?(h=n,u):h},u.y=function(n){return arguments.length?(s=n,u):s},u.hexagon=function(n){return arguments.length<1&&(n=e),"m"+a(n).join("l")+"z"},u.centers=function(){for(var n=[],r=0,t=!1,u=0;f+e>r;r+=o,t=!t,++u)for(var a=t?i/2:0,h=0;c+i/2>a;a+=i,++h){var s=[a,r];s.i=h,s.j=u,n.push(s)}return n},u.mesh=function(){var n=a(e).slice(0,4).join("l");return u.centers().map(function(r){return"M"+r+"m"+n}).join("")},u.size=function(n){return arguments.length?(c=+n[0],f=+n[1],u):[c,f]},u.radius=function(n){return arguments.length?(e=+n,i=2*e*Math.sin(Math.PI/3),o=1.5*e,u):e},u.radius(1)};var n=d3.range(0,2*Math.PI,Math.PI/3),r=function(n){return n[0]},t=function(n){return n[1]}}();