title: d3js - How to plot a multi line chart chart for multiple groups of items that can be updated?
body: <p>I am a very new beginner to d3 and have currently got a simple line chart working displaying two lines for some data for a single group. What I would like to do is be able to create multiple lines for multiple groups in a flexible way. Each group would have several lines and they would be colour coded for the group parent - in my data in this case it's asset or stock ticker</p>
  
  <p>Currently you can see in my code I am manually creating an array for each path but i guess this could get really messy if i start to have 100's of paths. Is there a better way to do this?</p>
  
  <p>I've tried to use d3.nest but i just cannot for the life of me figure how the data should be so can apply the update/enter/exit pattern for each group of lines</p>
  
  <p>Here is my WIP code:</p>
  
  <pre><code>
  &lt;!DOCTYPE html&gt;
  &lt;meta charset="utf-8"&gt;
  &lt;style&gt; /* set the CSS */
  
  body { font: 12px Arial;}
  
  path { 
      stroke: steelblue;
      stroke-width: 2;
      fill: none;
  }
  
  .axis path,
  .axis line {
      fill: none;
      stroke: grey;
      stroke-width: 1;
      shape-rendering: crispEdges;
  }
  
  &lt;/style&gt;
  &lt;body&gt;
  &lt;div id="graphDiv"&gt;&lt;/div&gt;
  
  &lt;!-- load the d3.js library --&gt;    
  &lt;script src="https://d3js.org/d3.v5.min.js"&gt;&lt;/script&gt;
  
  &lt;script&gt;
      var data_set = [{
      'Date': '2009-03-23',
      'Raw': 25,
      'Raw2': 25,
      'Asset': 'A'
    },
    {
      'Date': '2009-03-24',
      'Raw': 28,
      'Raw2': 25.4,
      'Asset': 'A'
    },
    {
      'Date': '2009-03-25',
      'Raw': 26,
      'Raw2': 25.37,
      'Asset': 'B'
    },
    {
      'Date': '2009-03-26',
      'Raw': 22,
      'Raw2': 25.03,
      'Asset': 'B'
    },
    {
      'Date': '2009-03-27',
      'Raw': 19,
      'Raw2': 24.42,
      'Asset': 'C'
    },
    {
      'Date': '2009-03-28',
      'Raw': 23,
      'Raw2': 24.28,
      'Asset': 'D'
    }
  ]
  
  var margin = {
    top: 30,
    right: 50,
    bottom: 30,
    left: 50
  };
  var svgWidth = 600;
  var svgHeight = 1000;
  var graphWidth = svgWidth - margin.left - margin.right;
  var graphHeight = svgHeight - margin.top - margin.bottom;
  // var parseDate = d3.timeParse("%d/%m/%Y");
  var parseDate = d3.timeParse("%Y-%m-%d");
  
  var x = d3.scaleTime().range([0, graphWidth]);
  var y = d3.scaleLinear().range([graphHeight, 0]);
  var z = d3.scaleOrdinal(d3.schemeCategory10); // for colours
  var xAxis = d3.axisBottom().scale(x).ticks(10);
  var yAxis = d3.axisLeft().scale(y).ticks(10);
  
  // Need to create the lines manually for each bit of data
  var line = d3.line()
    .x(function(d) {
      return x(d.date);
    })
    .y(function(d) {
      return y(d.y);
    });
  
  // Creates the SVG area within the div on the dom 
  // Just doing this once 
  var svg = d3.select("#graphDiv")
    .append("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight)
  var g = svg.append("g")
    .attr("transform",
      "translate(" + margin.left + "," + margin.top + ")")
    .call(d3.zoom().on("zoom", function() {
      svg.attr("transform", d3.event.transform)
    }));
  
  // Add the X Axis
  g.append("g").attr("class", "x axis")
    .attr("transform", "translate(0," + graphHeight + ")")
    .call(xAxis);
  // Text label for x axis 
  g.append("text")
    .style("text-anchor", "middle")
    .text("timeseries dates")
    .attr("transform", "translate(" + (graphWidth / 2) + " ," + (graphHeight + margin.top) + ")");
  
  // Add the Y Axis
  g.append("g")
    .attr("class", "y axis")
    .call(yAxis);
  // text label for the y axis
  g.append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 0 - margin.left)
    .attr("x", 0 - (graphHeight / 2))
    .attr("dy", "1em")
    .style("text-anchor", "middle")
    .text("price points");
  
  
  function drawGraph(data_set) {
  
    let pathData = []
    //assume 2 paths
    pathData.push([])
    pathData.push([])
  
    // Pass in the data here 
    data_set.forEach(function(d) {
  
      let path0 = {}
      let path1 = {}
  
      path0.date = parseDate(d.Date)
      path1.date = parseDate(d.Date)
  
      path0.y = +d.Raw
      path1.y = +d.Raw2
  
      pathData[0].push(path0)
      pathData[1].push(path1)
  
    });
  
    x.domain(d3.extent(data_set, function(d) {
      return parseDate(d.Date);
    }));
    y.domain([
      d3.min(data_set, function(d) {
        return Math.min(d.Raw, d.Raw2)
      }),
      d3.max(data_set, function(d) {
        return Math.max(d.Raw, d.Raw2)
      })
    ]);
  
    var lines = g.selectAll(".path")
      .data(pathData)
  
    lines.exit().remove()
  
    var enter = lines.enter()
      .append("path")
      .attr("class", "path")
      .style("stroke", (d, i) =&gt; z(i))
  
    var merge = enter.merge(lines)
      .attr("d", line)
  
  }
  
  // display initial chart
  window.onload = drawGraph(data_set)
  // Push new data every 5 seconds for a specific date
  var h = setInterval(function() {
    data_set.push({
      'Date': '2009-03-29',
      'Raw': Math.floor(Math.random() * 50),
      'Raw2': Math.floor(Math.random() * 25),
      'Asset': 'A'
    }, {
      'Date': '2009-03-30',
      'Raw': Math.floor(Math.random() * 50),
      'Raw2': Math.floor(Math.random() * 25),
      'Asset': 'A'
    }, {
      'Date': '2009-03-31',
      'Raw': Math.floor(Math.random() * 50),
      'Raw2': Math.floor(Math.random() * 25),
      'Asset': 'A'
    }, {
      'Date': '2009-04-01',
      'Raw': Math.floor(Math.random() * 50),
      'Raw2': Math.floor(Math.random() * 25),
      'Asset': 'A'
    }, {
      'Date': '2009-04-02',
      'Raw': Math.floor(Math.random() * 50),
      'Raw2': Math.floor(Math.random() * 25),
      'Asset': 'A'
    }, {
      'Date': '2009-04-03',
      'Raw': Math.floor(Math.random() * 50),
      'Raw2': Math.floor(Math.random() * 25),
      'Asset': 'A'
    });
    drawGraph(data_set);
  }, 5000);
  &lt;/script&gt;
  &lt;/body&gt;```
  
  
  
  </code></pre>