title: d3.js brush with multiline chart
body: <p>I'm making a multi-line chart and using a brush to select time periods. It's broadly based on Mike Bostock's example at <a href="http://bl.ocks.org/mbostock/1667367" rel="nofollow">http://bl.ocks.org/mbostock/1667367</a></p>
  
  <p>My chart is at <a href="http://lowercasen.com/dev/d3/general/piezobrush.html" rel="nofollow">http://lowercasen.com/dev/d3/general/piezobrush.html</a></p>
  
  <p>My problem is in selecting the multiple lines in my 'focus' area to apply the brush to. I've nested the data based on a key, so the data is within a function. Because the function that calls my brush is outside that function, it can't access the data and I'm getting a TypeError: undefined is not an object (evaluating 'data.length')</p>
  
  <p>Here's the code that nests the data:</p>
  
  <pre><code>     dataNest.forEach(function(d, i) {
  
         focus.append("path")
             .attr("class", "line")
                   .attr("id", d.key.replace(/\s+/g, ''))  //the replace stuff is getting rid of spaces
                   .attr("d", levelFocus(d.values)); 
  
         context.append("path")
              .attr("class", "line")
                   .attr("id", d.key.replace(/\s+/g, ''))  //the replace stuff is getting rid of spaces
                   .attr("d", levelContext(d.values)); 
  </code></pre>
  
  <p>and at the bottom I have the function for the brush:</p>
  
  <pre><code>     function brushed() {
         xFocus.domain(brush.empty() ? xContext.domain() : brush.extent());
         focus.selectAll(".line").attr("d", levelFocus(d.values));
         focus.select(".x.axis").call(xAxisFocus);
       }
  </code></pre>
  
  <p>It works fine for the x axis (if I comment out the line where I'm trying to select the lines) but I don't know how to select the lines correctly.</p>
  
  <p>Apologies for any garbled syntax or confusing language, my coding skills are basic at best.</p>
  
  <p>Any help is greatly appreciated, I've searched for hours for a solution.</p>
  
  <p>Here's the full code as requested by Lars</p>
  
  <pre><code>    &lt;!DOCTYPE html&gt;
      &lt;html lang="en"&gt;
      &lt;head&gt;
              &lt;meta charset="utf-8"&gt;
              &lt;title&gt;Multiline with brush&lt;/title&gt;
      &lt;script src="http://d3js.org/d3.v3.js"&gt;&lt;/script&gt;
      &lt;script src="d3/tooltip.js"&gt;&lt;/script&gt;
          &lt;link href="styles/evidentlySoCharts.css" rel="stylesheet"&gt;
          &lt;meta name="viewport" content="initial-scale=1"&gt;   
  
      &lt;style&gt;
  
      svg {
        font: 10px sans-serif;
      }
  
      path { 
          stroke-width: 1;
          fill: none;
      }
  
      #Stream1, #Nebo1D {
          stroke: #009390;
      }
  
      #Stream1Legend, #Nebo1DLegend {
          fill: #009390;
      }
  
      #Stream2, #Nebo2D {
          stroke: #8dc63f;
      }
  
      #Stream2Legend, #Nebo2DLegend {
          fill: #8dc63f;
      }
  
      #Stream3, #Nebo1S {
          stroke: #132d46;
      }
  
      #Stream3Legend, #Nebo1SLegend {
          fill: #132d46;
      }
  
      #Stream4, #Nebo2S {
          stroke: #aaa813;
      }
  
      #Stream4Legend, #Nebo2SLegend {
          fill: #aaa813;
      }
  
      #Stream5, #Nebo3 {
          stroke: #619dd4;
      }
  
      #Stream5Legend, #Nebo3Legend {
          fill: #619dd4;
      }
  
      .pn1d, .pn2d {
        fill: none;
        clip-path: url(#clip);
      }
  
      .pn1d {
        stroke: #009390;
      }
  
      .pn2d {
        stroke: #1b4164;
      }
  
      .axis path,
      .axis line {
        fill: none;
        stroke: #000;
        stroke-width: 1px;
        shape-rendering: crispEdges;
      }
  
      .brush .extent {
        stroke: #fff;
        fill-opacity: .125;
        shape-rendering: crispEdges;
      }
  
      &lt;/style&gt;
          &lt;/head&gt;
  
  
  
      &lt;body&gt;
      &lt;script&gt;
  
      var marginFocus = {top: 10, right: 10, bottom: 250, left: 40},
          marginContext = {top: 430, right: 10, bottom: 170, left: 40},
          width = 960 - marginFocus.left - marginFocus.right,
          heightFocus = 650 - marginFocus.top - marginFocus.bottom,
          heightContext = 650 - marginContext.top - marginContext.bottom;
          legendOffset = 550;
  
      var parseDate = d3.time.format("%d/%m/%y %H:%M").parse;
  
      var xFocus = d3.time.scale().range([0, width]),
          xContext = d3.time.scale().range([0, width]),
          yFocus = d3.scale.linear().range([heightFocus, 0]),
          yContext = d3.scale.linear().range([heightContext, 0]);
  
      var xAxisFocus = d3.svg.axis().scale(xFocus).orient("bottom"),
          xAxisContext = d3.svg.axis().scale(xContext).orient("bottom"),
          yAxisFocus = d3.svg.axis().scale(yFocus).orient("left");
  
      var levelFocus = d3.svg.line()
          .interpolate("linear")
          .x(function(d) { return xFocus(d.date); })
          .y(function(d) { return yFocus(d.level); });
  
  
      var levelContext = d3.svg.line()
          .interpolate("linear")
          .x(function(d) { return xContext(d.date); })
          .y(function(d) { return yContext(d.level); });
  
      var svg = d3.select("body").append("svg")
          .attr("width", width + marginFocus.left + marginFocus.right)
          .attr("height", heightFocus + marginFocus.top + marginFocus.bottom);
  
      svg.append("defs").append("clipPath")
          .attr("id", "clip")
        .append("rect")
          .attr("width", width)
          .attr("height", heightFocus);
  
      var focus = svg.append("g")
          .attr("class", "focus")
          .attr("transform", "translate(" + marginFocus.left + "," + marginFocus.top + ")");
  
      var context = svg.append("g")
          .attr("class", "context")
          .attr("transform", "translate(" + marginContext.left + "," + marginContext.top + ")");
  
      d3.csv("data/PiezoNeboNestSimple.csv", function(error, data) {
          data.forEach(function(d) {
          d.date = parseDate(d.date);
          d.level = +d.level;
          });
  
        xFocus.domain(d3.extent(data.map(function(d) { return d.date; })));
        yFocus.domain([d3.min(data.map(function(d) { return d.level; })) -2,0]);
        xContext.domain(xFocus.domain());
        yContext.domain(yFocus.domain());
  
          // Nest the entries by piezo
          var dataNest = d3.nest()
              .key(function(d) {return d.piezo;})
              .entries(data);
  
          legendSpace = width/dataNest.length; // spacing for legend // ******
  
      var brush = d3.svg.brush()
          .x(xContext)
          .on("brush", brushed);
  
  
      focus.selectAll("g").data(dataNest)
          .enter()
          .append("g")
          .attr("class", "line")
          .attr("id", function(d) { return d.key.replace(/\s+/g, '') })  //the replace stuff is getting rid of spaces
          .append("path")
          .attr("d", function(d) { return levelFocus(d.values); });    
  
      context.selectAll("g").data(dataNest)
          .enter()
          .append("g")
          .attr("class", "line")
          .attr("id", function(d) { return d.key.replace(/\s+/g, '') })  //the replace stuff is getting rid of spaces
          .append("path")
          .attr("d", function(d) { return levelContext(d.values); });    
  
  
        focus.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + heightFocus + ")")
            .call(xAxisFocus);
  
        focus.append("g")
            .attr("class", "y axis")
            .call(yAxisFocus);
  
        context.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + heightContext + ")")
            .call(xAxisContext);
  
        context.append("g")
            .attr("class", "x brush")
            .call(brush)
          .selectAll("rect")
            .attr("y", -6)
            .attr("height", heightContext + 7);
  
      function brushed() {
        xFocus.domain(brush.empty() ? xContext.domain() : brush.extent());
        focus.selectAll(".line").attr("d", levelFocus(dataNest.values));
        focus.select(".x.axis").call(xAxisFocus);
      }
  
      });
  
  
      &lt;/script&gt;
      &lt;/body&gt;
      &lt;/html&gt;
  </code></pre>