Issue with updating d3 interactive matrix scatterplot to v4

418 views Asked by At

I'm trying to improve my skills with D3.js by updating various v3 scripts I'm interested in to v4, but I got stuck while trying to "port" the interactive scatterplot matrix that Mike Bostok posted here: https://bl.ocks.org/mbostock/4063663

While I've ported with no problem the static version of the code (with no brush), when trying to implement the brush in the same fashion as in v3, I have found an issue that seems an actual D3 problem more than being related to my D3 noob-ness: brush seems to stick on the wrong cell on the scatterplot matrix! In particular, if I remove the brushmove part and I just log to console the quantities p.i and p.j (which identify which cell in the scatterplot matrix we are brushing on), I got a stuck i = 3 index.

var width = 960,
  size = 230,
  padding = 20;

var x = d3.scaleLinear()
  .range([padding / 2, size - padding / 2]);

var y = d3.scaleLinear()
  .range([size - padding / 2, padding / 2]);

var xAxis = d3.axisBottom()
  .scale(x)
  .ticks(6);

var yAxis = d3.axisLeft()
  .scale(y)
  .ticks(6);

var color = d3.scaleOrdinal(d3.schemeCategory10);

//d3.csv("flowers.csv", function(error, data) {
//  if (error) throw error;

data = iris;

var domainByTrait = {},
  traits = d3.keys(data[0]).filter(function(d) { return d !== "species"; }),
  n = traits.length;

traits.forEach(function(trait) {
  domainByTrait[trait] = d3.extent(data, function(d) { return d[trait]; });
});

xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);

var brush = d3.brush()
  .on("start", brushstart)
  .on("brush", brushmove)
  .on("end", brushend);

var svg = d3.select("body").append("svg")
  .attr("width", size * n + padding)
  .attr("height", size * n + padding)
  .append("g")
  .attr("transform", "translate(" + padding + "," + padding / 2 + ")");

svg.selectAll(".x.axis")
  .data(traits)
  .enter().append("g")
  .attr("class", "x axis")
  .attr("transform", function(d, i) { return "translate(" + (n - i - 1) * size + ",0)"; })
  .each(function(d) { x.domain(domainByTrait[d]); d3.select(this).call(xAxis); });

svg.selectAll(".y.axis")
  .data(traits)
  .enter().append("g")
  .attr("class", "y axis")
  .attr("transform", function(d, i) { return "translate(0," + i * size + ")"; })
  .each(function(d) { y.domain(domainByTrait[d]); d3.select(this).call(yAxis); });

var cell = svg.selectAll(".cell")
  .data(cross(traits, traits))
  .enter().append("g")
  .attr("class", "cell")
  .attr("transform", function(d) { return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")"; })
  .each(plot);

// Titles for the diagonal.
cell.filter(function(d) { return d.i === d.j; }).append("text")
  .attr("x", padding)
  .attr("y", padding)
  .attr("dy", ".71em")
  .text(function(d) { return d.x; });

cell.call(brush);

function plot(p) {
  var cell = d3.select(this);

  x.domain(domainByTrait[p.x]);
  y.domain(domainByTrait[p.y]);

  cell.append("rect")
    .attr("class", "frame")
    .attr("x", padding / 2)
    .attr("y", padding / 2)
    .attr("width", size - padding)
    .attr("height", size - padding);

  cell.selectAll("circle")
    .data(data)
    .enter().append("circle")
    .attr("cx", function(d) { return x(d[p.x]); })
    .attr("cy", function(d) { return y(d[p.y]); })
    .attr("r", 4)
    .style("fill", function(d) { return color(d.species); });
}

var brushCell;

// Clear the previously-active brush, if any.
function brushstart(p) {
  if (brushCell !== this) {
    d3.select(brushCell).call(brush.move, null);
    x.domain(domainByTrait[p.x]);
    y.domain(domainByTrait[p.y]);
    brushCell = this;
  }
}

