title: D3 Force Directed Graph Redraw with Less Edges
body: <p>I am trying to add a threshold to a force directed graph, where I will only include edges between vertices that that are above some threshold I store in a map. My slider is partly working, and the edges successfully get removed. 
  <a href="https://i.stack.imgur.com/H6dAO.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/H6dAO.jpg" alt="Before..."></a></p>
  
  <p><a href="https://i.stack.imgur.com/aQj9y.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/aQj9y.jpg" alt="After..."></a></p>
  
  <p>However, after the edges are removed, the graph stops animating, and there is an error in the console when calling force.start(). Do I really need to add unique ids? In the JSFiddle I linked, he does not do that, and his slider works with no problems.</p>
  
  <p>Thanks!
  <a href="https://i.stack.imgur.com/sKjmA.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/sKjmA.jpg" alt="Console Error"></a>
  There are multiple answers on StackOverflow to similar questions, and I have used them to fix my obvious errors (such as <a href="https://stackoverflow.com/questions/11357974/d3-js-cannot-read-property-weight-of-undefined-when-manually-defining-both">d3.js: &quot;Cannot read property &#39;weight&#39; of undefined&quot; when manually defining both nodes and links for force layout</a>), but I am down to this one. I am using this example: <a href="http://jsfiddle.net/simonraper/TdHgx/?utm_source=website&amp;utm_medium=embed&amp;utm_campaign=TdHgx" rel="nofollow noreferrer">http://jsfiddle.net/simonraper/TdHgx/?utm_source=website&amp;utm_medium=embed&amp;utm_campaign=TdHgx</a> from this website: <a href="http://www.coppelia.io/2014/07/an-a-to-z-of-extra-features-for-the-d3-force-layout/" rel="nofollow noreferrer">http://www.coppelia.io/2014/07/an-a-to-z-of-extra-features-for-the-d3-force-layout/</a></p>
  
  <p>I will send the relevant JS.</p>
  
  <pre><code>         function draw(occurence) {
          var ratio = window.devicePixelRatio || 1;
  
          var width = Math.min(700,0.8*$(window).width()), height = 700;
          var color = d3.scale.category20();
          var svg = d3.select("#" + occurence).append("svg")
              .attr("width", width)
              .attr("height", height)
              .attr("id", "#" + occurence + "svg");
  
          d3.json(occurence + ".json", function(error, graph) {
            if (error) throw error;
  
            var force = d3.layout.force()
              .charge(-120)
              .linkDistance(50)
              .size([width, height]);
  
            force
                .nodes(graph.nodes)
                .links(graph.links)
                .start();
            if (occurence == "occurrences3") {
              console.log(graph.nodes);
              console.log(graph.links);
            }
  
            var graphRec=JSON.parse(JSON.stringify(graph)); //Add this line
  
            var link = svg.selectAll(".link")
                .data(graph.links)
              .enter().append("line")
                .attr("class", "link")
                .style("stroke-width", function(d) { return Math.sqrt(d.value); });
  
            var node = svg.selectAll(".node")
                .data(graph.nodes)
              .enter().append("circle")
                .attr("class", "node")
                .attr("r", 5)
                .style("fill", function(d) { return color(d.group); })
                .call(force.drag);
  
            node.append("title")
                .text(function(d) { return d.name; });
  
            force.on("tick", function() {
              link.attr("x1", function(d) { return d.source.x; })
                  .attr("y1", function(d) { return d.source.y; })
                  .attr("x2", function(d) { return d.target.x; })
                  .attr("y2", function(d) { return d.target.y; });
  
            node.attr("cx", function(d) { return d.x; })
                .attr("cy", function(d) { return d.y; });
            });
  
            node.on("dblclick", function(d) {
              $("#uncuratedGraphsModal").modal();
              var d = d3.select(this).node().__data__;
              var name = d.name;
              $("#uncuratedGraphsModalHeader").text("Node " + name);
              $("#uncuratedGraphsModalBody").empty();
              var edge_by_person = edge_by_person_per_threshold[occurence + "edge_by_person"];
              var edges = edge_by_person[name];
              edges.sort(function(a,b) {
                  return a.dest - b.dest;
              });
              $.each(edges, function(edge) {
                  var new_edge = $("&lt;li&gt;");
                  new_edge.text("Neighbor: " + edges[edge].dest + ", Token: " + edges[edge].token);
                  $("#uncuratedGraphsModalBody").append(new_edge);
              });
            });
            $("#" + occurence + "thresholdSlider").on('input', function(thresh) {
              threshold($("#" + occurence + "thresholdSlider").val());
            });
            //adjust threshold
            function threshold(thresh) {
                var edge_by_person = edge_by_person_per_threshold_unweighted[occurence + "edge_by_person_unweighted"];
                graph.links.splice(0, graph.links.length);
                for (var i = 0; i &lt; graphRec.links.length; i++) {
                  var source = graphRec.links[i].source.name;
                  var dest = graphRec.links[i].target.name;
                  var value = -1;
                  var edges = edge_by_person[source];
                  var found = false;
                  for (var edge = 0; !found &amp;&amp; edge &lt; edges.length; edge++) {
                    if (dest == edges[edge].dest) {
                      value = edges[edge].token;
                      found = true;
                    }
                  }
                  if (value &gt;= thresh) {
                    graph.links.push({
                      source: graphRec.links[i].source.name,
                      target: graphRec.links[i].target.name,
                      value: graphRec.links[i].value
                    });
                  }
                }
                restart();
            }
            //Restart the visualisation after any node and link changes
            function restart() {
              link = link.data(graph.links);
              link.exit().remove();
              link.enter().insert("line", ".node").attr("class", "link")
              .style("stroke-width", function(d) { return Math.sqrt(d.value); });
  
              node = node.data(graph.nodes);
              node.enter().insert("circle", ".cursor").attr("class", "node")
                .attr("r", 5)
                .style("fill", function(d) { return color(d.group); })
                .call(force.drag);
              force
                .nodes(node)
                .links(link)
                .start();
            }
          });
        }
  </code></pre>
  
  <p>This is the JS that he added from the JsFiddle I linked:</p>
  
  <p><a href="https://i.stack.imgur.com/YRmoI.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/YRmoI.jpg" alt="JsAddition"></a></p>
  
  <p>This is my understanding: If you have the same nodes, and you just remove a few edges from graph.links, can't you just do a force.start()? When I directly copy his restart() function, all links are broken, and none get redrawn, even though doing a console.log(graph.links) shows the correct links to-redraw.</p>
  
  <p>I believe that it's talking to the wrong nodes at this point, maybe the wrong SVG. I have multiple SVGs on the same page.</p>