title: D3.js: Lines in multi-line chart not transitioning properly on update (both location and color)
body: <p>I have multiple, multi-line charts that a user can move between using radio buttons at the top of the page. JSFiddle here: <a href="https://jsfiddle.net/etonblue/wh07bk1u/6/" rel="nofollow noreferrer">https://jsfiddle.net/etonblue/wh07bk1u/6/</a>. I am having two issues with line transitions:</p>
  <ol>
  <li>Certain lines are not being removed on update. For example, if you click on the &quot;Annual Enrollment Change %&quot; radio button, you can see two green lines near the bottom (the ones without dots) that are 'left-over' from the &quot;Current Ratio&quot; chart. The update function is properly using  new data to draw the new green lines (the ones with the dots), just not transitioning/removing the old green lines. You can see this in other instances as well with different lines (e.g., click on Debt Service Coverage Ratio and then Aggregated 3-Year Total Margin- green line and pink line without dots). I am still trying to determine the pattern, but my assumption is that it is due to how I am updating the lines. <strong>EDIT: Added More Code</strong></li>
  </ol>
  <p>My Initial Chart:</p>
  <pre><code>var initialChart = function(m){
  
      var selectMetric = nestData.filter(d =&gt; d.key == m);
  
      var metricGroup = svg.selectAll(&quot;.metricGroup&quot;)
          .data(selectMetric, d =&gt; d ? d.key : this.key)
          .enter()
          .append(&quot;g&quot;)
          .attr(&quot;class&quot;, &quot;metricGroup&quot;)
          .each(function(d){
              x.domain([(d.value.ymin - .5), (d.value.ymax + .5)])
              y.domain([(ydom[(m-1)][0]), (ydom[(m-1)][1])])
          })
  
      var lineGroup = metricGroup.selectAll(&quot;.lineGroup&quot;)
          .attr(&quot;class&quot;, &quot;lineGroup&quot;)
          .data(d =&gt; d.value.school)
          .enter()
  
      lineGroup.append(&quot;path&quot;)
          .attr(&quot;d&quot;, d =&gt; line(d.values))
          .attr(&quot;class&quot;, &quot;line &quot; + &quot;slash&quot; + m)
          .attr('id', function (d) {
              return d.key.replace(/\s+/g, '') + m;
          })
          .attr(&quot;transform&quot;, `translate(0, 0)`)
          .attr(&quot;fill&quot;, &quot;none&quot;)
          .attr(&quot;stroke&quot;, d =&gt; color(d.key))
          .attr(&quot;stroke-linecap&quot;, &quot;round&quot;)
          .attr(&quot;stroke-linejoin&quot;, &quot;round&quot;)
          .attr(&quot;stroke-width&quot;, 2)
  
      lineGroup.selectAll(&quot;circle&quot;)
          .data(d =&gt; d.values)
          .enter()
          .append(&quot;circle&quot;)
          .attr(&quot;class&quot;, &quot;dot &quot; + &quot;dab&quot; + m)
          .attr('id', function (d) {
              return d.school.replace(/\s+/g, '') + m;
          })
          .attr(&quot;cx&quot;, d =&gt; x(d.year))
          .attr(&quot;cy&quot;, 0)
          .style('fill', d =&gt; color(d.school))
          .transition()
          .delay(function(d,i){return(i*2)})
          .duration(500)
          .attr(&quot;r&quot;, 4)
          .attr(&quot;cx&quot;, d =&gt; x(d.year))
          .attr(&quot;cy&quot;, d =&gt; d.mval &lt; y.domain()[0] ? y(y.domain()[0]) : d.mval &gt; y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
  
      var xAxis = svg.append(&quot;g&quot;)
          .attr(&quot;class&quot;, &quot;x axis&quot;)
          .attr(&quot;transform&quot;, &quot;translate(0,&quot; + height + &quot;)&quot;)
          .call(d3.axisBottom(x).ticks(8).tickFormat(d3.format(&quot;d&quot;)))
          .call(g =&gt; {
                  g.selectAll(&quot;text&quot;)
                      .style(&quot;text-anchor&quot;, &quot;middle&quot;)
                      .attr('fill', '#A9A9A9')
                  g.selectAll(&quot;line&quot;)
                      .attr('stroke', '#A9A9A9')
                  g.select(&quot;.domain&quot;)
                      .attr('stroke', '#A9A9A9')
              })
  
      var yAxis = svg.append(&quot;g&quot;)
          .attr(&quot;class&quot;, &quot;y axis&quot;)
          .attr(&quot;transform&quot;, `translate(0, 0)`)
          .call(d3.axisLeft(y).ticks(28, &quot;s&quot;).tickSize(-width).tickFormat(d3.format(&quot;,.2f&quot;)))
          .call(g =&gt; {
              g.selectAll(&quot;text&quot;)
                  .attr('fill', '#A9A9A9')
              g.selectAll(&quot;line&quot;)
                  .attr('stroke', '#A9A9A9')
                  .attr('stroke-width', 0.7)
                  .attr('opacity', 0.3)
              g.select(&quot;.domain&quot;).remove()
          })
          .append('text')
              .attr(&quot;transform&quot;, &quot;rotate(-90)&quot;)
              .attr(&quot;y&quot;, 0 - 60)
              .attr(&quot;x&quot;, 0 - (height / 2))
              .attr(&quot;dy&quot;, &quot;1em&quot;)
              .attr(&quot;fill&quot;, &quot;#A9A9A9&quot;)
              .style(&quot;text-anchor&quot;, &quot;middle&quot;)
              .text(yname[m-1])
              .attr(&quot;class&quot;, &quot;y axis label&quot;)
  }
  </code></pre>
  <p>Update function:</p>
  <pre><code>var updateChart = function(m){
  var selectMetric = nestData.filter(d =&gt; d.key == m);
  
      var metricGroup = svg.selectAll(&quot;.metricGroup&quot;)
          .data(selectMetric, d =&gt; d ? d.key : this.key)
          .enter()
          .append(&quot;g&quot;)
          .attr(&quot;class&quot;, &quot;metricGroup&quot;)
          .each(function(d){
              x.domain([(d.value.ymin - .5), (d.value.ymax + .5)])
              y.domain([-2,20])
          })
  
      var lineGroup = metricGroup.selectAll(&quot;.lineGroup&quot;)
          .attr(&quot;class&quot;, &quot;lineGroup&quot;)
          .data(d =&gt; d.value.school)
          .enter()
  
      lineGroup.append(&quot;path&quot;)
          .attr(&quot;d&quot;, d =&gt; line(d.values))
          .attr(&quot;class&quot;, &quot;line&quot;)
          .attr('id', function (d) {return d.key.replace(/\s+/g, '');})
          .attr(&quot;transform&quot;, `translate(0, 0)`)
          .attr(&quot;fill&quot;, &quot;none&quot;)
          .attr(&quot;stroke&quot;, d =&gt; color(d.key))
          .attr(&quot;stroke-width&quot;, 2)
  </code></pre>
  <ol start="2">
  <li>The other issue I am having appears to be related to my legend/onClick/onMouseout functions. If you click down each of the metric radio buttons, all of the colors (lines and dots) are properly drawn. However, if you click on one of the legend tags, mouseout, and then move to a different chart by clicking a different radio button, many of the &quot;lines&quot; are drawn in the incorrect color and they remain the incorrect color until you move your mouse over and back out of the legend. I am again trying to track why this is happening (and why it affects some lines and not others), with no luck so far.</li>
  </ol>
  <p>Setting the color:</p>
  <pre><code>    var schoolnames = allData.map(d =&gt; d.school).filter((value, index, self) =&gt; self.indexOf(value) === index)
  
      var color = d3.scaleOrdinal()
          .domain(schoolnames)
          .range([&quot;#393b79&quot;,&quot;#5254a3&quot;,&quot;#6b6ecf&quot;,&quot;#9c9ede&quot;,&quot;#637939&quot;,&quot;#8ca252&quot;,&quot;#b5cf6b&quot;,&quot;#cedb9c&quot;,&quot;#8c6d31&quot;,&quot;#bd9e39&quot;,&quot;#e7ba52&quot;,&quot;#e7cb94&quot;,&quot;#843c39&quot;,&quot;#ad494a&quot;,&quot;#d6616b&quot;,&quot;#6baed6&quot;,&quot;#9ecae1&quot;,&quot;#c6dbef&quot;,&quot;#e6550d&quot;,&quot;#fd8d3c&quot;,&quot;#e7969c&quot;,&quot;#7b4173&quot;,&quot;#a55194&quot;,&quot;#ce6dbd&quot;,&quot;#de9ed6&quot;,&quot;#3182bd&quot;,&quot;#fdae6b&quot;,&quot;#fdd0a2&quot;,&quot;#31a354&quot;,&quot;#74c476&quot;,&quot;#a1d99b&quot;,&quot;#c7e9c0&quot;,&quot;#756bb1&quot;,&quot;#9e9ac8&quot;,&quot;#bcbddc&quot;,&quot;#dadaeb&quot;])
  </code></pre>
  <p>The &quot;onClick&quot; function (without tooltip code). Note that the tooltips work fine in browser, but are not properly positioned in the JSFiddle.</p>
  <pre><code>function onClick(sel) {
  
      svg.selectAll(&quot;.line&quot;)
          .transition().duration(200)
          .style(&quot;stroke&quot;, &quot;lightgrey&quot;)
          .style(&quot;opacity&quot;, &quot;0.2&quot;)
          
      svg.selectAll(&quot;.dot&quot;)
          .transition().duration(200)
          .style(&quot;fill&quot;, &quot;lightgrey&quot;)
          .style(&quot;opacity&quot;, &quot;0.2&quot;)
  
      svg.selectAll(&quot;#&quot; + sel.replace(/\s+/g, '')).raise()
          .transition()
          .select('.line')
          .style(&quot;stroke&quot;, function(d) {return color(sel)})
          .attr(&quot;stroke-width&quot;, 3)
          .style(&quot;opacity&quot;, &quot;1&quot;)
  // do separate line and dot selections do anything? //
          .select('.dot')
          .style(&quot;fill&quot;, function(d) {return color(sel)})
          .style(&quot;opacity&quot;, &quot;1&quot;)
  
      d3.select('#key').selectAll('li')
          .select(d =&gt; d===sel?this:null)
          .transition().duration(200)
          .style('background', '#ededed')
  }
  </code></pre>
  <p>onMouseout function:</p>
  <pre><code>function onMouseout (sel) {
  
      svg.selectAll(&quot;.line&quot;)
          .transition()
          .duration(200).delay(50)
          .style(&quot;stroke&quot;, function(d) {
              return color(d.key)
          })
          .attr(&quot;stroke-width&quot;, 2)
          .style(&quot;opacity&quot;, &quot;1&quot;)
   
      svg.selectAll(&quot;.dot&quot;)
          .transition().duration(200).delay(50)
          .style(&quot;fill&quot;, function(d) {
              return color(d.school)
          })
          .style(&quot;opacity&quot;, &quot;1&quot;)
  
      d3.select('#key').selectAll('li')
          .select(d =&gt; d===sel?this:null)
          .transition().duration(500)
          .style('background', '#ffffff')
  }
  </code></pre>
  <p>Any suggestions would be appreciated.</p>