// Highlight the selected circles.
function brushmove(p) {
  // ??
  console.log(p.i +" " + p.j)
}

// If the brush is empty, select all circles.
function brushend(p) {
  if (!d3.event.selection) svg.selectAll(".hidden").classed("hidden", false);
}
//});

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;
}

The code is up for review at JSFiddle as well together with the iris object: https://jsfiddle.net/fabio_p/pmpjawmm/

Notice that the variable brushcell defined in function brushstart is the wrong one as well (suggesting that it's the "this" passed to the brush functions to be wrong)

Even weirder (at least to my unexperienced eyes), things seem to go in a better way if I change the order in which I add cells, as you can see at this other fiddle: https://jsfiddle.net/fabio_p/7pf4cqrg/ Here I just changed indexes at line 220 (and for scale consistency at line 206), and the index i is not stuck anymore at 3...

Any insights about what I'm doing wrong or where is D3 going wrong?

1

There are 1 answers

2
Andrew On BEST ANSWER

No problems with d3, you just have two minor problems in your code.

1) The move from v3 to v4 (as noted in the CHANGELOG) added the .extent() method for denoting the selection area. The default extent falls back to the size of the svg. If you look at each of your overlay objects they are the size of the entire svg document, that is what is causing your indexing to be wonky. The simple fix is to set the extent,

var brush = d3.brush()
  .on("start", brushstart)
  .on("brush", brushmove)
  .on("end", brushend)
  .extent([[0, 0], [size, size]]);

Now when you do your selections, the area is again limited to each graph and they have the correct indexes.

Problem 2) Due to the change from using a scale to using coordinates, you need to translate the absolute coordinate within the selection to your scale, as noted in the change log linked above, this can be done using .invert() on the defined scales.

 // Highlight the selected circles.
function brushmove(p) {
 if(d3.event.selection){
  var e = d3.event.selection;
  svg.selectAll("circle").classed("hidden", function(d) {
   return x.invert(e[0][0]) > d[p.x] || x.invert(e[1][0]) < d[p.x] 
   || y.invert(e[0][1]) < d[p.y] || y.invert(e[1][1]) > d[p.y];
  });
 }
}

Putting these two fixes in gets us back to the correct functionality,

