score:5

Accepted answer

You have three problems in your code:

  1. There is no SVG element called <node>. Thus, instead of...

    .append("node");
    

    ... it should be:

    .append("g");
    
  2. Text elements have no cx or cy attribute.

  3. Instead of changing the cx or cy of node, which has none (since it is a <g> element), you have to translate it:

    node.attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")"
    });
    

All together, this is your updated code:

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: black;
  stroke-width: 0px;
}
<svg width="800" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  // Create somewhere to put the force directed graph
  var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

  var radius = 20;

  // DATA
  var nodes_data = [{
    "id": "Lillian",
    "sex": "F"
  }, {
    "id": "Gordon",
    "sex": "M"
  }, {
    "id": "Sylvester",
    "sex": "M"
  }, {
    "id": "Mary",
    "sex": "F"
  }, {
    "id": "Helen",
    "sex": "F"
  }, {
    "id": "Jamie",
    "sex": "M"
  }, {
    "id": "Jessie",
    "sex": "F"
  }, {
    "id": "Ashton",
    "sex": "M"
  }, {
    "id": "Duncan",
    "sex": "M"
  }, {
    "id": "Evette",
    "sex": "F"
  }, {
    "id": "Mauer",
    "sex": "M"
  }, {
    "id": "Fray",
    "sex": "F"
  }, {
    "id": "Duke",
    "sex": "M"
  }, {
    "id": "Baron",
    "sex": "M"
  }, {
    "id": "Infante",
    "sex": "M"
  }, {
    "id": "Percy",
    "sex": "M"
  }, {
    "id": "Cynthia",
    "sex": "F"
  }, {
    "id": "Feyton",
    "sex": "M"
  }, {
    "id": "Lesley",
    "sex": "F"
  }, {
    "id": "Yvette",
    "sex": "F"
  }, {
    "id": "Maria",
    "sex": "F"
  }, {
    "id": "Lexy",
    "sex": "F"
  }, {
    "id": "Peter",
    "sex": "M"
  }, {
    "id": "Ashley",
    "sex": "F"
  }, {
    "id": "Finkler",
    "sex": "M"
  }, {
    "id": "Damo",
    "sex": "M"
  }, {
    "id": "Imogen",
    "sex": "F"
  }];
  var links_data = [{
    "source": "Sylvester",
    "target": "Gordon",
    "type": "A"
  }, {
    "source": "Sylvester",
    "target": "Lillian",
    "type": "A"
  }, {
    "source": "Sylvester",
    "target": "Mary",
    "type": "A"
  }, {
    "source": "Sylvester",
    "target": "Jamie",
    "type": "A"
  }, {
    "source": "Sylvester",
    "target": "Jessie",
    "type": "A"
  }, {
    "source": "Sylvester",
    "target": "Helen",
    "type": "A"
  }, {
    "source": "Helen",
    "target": "Gordon",
    "type": "A"
  }, {
    "source": "Mary",
    "target": "Lillian",
    "type": "A"
  }, {
    "source": "Ashton",
    "target": "Mary",
    "type": "A"
  }, {
    "source": "Duncan",
    "target": "Jamie",
    "type": "A"
  }, {
    "source": "Gordon",
    "target": "Jessie",
    "type": "A"
  }, {
    "source": "Sylvester",
    "target": "Fray",
    "type": "E"
  }, {
    "source": "Fray",
    "target": "Mauer",
    "type": "A"
  }, {
    "source": "Fray",
    "target": "Cynthia",
    "type": "A"
  }, {
    "source": "Fray",
    "target": "Percy",
    "type": "A"
  }, {
    "source": "Percy",
    "target": "Cynthia",
    "type": "A"
  }, {
    "source": "Infante",
    "target": "Duke",
    "type": "A"
  }, {
    "source": "Duke",
    "target": "Gordon",
    "type": "A"
  }, {
    "source": "Duke",
    "target": "Sylvester",
    "type": "A"
  }, {
    "source": "Baron",
    "target": "Duke",
    "type": "A"
  }, {
    "source": "Baron",
    "target": "Sylvester",
    "type": "E"
  }, {
    "source": "Evette",
    "target": "Sylvester",
    "type": "E"
  }, {
    "source": "Cynthia",
    "target": "Sylvester",
    "type": "E"
  }, {
    "source": "Cynthia",
    "target": "Jamie",
    "type": "E"
  }, {
    "source": "Mauer",
    "target": "Jessie",
    "type": "E"
  }, {
    "source": "Duke",
    "target": "Lexy",
    "type": "A"
  }, {
    "source": "Feyton",
    "target": "Lexy",
    "type": "A"
  }, {
    "source": "Maria",
    "target": "Feyton",
    "type": "A"
  }, {
    "source": "Baron",
    "target": "Yvette",
    "type": "E"
  }, {
    "source": "Evette",
    "target": "Maria",
    "type": "E"
  }, {
    "source": "Cynthia",
    "target": "Yvette",
    "type": "E"
  }, {
    "source": "Maria",
    "target": "Jamie",
    "type": "E"
  }, {
    "source": "Maria",
    "target": "Lesley",
    "type": "E"
  }, {
    "source": "Ashley",
    "target": "Damo",
    "type": "A"
  }, {
    "source": "Damo",
    "target": "Lexy",
    "type": "A"
  }, {
    "source": "Maria",
    "target": "Feyton",
    "type": "A"
  }, {
    "source": "Finkler",
    "target": "Ashley",
    "type": "E"
  }, {
    "source": "Sylvester",
    "target": "Maria",
    "type": "E"
  }, {
    "source": "Peter",
    "target": "Finkler",
    "type": "E"
  }, {
    "source": "Ashley",
    "target": "Gordon",
    "type": "E"
  }, {
    "source": "Maria",
    "target": "Imogen",
    "type": "E"
  }];

  // Set up the simulation and add forces
  var simulation = d3.forceSimulation()
    .nodes(nodes_data);

  var link_force = d3.forceLink(links_data)
    .id(function(d) {
      return d.id;
    });

  var charge_force = d3.forceManyBody()
    .strength(-200);

  var center_force = d3.forceCenter(width / 2, height / 2);

  simulation
    .force("charge_force", charge_force)
    .force("center_force", center_force)
    .force("links", link_force);


  // Add tick instructions:
  simulation.on("tick", tickActions);

  // Add encompassing group for the zoom
  var g = svg.append("g")
    .attr("class", "everything");

  // Draw lines for the links
  var link = g.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(links_data)
    .enter()
    .append("line")
    .attr("stroke-width", 2)
    .style("stroke", linkColour);

  // Draw circles and texts for the nodes
  var nodes = g.append("g")
    .attr("class", "nodes");

  var node = nodes.selectAll("node")
    .data(nodes_data)
    .enter()
    .append("g");

  var circle = node.append("circle")
    .attr("r", radius)
    .attr("fill", circleColour);

  var text = node.append("text")
    .text("asdasdasdas")
    .attr("y", -22)
    .attr("text-anchor", "middle");

  // Add drag capabilities
  var drag_handler = d3.drag()
    .on("start", drag_start)
    .on("drag", drag_drag)
    .on("end", drag_end);

  drag_handler(node);

  // Add zoom capabilities
  var zoom_handler = d3.zoom()
    .on("zoom", zoom_actions);

  zoom_handler(svg);

  /** Functions **/

  function circleColour(d) {
    if (d.sex == "M") {
      return "blue";
    } else {
      return "pink";
    }
  }

  // Function to choose the line colour and thickness
  function linkColour(d) {
    return "black";
  }

  // Drag functions
  function drag_start(d) {
    if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }

  // Make sure you can't drag the circle outside the box
  function drag_drag(d) {
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }

  function drag_end(d) {
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }

  // Zoom functions
  function zoom_actions() {
    g.attr("transform", d3.event.transform)
  }

  function tickActions() {
    // update node positions each tick of the simulation
    node.attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")"
    });

    // update link positions
    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;
      });
  }

</script>

score:1

Here is what I suppose you want : https://jsfiddle.net/n504g8vw/1/

How did I do it ? First of all I removed the node element and changed it for a g element with the class node.

var node = nodes.selectAll("g")
    .data(nodes_data)
    .enter()
    .append("g")
        .attr('class', 'node');

Okay now the circles are displaying but not moving with the graph. I modified the tick function to translate the g element containing the circle and text.

node.attr('transform', function (d) {
        return 'translate(' + d.x + ', ' + d.y + ')';
    });

The nodes are now moving with the graph but the center of circle is not matching the center of the nodes. You have to set the center of each circle to 0,0.

var circle = node.append("circle")
    .attr("r", radius)
    .attr("fill", circleColour)
    .attr("cx",0)
    .attr("cy", 0);

Finally you want the text to be centered on the node so you put some css on the text, you can do it with D3 like this (or directly on your css sheet)

var text = node.append("text")
    .text("asdasdasdas")
    .style("text-anchor", "middle");

Related Query

More Query from same tag