title: D3.js v5 - Swarm Tree - How to iteratively center swarms around tree nodes
body: <p>The task is to append a swarm of small circles around the nodes of a tree (where I have placed bigger circles). The depth of the tree is tiny -- just two, However, there is a slight degree of complexity when considering I'm appending several trees iteratively.</p>
  <p>To keep it simple, I didn't even try to append swarms to all trees. Instead, I set myself with a more modest goal of appending the swarm to just one node of one tree. Comments and snippet below:</p>
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var margins = {top:100, bottom:300, left:100, right:100};
  
  var height = 600;
  var width = 900;
  
  var totalWidth = width+margins.left+margins.right;
  var totalHeight = height+margins.top+margins.bottom;
  
  var svg = d3.select('body')
  .append('svg')
  .attr('width', totalWidth)
  .attr('height', totalHeight);
  
  var graphGroup = svg.append('g')
  .attr('transform', "translate("+margins.left+","+margins.top+")");
  
    var data = [
  {name:"China", tree: {
    "name": "Actors",
    "children": [
          {
            "name": "Jackie Chan",
            "movies":d3.range(50).map(function(v) {return v.toString()+'_movie'})
           },
           {
             "name": "Jet Li",
             "movies":d3.range(38).map(function(v) {return v.toString()+'_movie'})
            },
            {
              "name": "Chow Yun Fat",
              "movies":d3.range(46).map(function(v) {return v.toString()+'_movie'})
             }
        ]
  }},
  {name:"USA", tree: {
    "name": "Actors",
    "children": [
      {
        "name": "Tom Cruise",
        "movies":d3.range(7).map(function(v) {return v.toString()+'_movie'})
       },
       {
         "name": "Johnny Depp",
         "movies":d3.range(4).map(function(v) {return v.toString()+'_movie'})
        },
        {
          "name": "Harrison Ford",
          "movies":d3.range(20).map(function(v) {return v.toString()+'_movie'})
         },
         {
           "name": "Ryan Gosling",
           "movies":d3.range(4).map(function(v) {return v.toString()+'_movie'})
          }
        ]
  }},
  {name:"UK", tree: {
    "name": "Actors",
    "children": [
      {
        "name": "Daniel Day-Lewis",
        "movies":d3.range(36).map(function(v) {return v.toString()+'_movie'})
       },
       {
         "name": "Christoper Lee",
         "movies":d3.range(50).map(function(v) {return v.toString()+'_movie'})
        },
        ]
  }}
  
    ];
  
    //var formatComma = d3.format(",");
  
    var columns = 3;
    var spacing = 200;
    var vSpacing = 180;
  
    var regionG = graphGroup.selectAll('.region')
  .data(data)
  .enter()
  .append('g')
  .attr('class', 'region')
  .attr('id', (d, i) =&gt; 'region' + i)
  .attr('transform', (d, k) =&gt; {
    var horSpace = (k % columns) * spacing;
    var vertSpace = ~~((k / columns)) * vSpacing;
    return "translate(" + horSpace + "," + vertSpace + ")";
  });
  
  var miniTree = d3.tree()
  .size([150, 75]);
  
  regionG.append('rect')
  .attr('x',0)
  .attr('y',0)
  .attr('width',100)
  .attr('height',25)
  .style('fill',"#003366");
  
  regionG.append('text')
  .attr('x',50)
  .attr('y',-10)
  .attr('text-anchor','middle')
  .text(function(d) {return d.name});
  
  
  regionG.selectAll(null)
  .data( function(d) {
      return miniTree(d3.hierarchy(d.tree)).descendants().slice(1)
  
      })
    .enter().append("path")
  .attr("transform", "translate(-25,20)") // extra positioning.
  .attr("class", "link")
  .attr("d", function(d) {
     return "M" + d.x + "," + d.y
       + "C" + d.x + "," + (d.y + d.parent.y) / 2
       + " " + d.parent.x + "," +  (d.y + d.parent.y) / 2
       + " " + d.parent.x + "," + d.parent.y;
     });
  
  regionG.selectAll(null)
  .data( function(d) {return miniTree(d3.hierarchy(d.tree)).descendants() })
    .enter().append("g")
  .attr("class", function(d) {
    return "node" +
      (d.children ? " node--internal" : " node--leaf"); })
  .attr("transform", function(d) {
    return "translate(" + (d.x - 25) + "," + (d.y+20) + ")"; }) // with extra positioning.
    .append("circle")
    .attr('r',10)
    .attr('cx',0)
    .attr('cy',0)
    .style('fill',"#003366");
  
  
  
  //start simulation for one node
    var simulation = d3.forceSimulation(data[0].tree.children[0].movies)
    .force("x", d3.forceX(function(d) {
    return 0;
    }).strength(0.03))
    .force("y", d3.forceY(function(d) {
    return 95;
    }).strength(0.1))
    .force("collide", d3.forceCollide(04).iterations(1))
    .stop();
  
    simulation.tick(75);
  //append circles at (0,95) -- the center coorinates of the bottom left tree node
    var circles = graphGroup.selectAll(null)
    .data(data[0].tree.children[0].movies)
    .enter()
    .append("circle")
    .attr("r", 3)
    .attr("cx", function(d) { return d.x;})
    .attr("cy", function(d) { return d.y;})
    .style('fill', function(d) {return "#4f81b9"; });</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://d3js.org/d3.v5.min.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>
  <p>This has given a huge swath of errors that I'm having trouble debugging:</p>
  <blockquote>
  <p>Cannot create property 'vx' on string &quot;0_movie&quot; ... Cannot create property
  'vx' on string &quot;1_movie&quot; ...</p>
  </blockquote>
  <p>The desired result should be circles appended around the node.</p>
  <p>For context:</p>
  <ul>
  <li>The top shows the region: China</li>
  <li>The big circles on the tree nodes show the actors: Jackie Chan</li>
  <li>The smaller swarm circles are to show the number of movies he/she acted in</li>
  </ul>
  <p>The end result will have swarm circles around each node, but for the purposes of this question, we can just focus on the bottom-left node.</p>
  <h2>Question</h2>
  <p>How can I append swarm clusters at each node at the bottom-most depth of my tree?</p>