iris = [{
  "sepal.length": "5.1",
  "sepal.width": "3.5",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.9",
  "sepal.width": "3",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.7",
  "sepal.width": "3.2",
  "petal.length": "1.3",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.6",
  "sepal.width": "3.1",
  "petal.length": "1.5",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3.6",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.9",
  "sepal.width": "3.1",
  "petal.length": "1.5",
  "petal.width": "0.1",
  "species": "setosa"
}, {
  "sepal.length": "5.4",
  "sepal.width": "3.7",
  "petal.length": "1.5",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.8",
  "sepal.width": "3.4",
  "petal.length": "1.6",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.8",
  "sepal.width": "3",
  "petal.length": "1.4",
  "petal.width": "0.1",
  "species": "setosa"
}, {
  "sepal.length": "4.3",
  "sepal.width": "3",
  "petal.length": "1.1",
  "petal.width": "0.1",
  "species": "setosa"
}, {
  "sepal.length": "5.8",
  "sepal.width": "4",
  "petal.length": "1.2",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.7",
  "sepal.width": "4.4",
  "petal.length": "1.5",
  "petal.width": "0.4",
  "species": "setosa"
}, {
  "sepal.length": "5.4",
  "sepal.width": "3.9",
  "petal.length": "1.3",
  "petal.width": "0.4",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.5",
  "petal.length": "1.4",
  "petal.width": "0.3",
  "species": "setosa"
}, {
  "sepal.length": "5.7",
  "sepal.width": "3.8",
  "petal.length": "1.7",
  "petal.width": "0.3",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.8",
  "petal.length": "1.5",
  "petal.width": "0.3",
  "species": "setosa"
}, {
  "sepal.length": "5.4",
  "sepal.width": "3.4",
  "petal.length": "1.7",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.7",
  "petal.length": "1.5",
  "petal.width": "0.4",
  "species": "setosa"
}, {
  "sepal.length": "4.6",
  "sepal.width": "3.6",
  "petal.length": "1",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.3",
  "petal.length": "1.7",
  "petal.width": "0.5",
  "species": "setosa"
}, {
  "sepal.length": "4.8",
  "sepal.width": "3.4",
  "petal.length": "1.9",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3",
  "petal.length": "1.6",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3.4",
  "petal.length": "1.6",
  "petal.width": "0.4",
  "species": "setosa"
}, {
  "sepal.length": "5.2",
  "sepal.width": "3.5",
  "petal.length": "1.5",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.2",
  "sepal.width": "3.4",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.7",
  "sepal.width": "3.2",
  "petal.length": "1.6",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.8",
  "sepal.width": "3.1",
  "petal.length": "1.6",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.4",
  "sepal.width": "3.4",
  "petal.length": "1.5",
  "petal.width": "0.4",
  "species": "setosa"
}, {
  "sepal.length": "5.2",
  "sepal.width": "4.1",
  "petal.length": "1.5",
  "petal.width": "0.1",
  "species": "setosa"
}, {
  "sepal.length": "5.5",
  "sepal.width": "4.2",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.9",
  "sepal.width": "3.1",
  "petal.length": "1.5",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3.2",
  "petal.length": "1.2",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.5",
  "sepal.width": "3.5",
  "petal.length": "1.3",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.9",
  "sepal.width": "3.6",
  "petal.length": "1.4",
  "petal.width": "0.1",
  "species": "setosa"
}, {
  "sepal.length": "4.4",
  "sepal.width": "3",
  "petal.length": "1.3",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.4",
  "petal.length": "1.5",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3.5",
  "petal.length": "1.3",
  "petal.width": "0.3",
  "species": "setosa"
}, {
  "sepal.length": "4.5",
  "sepal.width": "2.3",
  "petal.length": "1.3",
  "petal.width": "0.3",
  "species": "setosa"
}, {
  "sepal.length": "4.4",
  "sepal.width": "3.2",
  "petal.length": "1.3",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3.5",
  "petal.length": "1.6",
  "petal.width": "0.6",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.8",
  "petal.length": "1.9",
  "petal.width": "0.4",
  "species": "setosa"
}, {
  "sepal.length": "4.8",
  "sepal.width": "3",
  "petal.length": "1.4",
  "petal.width": "0.3",
  "species": "setosa"
}, {
  "sepal.length": "5.1",
  "sepal.width": "3.8",
  "petal.length": "1.6",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "4.6",
  "sepal.width": "3.2",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5.3",
  "sepal.width": "3.7",
  "petal.length": "1.5",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "5",
  "sepal.width": "3.3",
  "petal.length": "1.4",
  "petal.width": "0.2",
  "species": "setosa"
}, {
  "sepal.length": "7",
  "sepal.width": "3.2",
  "petal.length": "4.7",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "6.4",
  "sepal.width": "3.2",
  "petal.length": "4.5",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "6.9",
  "sepal.width": "3.1",
  "petal.length": "4.9",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "5.5",
  "sepal.width": "2.3",
  "petal.length": "4",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.5",
  "sepal.width": "2.8",
  "petal.length": "4.6",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "5.7",
  "sepal.width": "2.8",
  "petal.length": "4.5",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.3",
  "sepal.width": "3.3",
  "petal.length": "4.7",
  "petal.width": "1.6",
  "species": "versicolor"
}, {
  "sepal.length": "4.9",
  "sepal.width": "2.4",
  "petal.length": "3.3",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "6.6",
  "sepal.width": "2.9",
  "petal.length": "4.6",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "5.2",
  "sepal.width": "2.7",
  "petal.length": "3.9",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "5",
  "sepal.width": "2",
  "petal.length": "3.5",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "5.9",
  "sepal.width": "3",
  "petal.length": "4.2",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "6",
  "sepal.width": "2.2",
  "petal.length": "4",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "6.1",
  "sepal.width": "2.9",
  "petal.length": "4.7",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "5.6",
  "sepal.width": "2.9",
  "petal.length": "3.6",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3.1",
  "petal.length": "4.4",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "5.6",
  "sepal.width": "3",
  "petal.length": "4.5",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "5.8",
  "sepal.width": "2.7",
  "petal.length": "4.1",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "6.2",
  "sepal.width": "2.2",
  "petal.length": "4.5",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "5.6",
  "sepal.width": "2.5",
  "petal.length": "3.9",
  "petal.width": "1.1",
  "species": "versicolor"
}, {
  "sepal.length": "5.9",
  "sepal.width": "3.2",
  "petal.length": "4.8",
  "petal.width": "1.8",
  "species": "versicolor"
}, {
  "sepal.length": "6.1",
  "sepal.width": "2.8",
  "petal.length": "4",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.3",
  "sepal.width": "2.5",
  "petal.length": "4.9",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "6.1",
  "sepal.width": "2.8",
  "petal.length": "4.7",
  "petal.width": "1.2",
  "species": "versicolor"
}, {
  "sepal.length": "6.4",
  "sepal.width": "2.9",
  "petal.length": "4.3",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.6",
  "sepal.width": "3",
  "petal.length": "4.4",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "6.8",
  "sepal.width": "2.8",
  "petal.length": "4.8",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3",
  "petal.length": "5",
  "petal.width": "1.7",
  "species": "versicolor"
}, {
  "sepal.length": "6",
  "sepal.width": "2.9",
  "petal.length": "4.5",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "5.7",
  "sepal.width": "2.6",
  "petal.length": "3.5",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "5.5",
  "sepal.width": "2.4",
  "petal.length": "3.8",
  "petal.width": "1.1",
  "species": "versicolor"
}, {
  "sepal.length": "5.5",
  "sepal.width": "2.4",
  "petal.length": "3.7",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "5.8",
  "sepal.width": "2.7",
  "petal.length": "3.9",
  "petal.width": "1.2",
  "species": "versicolor"
}, {
  "sepal.length": "6",
  "sepal.width": "2.7",
  "petal.length": "5.1",
  "petal.width": "1.6",
  "species": "versicolor"
}, {
  "sepal.length": "5.4",
  "sepal.width": "3",
  "petal.length": "4.5",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "6",
  "sepal.width": "3.4",
  "petal.length": "4.5",
  "petal.width": "1.6",
  "species": "versicolor"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3.1",
  "petal.length": "4.7",
  "petal.width": "1.5",
  "species": "versicolor"
}, {
  "sepal.length": "6.3",
  "sepal.width": "2.3",
  "petal.length": "4.4",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "5.6",
  "sepal.width": "3",
  "petal.length": "4.1",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "5.5",
  "sepal.width": "2.5",
  "petal.length": "4",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "5.5",
  "sepal.width": "2.6",
  "petal.length": "4.4",
  "petal.width": "1.2",
  "species": "versicolor"
}, {
  "sepal.length": "6.1",
  "sepal.width": "3",
  "petal.length": "4.6",
  "petal.width": "1.4",
  "species": "versicolor"
}, {
  "sepal.length": "5.8",
  "sepal.width": "2.6",
  "petal.length": "4",
  "petal.width": "1.2",
  "species": "versicolor"
}, {
  "sepal.length": "5",
  "sepal.width": "2.3",
  "petal.length": "3.3",
  "petal.width": "1",
  "species": "versicolor"
}, {
  "sepal.length": "5.6",
  "sepal.width": "2.7",
  "petal.length": "4.2",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "5.7",
  "sepal.width": "3",
  "petal.length": "4.2",
  "petal.width": "1.2",
  "species": "versicolor"
}, {
  "sepal.length": "5.7",
  "sepal.width": "2.9",
  "petal.length": "4.2",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.2",
  "sepal.width": "2.9",
  "petal.length": "4.3",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "5.1",
  "sepal.width": "2.5",
  "petal.length": "3",
  "petal.width": "1.1",
  "species": "versicolor"
}, {
  "sepal.length": "5.7",
  "sepal.width": "2.8",
  "petal.length": "4.1",
  "petal.width": "1.3",
  "species": "versicolor"
}, {
  "sepal.length": "6.3",
  "sepal.width": "3.3",
  "petal.length": "6",
  "petal.width": "2.5",
  "species": "virginica"
}, {
  "sepal.length": "5.8",
  "sepal.width": "2.7",
  "petal.length": "5.1",
  "petal.width": "1.9",
  "species": "virginica"
}, {
  "sepal.length": "7.1",
  "sepal.width": "3",
  "petal.length": "5.9",
  "petal.width": "2.1",
  "species": "virginica"
}, {
  "sepal.length": "6.3",
  "sepal.width": "2.9",
  "petal.length": "5.6",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.5",
  "sepal.width": "3",
  "petal.length": "5.8",
  "petal.width": "2.2",
  "species": "virginica"
}, {
  "sepal.length": "7.6",
  "sepal.width": "3",
  "petal.length": "6.6",
  "petal.width": "2.1",
  "species": "virginica"
}, {
  "sepal.length": "4.9",
  "sepal.width": "2.5",
  "petal.length": "4.5",
  "petal.width": "1.7",
  "species": "virginica"
}, {
  "sepal.length": "7.3",
  "sepal.width": "2.9",
  "petal.length": "6.3",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.7",
  "sepal.width": "2.5",
  "petal.length": "5.8",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "7.2",
  "sepal.width": "3.6",
  "petal.length": "6.1",
  "petal.width": "2.5",
  "species": "virginica"
}, {
  "sepal.length": "6.5",
  "sepal.width": "3.2",
  "petal.length": "5.1",
  "petal.width": "2",
  "species": "virginica"
}, {
  "sepal.length": "6.4",
  "sepal.width": "2.7",
  "petal.length": "5.3",
  "petal.width": "1.9",
  "species": "virginica"
}, {
  "sepal.length": "6.8",
  "sepal.width": "3",
  "petal.length": "5.5",
  "petal.width": "2.1",
  "species": "virginica"
}, {
  "sepal.length": "5.7",
  "sepal.width": "2.5",
  "petal.length": "5",
  "petal.width": "2",
  "species": "virginica"
}, {
  "sepal.length": "5.8",
  "sepal.width": "2.8",
  "petal.length": "5.1",
  "petal.width": "2.4",
  "species": "virginica"
}, {
  "sepal.length": "6.4",
  "sepal.width": "3.2",
  "petal.length": "5.3",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "6.5",
  "sepal.width": "3",
  "petal.length": "5.5",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "7.7",
  "sepal.width": "3.8",
  "petal.length": "6.7",
  "petal.width": "2.2",
  "species": "virginica"
}, {
  "sepal.length": "7.7",
  "sepal.width": "2.6",
  "petal.length": "6.9",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "6",
  "sepal.width": "2.2",
  "petal.length": "5",
  "petal.width": "1.5",
  "species": "virginica"
}, {
  "sepal.length": "6.9",
  "sepal.width": "3.2",
  "petal.length": "5.7",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "5.6",
  "sepal.width": "2.8",
  "petal.length": "4.9",
  "petal.width": "2",
  "species": "virginica"
}, {
  "sepal.length": "7.7",
  "sepal.width": "2.8",
  "petal.length": "6.7",
  "petal.width": "2",
  "species": "virginica"
}, {
  "sepal.length": "6.3",
  "sepal.width": "2.7",
  "petal.length": "4.9",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3.3",
  "petal.length": "5.7",
  "petal.width": "2.1",
  "species": "virginica"
}, {
  "sepal.length": "7.2",
  "sepal.width": "3.2",
  "petal.length": "6",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.2",
  "sepal.width": "2.8",
  "petal.length": "4.8",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.1",
  "sepal.width": "3",
  "petal.length": "4.9",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.4",
  "sepal.width": "2.8",
  "petal.length": "5.6",
  "petal.width": "2.1",
  "species": "virginica"
}, {
  "sepal.length": "7.2",
  "sepal.width": "3",
  "petal.length": "5.8",
  "petal.width": "1.6",
  "species": "virginica"
}, {
  "sepal.length": "7.4",
  "sepal.width": "2.8",
  "petal.length": "6.1",
  "petal.width": "1.9",
  "species": "virginica"
}, {
  "sepal.length": "7.9",
  "sepal.width": "3.8",
  "petal.length": "6.4",
  "petal.width": "2",
  "species": "virginica"
}, {
  "sepal.length": "6.4",
  "sepal.width": "2.8",
  "petal.length": "5.6",
  "petal.width": "2.2",
  "species": "virginica"
}, {
  "sepal.length": "6.3",
  "sepal.width": "2.8",
  "petal.length": "5.1",
  "petal.width": "1.5",
  "species": "virginica"
}, {
  "sepal.length": "6.1",
  "sepal.width": "2.6",
  "petal.length": "5.6",
  "petal.width": "1.4",
  "species": "virginica"
}, {
  "sepal.length": "7.7",
  "sepal.width": "3",
  "petal.length": "6.1",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "6.3",
  "sepal.width": "3.4",
  "petal.length": "5.6",
  "petal.width": "2.4",
  "species": "virginica"
}, {
  "sepal.length": "6.4",
  "sepal.width": "3.1",
  "petal.length": "5.5",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6",
  "sepal.width": "3",
  "petal.length": "4.8",
  "petal.width": "1.8",
  "species": "virginica"
}, {
  "sepal.length": "6.9",
  "sepal.width": "3.1",
  "petal.length": "5.4",
  "petal.width": "2.1",
  "species": "virginica"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3.1",
  "petal.length": "5.6",
  "petal.width": "2.4",
  "species": "virginica"
}, {
  "sepal.length": "6.9",
  "sepal.width": "3.1",
  "petal.length": "5.1",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "5.8",
  "sepal.width": "2.7",
  "petal.length": "5.1",
  "petal.width": "1.9",
  "species": "virginica"
}, {
  "sepal.length": "6.8",
  "sepal.width": "3.2",
  "petal.length": "5.9",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3.3",
  "petal.length": "5.7",
  "petal.width": "2.5",
  "species": "virginica"
}, {
  "sepal.length": "6.7",
  "sepal.width": "3",
  "petal.length": "5.2",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "6.3",
  "sepal.width": "2.5",
  "petal.length": "5",
  "petal.width": "1.9",
  "species": "virginica"
}, {
  "sepal.length": "6.5",
  "sepal.width": "3",
  "petal.length": "5.2",
  "petal.width": "2",
  "species": "virginica"
}, {
  "sepal.length": "6.2",
  "sepal.width": "3.4",
  "petal.length": "5.4",
  "petal.width": "2.3",
  "species": "virginica"
}, {
  "sepal.length": "5.9",
  "sepal.width": "3",
  "petal.length": "5.1",
  "petal.width": "1.8",
  "species": "virginica"
}];


