Search code examples
d3.jslinegraph

d3 nested line graph


I am new to d3.js (currently using d3.v4) and am stuck trying to use d3.nest to plot multiple lines.

This is the code I have:

var color = d3.scaleOrdinal().range(
'#673ab7',
'#9c27b0',
'#e91e63',
'#f44336',
'#ff5722',
'#ff9800',
'#ffc107',
'#ffeb3b',
'#cddc39',
'#8bc34a',
'#4caf50',
'#009688']);

var line = d3.line()
  .x(function(d) { return x(d.day); })
  .y(function(d) { return y(d.temp); });     

d3.csv('/static/data/temp_d3.csv', function(error, data){
  data.forEach(function(d){
    d.day= +d.day,
    d.temp= +d.temp;
  });

  //nest the entries by month
  var dataNest = d3.nest()
    .key(function(d) {return d.month;}).sortKeys(d3.ascending)
    .key(function(d) {return d.day;}).sortKeys(d3.ascending)
    .entries(data);  

  //loop through each symbol/key
  dataNest.forEach(function(d){
    svg.append('path')
    .data([data])
    .attr('class','line')
    .style('stroke',function() {
      return d.color = color(d.key);})
    .attr('d', line);
  });
});//end of read csv    

This is the graph I get, which doesn't seem like the points are sorted at all. My data file is in the format of

[month,day,temp]
[x , y ,z]
.
.
[x, y, z ]

and the file is not sorted in any way. I want to nest and sort by month and day and have 12 different lines (with different colors) on a plot.. Can somebody help me? Thanks.


Solution

  • To my mind you're wanting to nest by month and sort by day, but not nest by day like you're currently doing:

      var dataNest = d3.nest()
        .key(function(d) {return d.month;}).sortKeys(d3.ascending)
        //.key(function(d) {return d.day;}).sortKeys(d3.ascending)
        .sortValues (function(a,b) { return a.day > b.day ? 1 : -1; })
        .entries(data)
        ; 
    

    the line function will then need to be called slightly differently as the data is in the .values part of d

    .attr('d', function(d) { return line (d.values); })
    

    (This of course depends on not having multiple temperatures with the same month and day, in which case you'd nest on day as well but then need more code to average the temperatures, which would be a bit more complicated)


    To be a completist I'd also change your adding the lines code to be more d3'ish like so, but this is v3 code I'm using here (I haven't updated myself to v4 yet)

      svg.selectAll("path.line").data(dataNest, function(d) { return d.key; })
        .enter()
        .append('path')
        .attr('class','line')
        .style('stroke',function(d) {
             return color(d.key);})
        .attr('d', function(d) { return line (d.values); })
        ;