title: Dynamic D3 force graph
body: <p>I am trying to dynamically create a graph from a JSON file of the form:</p>
  
  <pre><code>{"nodes": [{"category": "...", "group": 1, "uid": 0, "number": 1, "complaints": [" ...,..."], "name": "..."}], "links": ['source':"",'target':"",'value':""]}
  </code></pre>
  
  <p>I can correctly draw the graph as I wish it to be displayed however when adding new nodes, the edges are not correctly formed and neither are the radius of the nodes (they are altered according to the number element in the JSON) I was not able to find any code to nor tutorials documenting how to do this in d3. However when you refresh the page the graph appears as I wish it to.</p>
  
  <p>This is the code I have came up with so far in order to try doing so. I feel like there is just a minor change that needs to be made in order to make it work but I cant figure out what it is. The fact that it displays as I wish it to when I refresh the page tells me that there is something wrong with the restart function. </p>
  
  <pre><code>&lt;html&gt;
      &lt;head&gt;
          &lt;style&gt;
              .node {
                  stroke: #fff;
                  stroke-width: 1.5px;
              }
              .link {
                  stroke: #999;
                  stroke-opacity: .6;
              }
              d3-tip {
                  line-height: 1;
                  color: black;
              }
          &lt;/style&gt;
          &lt;script src="https://d3js.org/d3.v3.min.js"&gt;&lt;/script&gt;
          &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"&gt;&lt;/script&gt;
          &lt;script type='text/javascript' src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"&gt; &lt;/script&gt;
      &lt;/head&gt;
  
      &lt;b&gt;
      &lt;/b&gt;
  
  
  
      &lt;script&gt;
  
          $.ajaxSetup({cache: false});
          var json;
          getJSON();
          function getJSON(){
                  $.ajax({
                      'async': false,
                      'global': false,
                      'url': "/categories.json",
                      'dataType': "json",
                      'success': function (data) {
                          json = data;
                          console.log("Updating JSON")
                      }
                  });
                  return json;
          }
  
          window.setInterval(function(){
              getJSON();
              restart();
          }, 5000);
  
  
          var width = 500,
              height = 500;
  
          var color = d3.scale.category20();
  
          var force = d3.layout.force()
              .charge(-120)
              .linkDistance(30)
              .size([width, height]);
  
          var svg = d3.select("body").append("svg")
              .attr("width", width)
              .attr("height", height);
  
          var tip = d3.tip()
              .attr('class', 'd3-tip')
              .offset([-10, 0])
              .html(function (d) {
              return  d.name + "&lt;/span&gt;";
          })
          svg.call(tip);
  
          force.nodes(json.nodes)
              .links(json.links)
              .start();
  
          var link = svg.selectAll(".link")
              .data(json.links)
              .enter().append("line")
              .attr("class", "link")
              .style("stroke-width", function (d) {
              return Math.sqrt(d.value);
          });
  
          var node = svg.selectAll(".node")
              .data(json.nodes)
              .enter().append("circle")
              .attr("class", "node")
              .attr("r", function(d) {
                  if(d.number &gt;= 20){
                      return 50;
                  }
                  if(d.number &gt; 1){
                      return ((d.number*1.3)+10);
                  }else{
                      return d.number+4
                  }
  
              })
              .style("fill", function (d) {
              return color(d.group);
          })
          .call(force.drag)
          .on('mouseover', tip.show)
          .on('mouseout', tip.hide);
  
          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;
              });
          });
  
          function restart() {
  
            force = d3.layout.force()
              .charge(-120)
              .linkDistance(30)
              .size([width, height]);
  
            tip = d3.tip()
              .attr('class', 'd3-tip')
              .offset([-10, 0])
              .html(function (d) {
              return  d.name + "&lt;/span&gt;";
            })
            svg.call(tip);
  
            link = svg.selectAll(".link")
              .data(json.links)
              .enter().append("line")
              .attr("class", "link")
              .style("stroke-width", function (d) {
              return Math.sqrt(d.value);
            });;
  
            // Apply the general update pattern to the nodes.
            node = svg.selectAll(".node")
              .data(json.nodes)
              .enter().append("circle")
              .attr("class", "node")
              .attr("r", function(d) {
                  if(d.number &gt;= 20){
                      return 50;
                  }
                  if(d.number &gt; 1){
                      return ((d.number*1.3)+10);
                  }else{
                      return d.number+4
                  }
  
              })
              .style("fill", function (d) {
              return color(d.group);
            })
            .call(force.drag)
            .on('mouseover', tip.show)
            .on('mouseout', tip.hide);
  
            force.nodes(json.nodes)
              .links(json.links)
              .start();
  
            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;
              })
              node.attr("cy", function (d) {
                  return d.y;
              });
            });
  
  
          }
      &lt;/script&gt;
  
  &lt;/html&gt;
  </code></pre>