This example first generates a set of random points. Then the space is divided into squares and each square is colored proportional to the log of the minimum of residue for all lines passing through the square. Hovering over a square shows the line with minimum residue for all lines passing through the square.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
circle{
fill:#DE3D71;
}
rect{
stroke:none;
}
line{
stroke:#29342E;
stroke-width:3px;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 0, right: 0, bottom: 0, left: 0},
width = 960 - margin.left - margin.right,
height = 580 - margin.top - margin.bottom,
sqsz = 6 // square size in pxl
,rad = 3 // radius of dots
;
function getRandomPoints(){ // generate array of random points
var ret =[]
,n = 80 // number of points to generate
,m = -0.3 // slope of line for sampling
,b = 65 // intercept of line for sampling
,c = 0 // counter for points generated so far.
,w = 5 // perturbation scale
,xmax = width/sqsz -1
,ymax = height/sqsz
;
do {
var x=Math.round(Math.random()*xmax), y=Math.round(m*x+b +(2*Math.random()-1)*w);
if( y>0 && y<ymax ){
ret.push({x:x, y:y});
}
c+=1;
}while(c<n);
return ret;
}
function res(x0, y0){
var sx=d3.sum(points.map(function(d){ return (d.x-x0)*(d.x-x0) }))
,sy=d3.sum(points.map(function(d){ return (d.y-y0)*(d.x-x0) }))
,m = sy/sx
;
return {
m:m
,res:Math.log(d3.sum(points.map(function(d){ var r = d.y-y0 - m*(d.x - x0); return r*r; })))
};
}
var sq = [];
var points = getRandomPoints();
for(var j=0; j< height/sqsz; j++){
for(var i=0; i< width/sqsz; i++){
sq.push({x:i, y:j, s:res(i, j)});
}
}
function moveline(d){
//console.log(d);
svg.select("line").attr("x1",0).attr("y1",d.y*sqsz+d.s.m*(0-d.x*sqsz))
.attr("x2",width).attr("y2",d.y*sqsz+d.s.m*(width-d.x*sqsz));
}
var max=d3.max(sq.map(function(s){ return s.s.res;}))
,min=d3.min(sq.map(function(s){ return s.s.res;}))
;
var color = d3.scale.linear().domain([min, max]).range(["#FFF","#4682b4"]);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.selectAll("rect")
.data(sq)
.enter().append("rect")
.attr("x",function(d){return d.x*sqsz}).attr("y",function(d){return d.y*sqsz})
.attr("width",sqsz).attr("height",sqsz)
.attr("res",function(d){ return d.s.res})
.attr("m",function(d){ return d.s.m})
.style("fill",function(d){ return color((d.s.res))})
.on("mouseover",function(d){ return moveline(d);});
svg.append("line").attr("x1",0).attr("y1",0).attr("x2",0).attr("y2",0);
svg.selectAll("circle")
.data(points)
.enter().append("circle")
.attr("cx",function(d){return (d.x+.5)*sqsz}).attr("cy",function(d){return (d.y+.5)*sqsz})
.attr("r",rad);
</script>