cicero38
cicero38

Reputation: 11

How to draw a line in D3 using csv

I am trying to draw a line in D3 using point data obtained from CSV input. While I can cycle through my data (in dataSet), is it even possible to assign x2 and y2 coordinates from the next index?

//variable 'dataSet' holds all data points
//x-coordinate in index [0], and y-coordinate in index [1]

svg.selectAll("line")
  .data(dataSet)
  .enter().append("line")
    .attr("x1", function(d){
      return d[0];
    })
    .attr("y1", function(d){
      return d[1];
    })
    .attr("x2", function(d){
      return d[0]; //here's the problem, how can I access the next x-coordinate?
    })
    .attr("y2", function(d){
      return d[1]; //here's the problem, how can I access the next y-coordinate?
    })                
    .attr("interpolate", "linear")

Upvotes: 1

Views: 102

Answers (1)

altocumulus
altocumulus

Reputation: 21578

The callback provided to selection.attr() will be passed the current index as the second argument along with the datum as the first argument. This index can be used to access the next element in the original dataSet bound to the selection:

.attr("x2", function(d, i) {   // d is the datum, i is the index
   return dataSet[i+1][0];     // Peek ahead to the next element of the data array
}

In fact, in the callbacks you can safely assume that d === dataSet[i].

Keep in mind, though, that—when peeking ahead—this will eventually throw a RangeError for the last datum because i + 1 will refer to a non-existing next-to-last element. To safeguard against this you need to implement a check which, depending on your scenario, could be something like this:

  1. Draw a zero-length line to visually end the connected lines:

    dataSet[Math.min(i + 1, dataSet.length - 1)]
    
  2. Close the lines by connecting the last to the first point:

    dataSet[(i + 1) % dataSet.length]
    

Putting all that together your solution might look like this:

var len = dataSet.length;

function next(i) {
  var nextIndex = Math.min(i + 1, len - 1);  // open 
  // var nextIndex =(i + 1) % len;           // closed
  return dataSet[nextIndex];
}

svg.selectAll("line")
  .data(dataSet)
  .enter().append("line")
    // ... set x1, x2
    .attr("x2", function(d, i) {
      return next(i)[0];
    })
    .attr("y2", function(d, i) {
      return next(i)[1];
    });                

Upvotes: 1

Related Questions