title: Adding and removing elements from D3 Visualization with animation
body: <p>long time user first time asking a question here (first time I haven't been able to solve a problem using answers I searched for). I've recreated the uber chord chart in JS D3 with my own data. My implementation can be found <a href="https://www.purdue.edu/oir/test/IanJS/" rel="nofollow">here</a>, though that address may not stay good forever so here is the code (forgive a few misalignments throughout):</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="Content-Type" content="text/html;charset=utf-8"/&gt;
      &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
      &lt;script type="text/javascript" src="d3/d3.js"&gt;&lt;/script&gt;
      &lt;script type="text/javascript" src="d3/d3.layout.js"&gt;&lt;/script&gt;
      &lt;link type="text/css" rel="stylesheet" href="style.css"/&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;div id="body"&gt;
        &lt;div id="footer"&gt;
          Purdue OIR Testing - Migration
          &lt;div class="hint"&gt;mouseover groups to highlight&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div id="tooltip"&gt;&lt;/div&gt;
      &lt;script type="text/javascript"&gt;
  
  
  //import the data and call the draw chords function 
  d3.text("migrationdata.csv", function(data) {
      var matrix = d3.csv.parseRows(data).map(function(row) {
          return row.map(function(value) {
              return +value;
          });
      });
      d3.text("headersColors.csv", function(headerdata) {
      var headersColors = d3.csv.parseRows(headerdata);
      var headers = headersColors[1];
      var colors = headersColors[2];
  
      drawChords(matrix, headers, colors);
   });
  });
  
  //create the chord viz
  function drawChords (matrix, headers, colors){
  
      var w = 980,
          h = 800,
          r1 = h / 2,
          r0 = r1 - 110,
          fadeOutA = 0,
          fadeInA = 0.8;
  
      var fill = d3.scale.category20c();
  
      var chord = d3.layout.chord()
          .padding(.02)
          .sortSubgroups(d3.descending)
          .sortChords(d3.descending);
  
      var arc = d3.svg.arc()
          .innerRadius(r0)
          .outerRadius(r0 + 20);
  
      var svg = d3.select("body").append("svg:svg")
          .attr("width", w)
          .attr("height", h)
        .append("svg:g")
          .attr("id", "circle")
          .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
  
      svg.append("circle")
          .attr("r", r0 + 20);
          //.attr("fill-opacity",0);
  
      //assign the matrix
        chord.matrix(matrix);
  
      //create the groups
        var g = svg.selectAll("g.group")
            .data(chord.groups)
          .enter().append("svg:g")
            .attr("class", "group")
            .on("mouseover", mouseover)
            .on("mouseout", function (d) { d3.select("#tooltip").style("visibility", "hidden") });
  
        g.append("svg:path")
            .style("stroke", function(d) { return colors[d.index]; })
            .style("fill", function(d) { return colors[d.index]; })
            .attr("d", arc);
  
        g.append("svg:text")
            .each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
            .attr("dy", ".35em")
            .attr("text-anchor", function(d) { return d.angle &gt; Math.PI ? "end" : null; })
            .attr("transform", function(d) {
              return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
                  + "translate(" + (r0 + 26) + ")"
                  + (d.angle &gt; Math.PI ? "rotate(180)" : "");
            })
            .text(function(d) { return headers[d.index]; });
  
        var chordPaths = svg.selectAll("path.chord")
            .data(chord.chords)
          .enter().append("svg:path")
            .attr("class", "chord")
            .style("stroke", function(d) { return d3.rgb(colors[d.source.index]).darker(); })
            .style("fill", function(d) { return colors[d.source.index]; })
            .attr("d", d3.svg.chord().radius(r0))
            .on("mouseover", function (d) {
                d3.select("#tooltip")
                  .style("visibility","visible")
                  .html(chordTip(d))
                  .style("left", (d3.event.pageX - 100) + "px")     
                  .style("top", (d3.event.pageY - 100) + "px");  
                 })
             .on("mouseout", function (d) { d3.select("#tooltip").style("visibility", "hidden") });
  
        function chordTip (d) {
          var p = d3.format(".1%"), q = d3.format(",.2r")
          return "Migration Info:&lt;br/&gt;"
            +  headers[d.source.index] + " → " + headers[d.target.index]
            + ": " + Math.round(d.source.value) + "&lt;br/&gt;"
            + headers[d.target.index] + " → " + headers[d.source.index]
            + ": " + Math.round(d.target.value) + "&lt;br/&gt;";
        }
  
        function groupTip (d) {
          return "College Info:&lt;br/&gt;"
              + headers[d.index] + " : " + Math.round(d.value) + "&lt;br/&gt;";
          }
  
        function mouseover(d, i) {
          d3.select("#tooltip")
            .style("visibility", "visible")
            .html(groupTip(d))
            .style("top", function () { return (d3.event.pageY - 80)+"px"})
            .style("left", function () { return (d3.event.pageX - 130)+"px";})
  
          chordPaths.classed("fade", function(p) {
            return p.source.index != i
                &amp;&amp; p.target.index != i;
          });
    }
  
  }
  
  
  
  // Returns an event handler for fading a given chord group.
  function fade(opacity) {
    return function(d, i) {
      svg.selectAll("path.chord")
          .filter(function(d) { return d.source.index != i &amp;&amp; d.target.index != i; })
        .transition()
          .style("stroke-opacity", opacity)
          .style("fill-opacity", opacity);
    };
  }
  
      &lt;/script&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>This works fine, and is totally functional. It shows student movement between colleges from Fall 2012-Fall 2013 (I plan to make the explanation on screen a bit better as I go). My next step is to make this drillable. So for instance, if you click a college I want to expand that college out into its departments and show the chords between various departments and "Other" which would be the combination of all other colleges. Further, you would be able to drill into department to get major-level detail in the same fashion. I have all the raw data I need to do this, and I am fairly confident I know how I can use it to create the new matrices on the fly when clicking on a group.</p>
  
  <p>My question is, doing what I describe above is all fairly straight forward if I just dump the current viz for a new one with new data each time, but that's going to be a harsh transition. I'd prefer something with animation like <a href="http://exposedata.com/tutorial/chord/latest.html" rel="nofollow">this</a>. However, that example only works if your matrices are the same size on each end of the transition. Because of how I'd like to drill into this data, that will not always be true for me. I could have fewer or more groups/chords than I did before. My question is, if I create a new chord layout with a bigger/smaller matrix than what is currently on screen, can I somehow smoothly animate the new/un-needed groups/chords in/away? If so, how would I go about this and are there any examples out there?</p>
  
  <p>I'm still fairly new to D3 but I'm trying to learn quickly as there is a ton of demand here for these types of visualizations. If there is a tutorial on this feel free to simply link it, I've been researching this on and off for a few days now and haven't found anything satisfactory explaining how to smoothly add/remove elements in a d3 layout.</p>