diff -r efd9c589177a -r c0b4a8b5a012 toolkit/javascript/d3/examples/splom/splom.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolkit/javascript/d3/examples/splom/splom.js Thu Apr 10 14:20:23 2014 +0200 @@ -0,0 +1,119 @@ +d3.json("flowers.json", function(flower) { + + // Size parameters. + var size = 150, + padding = 19.5, + n = flower.traits.length; + + // Position scales. + var x = {}, y = {}; + flower.traits.forEach(function(trait) { + var value = function(d) { return d[trait]; }, + domain = [d3.min(flower.values, value), d3.max(flower.values, value)], + range = [padding / 2, size - padding / 2]; + x[trait] = d3.scale.linear().domain(domain).range(range); + y[trait] = d3.scale.linear().domain(domain).range(range.reverse()); + }); + + // Axes. + var axis = d3.svg.axis() + .ticks(5) + .tickSize(size * n); + + // Brush. + var brush = d3.svg.brush() + .on("brushstart", brushstart) + .on("brush", brush) + .on("brushend", brushend); + + // Root panel. + var svg = d3.select("#chart").append("svg:svg") + .attr("width", size * n + padding) + .attr("height", size * n + padding); + + // X-axis. + svg.selectAll("g.x.axis") + .data(flower.traits) + .enter().append("svg:g") + .attr("class", "x axis") + .attr("transform", function(d, i) { return "translate(" + i * size + ",0)"; }) + .each(function(d) { d3.select(this).call(axis.scale(x[d]).orient("bottom")); }); + + // Y-axis. + svg.selectAll("g.y.axis") + .data(flower.traits) + .enter().append("svg:g") + .attr("class", "y axis") + .attr("transform", function(d, i) { return "translate(0," + i * size + ")"; }) + .each(function(d) { d3.select(this).call(axis.scale(y[d]).orient("right")); }); + + // Cell and plot. + var cell = svg.selectAll("g.cell") + .data(cross(flower.traits, flower.traits)) + .enter().append("svg:g") + .attr("class", "cell") + .attr("transform", function(d) { return "translate(" + d.i * size + "," + d.j * size + ")"; }) + .each(plot); + + // Titles for the diagonal. + cell.filter(function(d) { return d.i == d.j; }).append("svg:text") + .attr("x", padding) + .attr("y", padding) + .attr("dy", ".71em") + .text(function(d) { return d.x; }); + + function plot(p) { + var cell = d3.select(this); + + // Plot frame. + cell.append("svg:rect") + .attr("class", "frame") + .attr("x", padding / 2) + .attr("y", padding / 2) + .attr("width", size - padding) + .attr("height", size - padding); + + // Plot dots. + cell.selectAll("circle") + .data(flower.values) + .enter().append("svg:circle") + .attr("class", function(d) { return d.species; }) + .attr("cx", function(d) { return x[p.x](d[p.x]); }) + .attr("cy", function(d) { return y[p.y](d[p.y]); }) + .attr("r", 3); + + // Plot brush. + cell.call(brush.x(x[p.x]).y(y[p.y])); + } + + // Clear the previously-active brush, if any. + function brushstart(p) { + if (brush.data !== p) { + cell.call(brush.clear()); + brush.x(x[p.x]).y(y[p.y]).data = p; + } + } + + // Highlight the selected circles. + function brush(p) { + var e = brush.extent(); + svg.selectAll("circle").attr("class", function(d) { + return e[0][0] <= d[p.x] && d[p.x] < e[1][0] + && e[0][1] <= d[p.y] && d[p.y] < e[1][1] + ? d.species : null; + }); + } + + // If the brush is empty, select all circles. + function brushend() { + if (brush.empty()) svg.selectAll("circle").attr("class", function(d) { + return d.species; + }); + } + + function cross(a, b) { + var c = [], n = a.length, m = b.length, i, j; + for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j}); + return c; + } +});