text: 
  nv.models.lineWithFocus = function() {
    var margin  = {top: 30, right: 20, bottom: 30, left: 60},
        margin2 = {top: 0, right: 20, bottom: 20, left: 60},
        width = 960,
        height = 500,
        height1 = 400,
        height2 = 100,
        color = d3.scale.category20().range(),
        getX = function(d) { return d.x },
        getY = function(d) { return d.y },
        id = Math.floor(Math.random() * 10000); //Create semi-unique ID incase user doesn't select one
  
    var x = d3.scale.linear(),
        y = d3.scale.linear(),
        x2 = d3.scale.linear(),
        y2 = d3.scale.linear(),
        xAxis = nv.models.axis().scale(x).orient('bottom'),
        yAxis = nv.models.axis().scale(y).orient('left'),
        xAxis2 = nv.models.axis().scale(x2).orient('bottom'),
        yAxis2 = nv.models.axis().scale(y2).orient('left'),
        legend = nv.models.legend().height(30),
        focus = nv.models.line().clipEdge(true),
        context = nv.models.line().interactive(false),
        dispatch = d3.dispatch('tooltipShow', 'tooltipHide'),
        brush = d3.svg.brush()
              .x(x2);
  
  
    //var wrap, gEnter, g, focus, focusLines, contextWrap, focusWrap, contextLines;  //brought all variables to this scope for use within brush function... is this a bad idea?
  
    //var seriesData;  //Temporarily bringing this data to this scope.... may be bad idea (same with above).. may need to rethink brushing
  
    function chart(selection) {
      selection.each(function(data) {
        var seriesData = data.filter(function(d) { return !d.disabled })
              .map(function(d) { return d.values }),
            availableWidth = width - margin.left - margin.right,
            availableHeight1 = height1 - margin.top - margin.bottom,
            availableHeight2 = height2 - margin2.top - margin2.bottom;
  
        x2  .domain(d3.extent(d3.merge(seriesData), getX ))
            .range([0, availableWidth]);
        y2  .domain(d3.extent(d3.merge(seriesData), getY ))
            .range([availableHeight2, 0]);
  
        x   .domain(brush.empty() ? x2.domain() : brush.extent())
            .range([0, availableWidth]);
        y   .domain(y2.domain())
            .range([availableHeight1, 0]);
  
        brush.on('brush', onBrush);
  
        focus
          .width(availableWidth)
          .height(availableHeight1)
          .color(data.map(function(d,i) {
            return d.color || color[i % 10];
          }).filter(function(d,i) { return !data[i].disabled }))
  
        context
          .width(availableWidth)
          .height(availableHeight2)
          .color(data.map(function(d,i) {
            return d.color || color[i % 10];
          }).filter(function(d,i) { return !data[i].disabled }))
  
  
        updateFocus();
  
  
        var wrap = d3.select(this).selectAll('g.wrap').data([data]);
        var gEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 lineWithFocus').append('g');
  
        gEnter.append('g').attr('class', 'focus');
        gEnter.append('g').attr('class', 'context');
        gEnter.append('g').attr('class', 'legendWrap');
  
  
  
        var g = wrap.select('g')
            //.attr('transform', 'translate(0,0)');
  
  
  
  
        // ********** LEGEND **********
  
        legend.width(width/2 - margin.right);
  
        g.select('.legendWrap')
            .datum(data)
            .attr('transform', 'translate(' + (availableWidth / 2) + ',0)')
            .call(legend);
  
  
        //TODO: margins should be adjusted based on what components are used: axes, axis labels, legend
        margin.top = legend.height();
  
  
  
  
        // ********** FOCUS **********
  
        var focusWrap = g.select('.focus')
            .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  
        gEnter.select('.focus').append('g').attr('class', 'x axis');
        gEnter.select('.focus').append('g').attr('class', 'y axis');
        gEnter.select('.focus').append('g').attr('class', 'focusLines');
  
  
        var focusLines = focusWrap.select('.focusLines')
            .datum(data.filter(function(d) { return !d.disabled }))
  
        d3.transition(focusLines).call(focus);
  
  
        xAxis
          .domain(x.domain())
          .range(x.range())
          .ticks( width / 100 )
          .tickSize(-(availableHeight1), 0);
  
        focusWrap.select('.x.axis')
            .attr('transform', 'translate(0,' + y.range()[0] + ')');
        d3.transition(g.select('.x.axis'))
            .call(xAxis);
  
        yAxis
          .domain(y.domain())
          .range(y.range())
          .ticks( height / 36 )
          .tickSize(-(availableWidth), 0);
  
        d3.transition(g.select('.y.axis'))
            .call(yAxis);
  
  
  
  
        // ********** CONTEXT **********
  
        var contextWrap = g.select('.context')
            .attr('transform', 'translate(' + margin2.left + ',' + height1 + ')');
  
        gEnter.select('.context').append('g').attr('class', 'x2 axis');
        gEnter.select('.context').append('g').attr('class', 'y2 axis');
        gEnter.select('.context').append('g').attr('class', 'contextLines');
        gEnter.select('.context').append('g').attr('class', 'x brush')
            .attr('class', 'x brush')
            .call(brush)
          .selectAll('rect')
            .attr('y', -5)
            .attr('height', height2 + 4);
  
        var contextLines = contextWrap.select('.contextLines')
            .datum(data.filter(function(d) { return !d.disabled }))
  
        d3.transition(contextLines).call(context);
  
  
        xAxis2
          .domain(x2.domain())
          .range(x2.range())
          .ticks( width / 100 )
          .tickSize(-(availableHeight2), 0);
  
        contextWrap.select('.x2.axis')
            .attr('transform', 'translate(0,' + y2.range()[0] + ')');
        d3.transition(contextWrap.select('.x2.axis'))
            .call(xAxis2);
  
  
        yAxis2
          .domain(y2.domain())
          .range(y2.range())
          .ticks( availableHeight2 / 24 )
          .tickSize(-(availableWidth), 0);
  
        contextWrap.select('.y2.axis');
  
        d3.transition(contextWrap.select('.y2.axis'))
            .call(yAxis2);
  
  
  
  
  
  
        // ********** EVENT LISTENERS **********
  
        legend.dispatch.on('legendClick', function(d,i) {
          d.disabled = !d.disabled;
  
          if (!data.filter(function(d) { return !d.disabled }).length) {
            data.map(function(d) {
              d.disabled = false;
              wrap.selectAll('.series').classed('disabled', false);
              return d;
            });
          }
  
          selection.transition().call(chart);
        });
  
  /*
        legend.dispatch.on('legendMouseover', function(d, i) {
          d.hover = true;
          selection.transition().call(chart)
        });
        legend.dispatch.on('legendMouseout', function(d, i) {
          d.hover = false;
          selection.transition().call(chart)
        });
  */
  
        focus.dispatch.on('elementMouseover.tooltip', function(e) {
          dispatch.tooltipShow({
            point: e.point,
            series: e.series,
            pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
            seriesIndex: e.seriesIndex,
            pointIndex: e.pointIndex
          });
        });
        focus.dispatch.on('elementMouseout.tooltip', function(e) {
          dispatch.tooltipHide(e);
        });
  
  
  
  
  
        function onBrush() {
          updateFocus();
  
          focusLines.call(focus)
          wrap.select('.x.axis').call(xAxis);
          wrap.select('.y.axis').call(yAxis);
        }
  
        function updateFocus() {
          var yDomain = brush.empty() ? y2.domain() : d3.extent(d3.merge(seriesData).filter(function(d) {
            return getX(d) >= brush.extent()[0] && getX(d) <= brush.extent()[1];
          }), getY);  //This doesn't account for the 1 point before and the 1 point after the domain.  Would fix, but likely need to change entire methodology here
  
          if (typeof yDomain[0] == 'undefined') yDomain = y2.domain(); //incase the brush doesn't cover a single point
  
  
          x.domain(brush.empty() ? x2.domain() : brush.extent());
          y.domain(yDomain);
  
          //TODO: Rethink this... performance is horrible, likely need to cut off focus data to within the range
          //      If I limit the data for focusLines would want to include 1 point before and after the extent,
          //      Need to figure out an optimized way to accomplish this.
          //      ***One concern is to try not to make the assumption that all lines are of the same length, and
          //         points with the same index have the same x value (while this is true in our test cases, may 
          //         not always be)
          
          focus.xDomain(x.domain());
          focus.yDomain(y.domain());
        }
  
  
      });
  
      return chart;
    }
  
  
  
    // ********** FUNCTIONS **********
  
  
  
  
    // ********** PUBLIC ACCESSORS **********
  
    chart.dispatch = dispatch;
  
    chart.x = function(_) {
      if (!arguments.length) return getX;
      getX = _;
      focus.x(_);
      context.x(_);
      return chart;
    };
  
    chart.y = function(_) {
      if (!arguments.length) return getY;
      getY = _;
      focus.y(_);
      context.y(_);
      return chart;
    };
  
    chart.margin = function(_) {
      if (!arguments.length) return margin;
      margin = _;
      return chart;
    };
  
    chart.width = function(_) {
      if (!arguments.length) return width;
      width = _;
      return chart;
    };
  
    chart.height = function(_) {
      if (!arguments.length) return height;
      height = _;
      height1 =  _ - height2;
      return chart;
    };
  
    chart.contextHeight = function(_) {
      if (!arguments.length) return height2;
      height2 = _;
      height1 = height - _;
      return chart;
    };
  
    chart.id = function(_) {
      if (!arguments.length) return id;
      id = _;
      return chart;
    };
  
  
    // Chart has multiple similar Axes, to prevent code duplication, probably need to link all axis functions manually like below
    chart.xTickFormat = function(_) {
      if (!arguments.length) return x.tickFormat();
      xAxis.tickFormat(_);
      xAxis2.tickFormat(_);
      return chart;
    };
  
    chart.yTickFormat = function(_) {
      if (!arguments.length) return y.tickFormat();
      yAxis.tickFormat(_);
      yAxis2.tickFormat(_);
      return chart;
    };
  
  
  
    //TODO: allow for both focus and context axes to be linked
    chart.xAxis = xAxis;
    chart.yAxis = yAxis;
  
  
    return chart;
  }
  