william007
william007

Reputation: 18525

Multidimensional array for D3

The following code works for D3 V3, but not D3 V4, how to rectify it?

<!DOCTYPE html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.9/d3.js" type="text/JavaScript"></script-->
<body></body>
<script>
var dataset = [[1,3,3,5,6,7],[3,5,8,3,2,6],[9,0,6,3,6,3],[3,4,4,5,6,8],[3,4,5,2,1,8]];

var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500);


svg.append("g")
        .selectAll("g")
        .data(dataset)
        .enter()
        .append("g") //removing
        .selectAll("text") // these
        .data( function(d,i,j) { return d; } ) //lines
        .enter() //text displays normally
        .append("text")
        .text( function(d,i,j) { return d; } )
        .attr("x", function(d,i,j) { console.log(j);return (i * 20) + 40; })
        .attr("y", function(d,i,j) { return (j * 20) + 40; })
        .attr("font-family", "sans-serif")
        .attr("font-size", "20px")


</script>

Upvotes: 2

Views: 1247

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

The explanation here is simple, and it was the subject of this answer of mine: the third argument has changed from D3 v3 to D3 v4.

This is the problematic line:

.attr("y", function(d,i,j) { return (j * 20) + 40; })
//the 3rd argum. -------^            ^--- using the 3rd argument

In D3 v3, the third argument is the index of the parent group. However, in v4, the third argument is the current group. The changelog is clear:

The arguments passed to callback functions has changed slightly in 4.0 to be more consistent. The standard arguments are the element’s datum (d), the element’s index (i), and the element’s group (nodes), with this as the element.

But there is a way to achieve what you want in v4! The same changelog says:

The slight exception to this convention is selection.data, which is evaluated for each group rather than each element; it is passed the group’s parent datum (d), the group index (i), and the selection’s parents (parents), with this as the group’s parent. (emphasis mine)

Thus, we can use the data() method to get the group's index.

Here, I'm using a local variable...

var local = d3.local();

... to get the index inside data():

.data( function(d,i) { 
    local.set(this, i);
    return d;
})

Then, using it to set the y position:

.attr("y", function(d) {
    return (local.get(this) * 20) + 40;
})

Here is your code with that change:

var dataset = [
  [1, 3, 3, 5, 6, 7],
  [3, 5, 8, 3, 2, 6],
  [9, 0, 6, 3, 6, 3],
  [3, 4, 4, 5, 6, 8],
  [3, 4, 5, 2, 1, 8]
];

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 500);

var local = d3.local();

svg.append("g")
  .selectAll("g")
  .data(dataset)
  .enter()
  .append("g")
  .selectAll("text")
  .data(function(d, i) {
    local.set(this, i)
    return d;
  })
  .enter()
  .append("text")
  .text(function(d, i, j) {
    return d;
  })
  .attr("x", function(d, i, j) {
    return (i * 20) + 40;
  })
  .attr("y", function(d) {
    return (local.get(this) * 20) + 40;
  })
  .attr("font-family", "sans-serif")
  .attr("font-size", "20px")
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 4

Related Questions