0

I'm stuck at trying to bind two-dimensional data in d3. I want to display a matrix of green squares. I'm building a matrix like this:

var size = 10;
dataset = [];
for(var y = 0; y<size; y++){
    var tempData = [size];
    for(var x = 0; x<size; x++){
        tempData[x] = 5;
    };
    dataset.push(tempData);
};

I'm not sure how to bind the data correctly. I sort of understand Mike Bostock's tutorial on nested selections, but he's binding a matrix of fixed size to already existing elements. How would I use enter() to create new rectangles? This is how I tried to apply the tutorial's advice to first bind the outer, then the inner arrays.. not surprised that it doesn't work but I also don't know where to go from here..

svg.selectAll("rect")
   .data(dataset)
   .selectAll("rect")
   .data(function (d,i) {return d;})
   .enter()
   .append("rect")
   .attr("x", function(d,i){
            return i*20})
   .attr("y", function(d,i){
            return i*20;})
   .attr("height", 15)
   .attr("width", 15)
   .attr("fill", "green");
smcs
  • 1,772
  • 3
  • 18
  • 48

1 Answers1

5

There are two problems. First, you have the second .selectAll() immediately after the first .data(), which means that you'll be operating on the update selection. This is empty as there are no elements in the DOM to start with. You need to operate on the enter selection instead (and it's good practice to use g elements here for the first level):

svg.selectAll("rect")
  .data(dataset)
  .enter()
  .append("g")
  .selectAll("rect")
  .data(function (d,i) {return d;})

Second, you're putting the rectangles along the diagonal (same x and y coordinates), so even though the correct number of rect elements is there, you don't see all of them because they overlap. To fix, you need to take the index in the parent group into account for one of the coordinates (using the secret third argument):

.append("rect")
.attr("x", function(d,i){
        return i*20;
})
.attr("y", function(d, i, j){
        return j*20;
})

Complete demo here.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
  • Nice! You beat me to it. I knew you had to use `g` elements, but I forgot to use the second `enter()` selection. I'm getting rusty with d3... – Jeff Kilbride Jan 08 '16 at 07:20
  • Nice catch! Having dealt with D3 for quite some time, I have never come across the *secret third argument*. Although I can find it in the source code, I have never seen this documented anywhere. Are you aware of any documentation on this parameter or is it really that *secret*? – altocumulus Jan 08 '16 at 09:09
  • @altocumulus I haven't seen it documented anywhere. – Lars Kotthoff Jan 08 '16 at 17:13
  • @altocumulus I learned about it from reading _D3.js in Action_ by Elijah Meeks, which I highly recommend. – Jeff Kilbride Jan 08 '16 at 17:47
  • A third argument! Now I've seen it all. Great answer, thank you Lars. – smcs Jan 10 '16 at 23:43
  • @Lars Kotthof I implemented the code line for line from the jsfiddle, and one row of green rectangles is displayed but I get the error 'd3.js:7651 Error: attribute y: Expected length, "NaN".' – Adam Freymiller Aug 30 '16 at 04:49
  • @AdamFreymiller I'm afraid I can't possibly help you without knowing what exactly you did. – Lars Kotthoff Aug 30 '16 at 17:14
  • @LarsKotthoff http://stackoverflow.com/questions/39238923/third-variable-in-d3-anonymous-function-does-not-recognize-index-of-parent-datas – Adam Freymiller Aug 31 '16 at 00:18