title: D3.js Bubble Chart from csv
body: <p>I have a D3 force layout with labels working very nicely thanks to a Stack Overflow user. My resulting jsfiddle is here <a href="https://jsfiddle.net/TimBrighton/wLuoqynb/" rel="nofollow noreferrer">https://jsfiddle.net/TimBrighton/wLuoqynb/</a></p>
  
  <p>Now I need to convert the input so it can accept a csv file instead of the "generated" nodes in this example. The CSV would just have "title","radius" values I guess. I've tried this for some hours using a modified version of this kind of function but it is just not working:</p>
  
  <pre><code>d3.csv("data.csv", function(error, data) {
    if (error) throw error;
  
    data.forEach(function(d) {
      d.date = format.parse(d.date);
      d.value = +d.value;        
    });
  </code></pre>
  
  <p>My current code is here:</p>
  
  <pre><code>var width = 960,
      height = 500,
      padding = 1.5, // separation between same-color nodes
      clusterPadding = 6, // separation between different-color nodes
      maxRadius = 40;
      minRadius = 20;
  
  var n = 50, // total number of nodes
      m = 5; // number of distinct clusters
  
  var color = d3.scale.category10()
      .domain(d3.range(m));
  
  // The largest node for each cluster.
  var clusters = new Array(m);
  
  var nodeNumber=1;
  
  var nodes = d3.range(n).map(function () {
  
      var i = Math.floor(Math.random() * m),
          r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius,
          d = {           
              cluster: i,
              radius: r,
              name: nodeNumber,
              x: Math.cos(i / m * 2 * Math.PI) * 200 + width / 2 + Math.random(),
              y: Math.sin(i / m * 2 * Math.PI) * 200 + height / 2 + Math.random()
          };
      if (!clusters[i] || (r &gt; clusters[i].radius)) clusters[i] = d;
      nodeNumber++;
      return d;
  
  });
  
  var force = d3.layout.force()
      .nodes(nodes)
      .size([width, height])
      .gravity(.02)
      .charge(0)
      .on("tick", tick)
      .start();
  
  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);
  
  var node = svg.selectAll("circle")
      .data(nodes)
      .enter().append("g").call(force.drag);
  //addcircle to the group
  node.append("circle")
      .style("fill", function (d) {
      return color(d.cluster);
  }).attr("r", function(d){return d.radius})
  //add text to the group    
  node.append("text")
      .text(function (d) {
      return d.name;
  })
  .attr("dx", -10)
      .attr("dy", ".35em")
      .text(function (d) {
      return d.name
  })
      .style("stroke", "none");
  
  
  
  
  
  
  function tick(e) {
      node.each(cluster(10 * e.alpha * e.alpha))
          .each(collide(.5))
      //.attr("transform", functon(d) {});
      .attr("transform", function (d) {
          var k = "translate(" + d.x + "," + d.y + ")";
          return k;
      })
  
  }
  
  // Move d to be adjacent to the cluster node.
  function cluster(alpha) {
      return function (d) {
          var cluster = clusters[d.cluster];
          if (cluster === d) return;
          var x = d.x - cluster.x,
              y = d.y - cluster.y,
              l = Math.sqrt(x * x + y * y),
              r = d.radius + cluster.radius;
          if (l != r) {
              l = (l - r) / l * alpha;
              d.x -= x *= l;
              d.y -= y *= l;
              cluster.x += x;
              cluster.y += y;
          }
      };
  }
  
  // Resolves collisions between d and all other circles.
  function collide(alpha) {
      var quadtree = d3.geom.quadtree(nodes);
      return function (d) {
          var r = d.radius + maxRadius + Math.max(padding, clusterPadding),
              nx1 = d.x - r,
              nx2 = d.x + r,
              ny1 = d.y - r,
              ny2 = d.y + r;
          quadtree.visit(function (quad, x1, y1, x2, y2) {
              if (quad.point &amp;&amp; (quad.point !== d)) {
                  var x = d.x - quad.point.x,
                      y = d.y - quad.point.y,
                      l = Math.sqrt(x * x + y * y),
                      r = d.radius + quad.point.radius + (d.cluster === quad.point.cluster ? padding : clusterPadding);
                  if (l &lt; r) {
                      l = (l - r) / l * alpha;
                      d.x -= x *= l;
                      d.y -= y *= l;
                      quad.point.x += x;
                      quad.point.y += y;
                  }
              }
              return x1 &gt; nx2 || x2 &lt; nx1 || y1 &gt; ny2 || y2 &lt; ny1;
          });
      };
  }
  </code></pre>