See it running at http://bl.ocks.org/3867599
Modified from here: http://jsfiddle.net/cuHrV/
See it running at http://bl.ocks.org/3867599
Modified from here: http://jsfiddle.net/cuHrV/
| <html> | |
| <head> | |
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | |
| <title>Scatter to Heatmap</title> | |
| <script src="http://d3js.org/d3.v2.js"></script> | |
| <script src=" https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> | |
| <link href='http://fonts.googleapis.com/css?family=Numans' rel='stylesheet' type='text/css'> | |
| <style> | |
| body { | |
| font-family: 'Numans', sans-serif; | |
| } | |
| div#plots { | |
| margin-bottom: 15px; | |
| } | |
| div#scatterplot, div#heatchart { | |
| border: 1px solid #ccc; | |
| margin-bottom: 10px; | |
| } | |
| div#scatterContainer, div#heatchartContainer { | |
| float: left; | |
| margin-left: 15px; | |
| margin-bottom: 20px; | |
| } | |
| circle { | |
| fill: #063; | |
| } | |
| </style> | |
| <h1>Scatter to Heatmap</h1> | |
| <div id="plots"> | |
| <div id="scatterContainer"> | |
| <div id="scatterplot"></div> | |
| </div> | |
| <div id="heatchartContainer"> | |
| <div id="heatchart"></div> | |
| </div> | |
| </div> | |
| <script type="text/javascript"> | |
| var numPoints = 1500, | |
| size = 300, | |
| numRows = 16, | |
| numCols = 16, | |
| showingScatter = true, | |
| scatterDirty = false, | |
| data = null, | |
| cells = null, | |
| color = d3.interpolateRgb("#fff", "#063"); | |
| var getEmptyCells = function() { | |
| var emptyCells = []; | |
| for (var rowNum = 0; rowNum < numRows; rowNum++) { | |
| emptyCells.push([]); | |
| var row = emptyCells[emptyCells.length - 1]; | |
| for (var colNum = 0; colNum < numCols; colNum++) { | |
| row.push({ | |
| row: rowNum, | |
| col: colNum, | |
| density: 0, | |
| points: [] | |
| }); | |
| } | |
| } | |
| return emptyCells; | |
| }; | |
| var clearCells = function() { | |
| for (var rowNum = 0; rowNum < numRows; rowNum++) { | |
| for (var colNum = 0; colNum < numCols; colNum++) { | |
| cells[rowNum][colNum].density = 0; | |
| cells[rowNum][colNum].points = []; | |
| } | |
| } | |
| }; | |
| var randomizeData = function() { | |
| data = []; | |
| if (cells === null) { | |
| cells = getEmptyCells(); | |
| } | |
| else { | |
| clearCells(); | |
| } | |
| var x, y, col, row; | |
| for (var i = 0; i < numPoints; i++) { | |
| x = Math.random() * size; | |
| y = Math.random() * size; | |
| col = Math.min(Math.floor(x / size * numCols), numCols - 1); | |
| row = Math.min(Math.floor(y / size * numRows), numRows - 1); | |
| data.push({ | |
| x: x, | |
| y: y, | |
| col: col, | |
| row: row, | |
| cell: cells[row][col], | |
| ind: i | |
| }); | |
| cells[row][col].points.push(data[data.length - 1]); | |
| } | |
| }; | |
| var selectPoints = function(points) { | |
| d3.selectAll(points).attr("r", 4).attr("stroke", "#f00").attr("stroke-width", 3); | |
| for (var i = 0; i < points.length; i++) { | |
| points[i].parentNode.appendChild(points[i]); | |
| } | |
| }; | |
| var deselectPoints = function(points) { | |
| d3.selectAll(points).attr("r", 2).attr("stroke", "none"); | |
| }; | |
| var selectCell = function(cell) { | |
| d3.select(cell).attr("stroke", "#f00").attr("stroke-width", 3); | |
| cell.parentNode.parentNode.appendChild(cell.parentNode); | |
| cell.parentNode.appendChild(cell); | |
| }; | |
| var deselectCell = function(cell) { | |
| d3.select(cell).attr("stroke", "#fff").attr("stroke-width", 1); | |
| }; | |
| var onPointOver = function(point, data) { | |
| selectPoints([point]); | |
| var cell = d3.select("div#heatchart").select('[cell="r' + data.row + 'c' + data.col + '"]'); | |
| selectCell(cell.node()); | |
| }; | |
| var onPointOut = function(point, data) { | |
| deselectPoints([point]); | |
| var cell = d3.select("div#heatchart").select('[cell="r' + data.row + 'c' + data.col + '"]'); | |
| deselectCell(cell.node()); | |
| }; | |
| var createScatterplot = function() { | |
| var scatterplot = d3.select("div#scatterplot").append("svg:svg").attr("width", size).attr("height", size); | |
| scatterplot.selectAll("circle").data(data).enter().append("svg:circle").attr("cx", function(d, i) { | |
| return d.x; | |
| }).attr("cy", function(d, i) { | |
| return d.y; | |
| }).attr("r", 2).attr("ind", function(d) { | |
| return d.ind; | |
| }).on("mouseover", function(d) { | |
| onPointOver(this, d); | |
| }).on("mouseout", function(d) { | |
| onPointOut(this, d); | |
| }); | |
| }; | |
| var onCellOver = function(cell, data) { | |
| selectCell(cell); | |
| if (showingScatter) { | |
| var pointEls = []; | |
| for (var i = 0; i < data.points.length; i++) { | |
| pointEls.push(d3.select("div#scatterplot").select('[ind="' + data.points[i].ind + '"]').node()); | |
| } | |
| selectPoints(pointEls); | |
| } | |
| }; | |
| var onCellOut = function(cell, data) { | |
| deselectCell(cell); | |
| if (showingScatter) { | |
| var pointEls = []; | |
| for (var i = 0; i < data.points.length; i++) { | |
| pointEls.push(d3.select("div#scatterplot").select('[ind="' + data.points[i].ind + '"]').node()); | |
| } | |
| deselectPoints(pointEls); | |
| } | |
| }; | |
| var updateScatterplot = function() { | |
| // select | |
| var dots = d3.select("div#scatterplot").select("svg").selectAll("circle").data(data); | |
| // enter | |
| dots.enter().append("svg:circle").attr("cx", function(d, i) { | |
| return d.x; | |
| }).attr("cy", function(d, i) { | |
| return d.y; | |
| }).attr("r", 2).attr("ind", function(d) { | |
| return d.ind; | |
| }).on("mouseover", function(d) { | |
| onPointOver(this, d); | |
| }).on("mouseout", function(d) { | |
| onPointOut(this, d); | |
| }); | |
| // update | |
| dots.attr("cx", function(d, i) { | |
| return d.x; | |
| }).attr("cy", function(d, i) { | |
| return d.y; | |
| }).attr("ind", function(d) { | |
| return d.ind; | |
| }).on("mouseover", function(d) { | |
| onPointOver(this, d); | |
| }).on("mouseout", function(d) { | |
| onPointOut(this, d); | |
| }); | |
| // exit | |
| dots.exit().remove(); | |
| }; | |
| var createHeatchart = function() { | |
| var min = 999; | |
| var max = -999; | |
| var l; | |
| for (var rowNum = 0; rowNum < cells.length; rowNum++) { | |
| for (var colNum = 0; colNum < numCols; colNum++) { | |
| l = cells[rowNum][colNum].points.length; | |
| if (l > max) { | |
| max = l; | |
| } | |
| if (l < min) { | |
| min = l; | |
| } | |
| } | |
| } | |
| var heatchart = d3.select("div#heatchart").append("svg:svg").attr("width", size).attr("height", size); | |
| heatchart.selectAll("g").data(cells).enter().append("svg:g").selectAll("rect").data(function(d) { | |
| return d; | |
| }).enter().append("svg:rect").attr("x", function(d, i) { | |
| return d.col * (size / numCols); | |
| }).attr("y", function(d, i) { | |
| return d.row * (size / numRows); | |
| }).attr("width", size / numCols).attr("height", size / numRows).attr("fill", function(d, i) { | |
| return color((d.points.length - min) / (max - min)); | |
| }).attr("stroke", "#fff").attr("cell", function(d) { | |
| return "r" + d.row + "c" + d.col; | |
| }).on("mouseover", function(d) { | |
| onCellOver(this, d); | |
| }).on("mouseout", function(d) { | |
| onCellOut(this, d); | |
| }); | |
| }; | |
| var updateHeatchart = function() { | |
| var min = 999; | |
| var max = -999; | |
| var l; | |
| for (var rowNum = 0; rowNum < cells.length; rowNum++) { | |
| for (var colNum = 0; colNum < numCols; colNum++) { | |
| l = cells[rowNum][colNum].points.length; | |
| if (l > max) { | |
| max = l; | |
| } | |
| if (l < min) { | |
| min = l; | |
| } | |
| } | |
| } | |
| d3.select("div#heatchart").select("svg").selectAll("g").data(cells).selectAll("rect").data(function(d) { | |
| return d; | |
| }).attr("x", function(d, i) { | |
| return d.col * (size / numCols); | |
| }).attr("y", function(d, i) { | |
| return d.row * (size / numRows); | |
| }).attr("fill", function(d, i) { | |
| return color((d.points.length - min) / (max - min)); | |
| }).attr("cell", function(d) { | |
| return "r" + d.row + "c" + d.col; | |
| }).on("mouseover", function(d) { | |
| onCellOver(this, d); | |
| }).on("mouseout", function(d) { | |
| onCellOut(this, d); | |
| }); | |
| }; | |
| var onRandomizeClick = function() { | |
| randomizeData(); | |
| if (showingScatter) { | |
| updateScatterplot(); | |
| } | |
| else { | |
| scatterDirty = true; | |
| } | |
| updateHeatchart(); | |
| }; | |
| var onNumPointsChange = function(event) { | |
| numPoints = event.target.options[event.target.selectedIndex].value; | |
| randomizeData(); | |
| if (showingScatter) { | |
| updateScatterplot(); | |
| } | |
| else { | |
| scatterDirty = true; | |
| } | |
| updateHeatchart(); | |
| }; | |
| var onShowScatterplotChange = function(event) { | |
| showingScatter = event.target.checked; | |
| if (showingScatter) { | |
| if (scatterDirty) { | |
| updateScatterplot(); | |
| scatterDirty = false; | |
| } | |
| d3.select("div#scatterplot").select("svg").attr("visibility", "visible"); | |
| } | |
| else { | |
| d3.select("div#scatterplot").select("svg").attr("visibility", "hidden"); | |
| } | |
| }; | |
| var init = function() { | |
| randomizeData(); | |
| createScatterplot(); | |
| createHeatchart(); | |
| }; | |
| init(); | |
| </script> | |
| </body> | |
| </html> |