var width = 960,
  size = 230,
  padding = 20;

var x = d3.scaleLinear()
  .range([padding / 2, size - padding / 2]);

var y = d3.scaleLinear()
  .range([size - padding / 2, padding / 2]);

var xAxis = d3.axisBottom()
  .scale(x)
  .ticks(6);

var yAxis = d3.axisLeft()
  .scale(y)
  .ticks(6);

var color = d3.scaleOrdinal(d3.schemeCategory10);

//d3.csv("flowers.csv", function(error, data) {
//  if (error) throw error;

data = iris;

var domainByTrait = {},
  traits = d3.keys(data[0]).filter(function(d) {
    return d !== "species";
  }),
  n = traits.length;

traits.forEach(function(trait) {
  domainByTrait[trait] = d3.extent(data, function(d) {
    return d[trait];
  });
});

xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);

var brush = d3.brush()
  .on("start", brushstart)
  .on("brush", brushmove)
  .on("end", brushend)
  .extent([
    [0, 0],
    [size, size]
  ]);

var svg = d3.select("body").append("svg")
  .attr("width", size * n + padding)
  .attr("height", size * n + padding)
  .append("g")
  .attr("transform", "translate(" + padding + "," + padding / 2 + ")");

svg.selectAll(".x.axis")
  .data(traits)
  .enter().append("g")
  .attr("class", "x axis")
  .attr("transform", function(d, i) {
    return "translate(" + (n - i - 1) * size + ",0)";
  })
  .each(function(d) {
    x.domain(domainByTrait[d]);
    d3.select(this).call(xAxis);
  });

