1

I'm trying to create arbitrary groups of columns and rows using these attributes in the objects:

        var svg = d3.select("#right-section").append("svg").attr("width",600).attr("height",600);
        var flatInputMatrix = [1,1,1,0,0,3,3,3,0,0,4,4,4,0,0,5,5,5,0,0,0,2,0,4,4,0,0,0,5,5,0,1,0,2,2];
        var m = 5;
        var r = 3;

        var counter = -1;

        var data = flatInputMatrix.map(function(d, i) {
          i % m === 0 ? counter++ : null;
          return {
            column: i % m,
            row: counter,
            value: d
          };
        });

        var columnsGroups = svg.append("g")
        var columns = columnsGroups.selectAll("columns").data(data.column= this.column).enter()

        var numbers = svg.selectAll("numbers").data(data).enter().append("text")
            .attr("x",function(d,i) { return (i % m)*50 + 10 + r; })
            .attr("y",function(d,i) { return Math.floor(i / m) *50+50; })
            .style("opacity", 0.5)
            .text(function(d) { return d.value; })
            .on("mouseover", function(d.columns){d3.select(this).style("opacity", 1)  })

The idea is to have a column (later a group of columns) have the opacity = 1 when it is hovered over by the cursor.

1 Answer 1

1

Solution #1

Since you want to group by columns, I believe the best approach is nesting your data first (by columns, of course):

var nested = d3.nest()
    .key(function(d) {
        return d.column
    })
    .entries(data);

Then, we append different groups, one for each column:

var columns = svg.selectAll("foo")
    .data(nested)
    .enter()
    .append("g")
    .attr("transform", function(d) {
        return "translate(" + (50 + 50 * d.key) + ",0)";
    })
    .style("opacity", 0.5);

Finally, we set the mouseover:

columns.on("mouseover", function() {
    d3.select(this).style("opacity", 1);
}).on("mouseout", function() {
    d3.select(this).style("opacity", 0.5)
})

Here is the demo:

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

var flatInputMatrix = [1, 1, 1, 0, 0, 3, 3, 3, 0, 0, 4, 4, 4, 0, 0, 5, 5, 5, 0, 0, 0, 2, 0, 4, 4, 0, 0, 0, 5, 5, 0, 1, 0, 2, 2];
var m = 5;
var r = 3;

var counter = -1;

var data = flatInputMatrix.map(function(d, i) {
  i % m === 0 ? counter++ : null;
  return {
    column: i % m,
    row: counter,
    value: d
  };
});

var nested = d3.nest()
  .key(function(d) {
    return d.column
  })
  .entries(data);

var columns = svg.selectAll("foo")
  .data(nested)
  .enter()
  .append("g")
  .attr("transform", function(d) {
    return "translate(" + (50 + 50 * d.key) + ",0)";
  })
  .style("opacity", 0.5);

var numbers = columns.selectAll("foo")
  .data(function(d) {
    return d.values
  })
  .enter()
  .append("text")
  .attr("y", function(d) {
    return d.row * 50 + 50;
  })
  .text(function(d) {
    return d.value;
  });

columns.on("mouseover", function() {
  d3.select(this).style("opacity", 1);
}).on("mouseout", function() {
  d3.select(this).style("opacity", 0.5)
})
<script src="https://d3js.org/d3.v4.min.js"></script>

Solution#2

However, if you don't want to substantially refactor your code, you can simply use the datum in the mouseover function:

numbers.on("mouseover", function(d) {
    var column = d.column;
    numbers.filter(function(d) {
            return d.column === column
        })
        .style("opacity", 1)
}).on("mouseout", function() {
    numbers.style("opacity", 0.5)
})

That way, you can keep your code just like it is right now. Here is the demo:

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

var flatInputMatrix = [1, 1, 1, 0, 0, 3, 3, 3, 0, 0, 4, 4, 4, 0, 0, 5, 5, 5, 0, 0, 0, 2, 0, 4, 4, 0, 0, 0, 5, 5, 0, 1, 0, 2, 2];
var m = 5;
var r = 3;

var counter = -1;

var data = flatInputMatrix.map(function(d, i) {
  i % m === 0 ? counter++ : null;
  return {
    column: i % m,
    row: counter,
    value: d
  };
});

var numbers = svg.selectAll("numbers")
  .data(data)
  .enter()
  .append("text")
  .attr("x", function(d, i) {
    return (i % m) * 50 + 10 + r;
  })
  .attr("y", function(d, i) {
    return Math.floor(i / m) * 50 + 50;
  })
  .style("opacity", 0.5)
  .text(function(d) {
    return d.value;
  });

numbers.on("mouseover", function(d) {
  var column = d.column;
  numbers.filter(function(d) {
      return d.column === column
    })
    .style("opacity", 1)
}).on("mouseout", function() {
  numbers.style("opacity", 0.5)
})
<script src="https://d3js.org/d3.v4.min.js"></script>

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I'll probably use #2 as there will be other groupings not by column that I want to do.
Hi again. I have a new question concerning the possibility of adding axes to the rows/columns of the data: stackoverflow.com/questions/43461986/…
I just answered it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.