Problema con la actualización del diagrama de dispersión de matriz interactiva d3 a v4

Estoy tratando de mejorar mis habilidades con D3.js actualizando varios scripts de v3 que me interesan en v4, pero me quedé atascado al intentar "portar" la matriz de diagrama de dispersión interactiva que Mike Bostok publicó aquí:https://bl.ocks.org/mbostock/4063663

Si bien porté sin problemas la versión estática del código (sin pincel), al intentar implementar el pincel de la misma manera que en v3, encontré un problema que parece un problema real de D3 más que estar relacionado con mi novato D3: ¡el pincel parece pegarse en la celda incorrecta en la matriz de diagrama de dispersión! En particular, si elimino la parte brushmove y solo registro para consolar las cantidades p.i y p.j (que identifican en qué celda de la matriz de diagrama de dispersión estamos cepillando), obtengo un índice i = 3 atascado.

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

El código está disponible para su revisión en JSFiddle, junto con el objeto iris:https://jsfiddle.net/fabio_p/pmpjawmm/

Tenga en cuenta que la variable brushcell definida en la función brushstart también es incorrecta (lo que sugiere que es el "this" pasado a las funciones de pincel como incorrecto)

Aún más extraño (al menos para mis ojos inexpertos), las cosas parecen ir mejor si cambio el orden en el que agrego las celdas, como puede ver en este otro violín:https://jsfiddle.net/fabio_p/7pf4cqrg/ Aquí acabo de cambiar los índices en la línea 220 (y para la consistencia de la escala en la línea 206), y el índice ya no está atascado en 3 ...

¿Alguna idea sobre lo que estoy haciendo mal o dónde va mal D3?

Respuestas a la pregunta(1)

Su respuesta a la pregunta