svg.selectAll(".y.axis")
  .data(traits)
  .enter().append("g")
  .attr("class", "y axis")
  .attr("transform", function(d, i) {
    return "translate(0," + i * size + ")";
  })
  .each(function(d) {
    y.domain(domainByTrait[d]);
    d3.select(this).call(yAxis);
  });

var cell = svg.selectAll(".cell")
  .data(cross(traits, traits))
  .enter().append("g")
  .attr("class", "cell")
  .attr("transform", function(d) {
    return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")";
  })
  .each(plot);

// Titles for the diagonal.
cell.filter(function(d) {
    return d.i === d.j;
  }).append("text")
  .attr("x", padding)
  .attr("y", padding)
  .attr("dy", ".71em")
  .text(function(d) {
    return d.x;
  });

cell.call(brush);

//console.log(traits.map(function(d) { return domainByTrait[d];}));

function plot(p) {
  var cell = d3.select(this);

  x.domain(domainByTrait[p.x]);
  y.domain(domainByTrait[p.y]);

  cell.append("rect")
    .attr("class", "frame")
    .attr("x", padding / 2)
    .attr("y", padding / 2)
    .attr("width", size - padding)
    .attr("height", size - padding);

  cell.selectAll("circle")
    .data(data)
    .enter().append("circle")
    .attr("cx", function(d) {
      return x(d[p.x]);
    })
    .attr("cy", function(d) {
      return y(d[p.y]);
    })
    .attr("r", 4)
    .style("fill", function(d) {
      return color(d.species);
    });
}

var brushCell;

// Clear the previously-active brush, if any.
function brushstart(p) {
  if (brushCell !== this) {
    d3.select(brushCell).call(brush.move, null);
    x.domain(domainByTrait[p.x]);
    y.domain(domainByTrait[p.y]);
    brushCell = this;
  }
}

// Highlight the selected circles.
function brushmove(p) {
  if (d3.event.selection) {
    var e = d3.event.selection;
    svg.selectAll("circle").classed("hidden", function(d) {
      return x.invert(e[0][0]) > d[p.x] || x.invert(e[1][0]) < d[p.x] || y.invert(e[0][1]) < d[p.y] || y.invert(e[1][1]) > d[p.y];
    });
  }
}

// If the brush is empty, select all circles.
function brushend(p) {
    if (!d3.event.selection) svg.selectAll(".hidden").classed("hidden", false);
  }
  //});

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;
}
svg {
  font: 10px sans-serif;
  padding: 10px;
}
.axis,
.frame {
  shape-rendering: crispEdges;
}
.axis line {
  stroke: #ddd;
}
.axis path {
  display: none;
}
.cell text {
  font-weight: bold;
  text-transform: capitalize;
}
.frame {
  fill: none;
  stroke: #aaa;
}
circle {
  fill-opacity: .7;
}
circle.hidden {
  fill: #ccc !important;
}
.extent {
  fill: #000;
  fill-opacity: .125;
  stroke: #fff;
}
<!DOCTYPE html>

<body>
  <script src="//d3js.org/d3.v4.min.js"></script>
</body>