How do you add labels to the circles representing the nodes in the force-directed-layout example?

18,470 views
Skip to first unread message

rjurney

unread,
Aug 18, 2011, 10:59:37 PM8/18/11
to d3-js
http://mbostock.github.com/d3/ex/force.html

I am new to D3. I've looked at many other examples, but I can't find
a straightforward answer: how do you create a label to display the
'name' of each node over the circle?

Thanks,
Russ

Devang Mundhra

unread,
Aug 18, 2011, 11:38:19 PM8/18/11
to d3...@googlegroups.com
Hi Russ,

In the force.html example, the 'name' of each node is being displayed as svg:title, so if you hover over the node, you should be able to see the name (d.name).
If you want to display it over each node, you can do something similar but instead of appending "svg:title", something like

node.append("svg:text")
  .text(function(d) {return d.name;})
  .attr("x", function(d) {return d.x;})
  .attr("y", function(d) {return d.y;});

should work.

Thanks,
Devang

Mike Bostock

unread,
Aug 18, 2011, 11:45:34 PM8/18/11
to d3...@googlegroups.com
> how do you create a label to display the 'name' of each node over the circle?

Typically by adding an svg:text element. Something like this in terms of SVG:

<svg:g class="node" transform="translate(d.x, d.y)">
<svg:circle r="5"/>
<svg:text x="10" dy=".31em" text="d.name"/>
</svg:g>

Or, in D3:

var g = svg.selectAll("g.node")
.data(nodes)
.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + ","
+ d.y + ")"; })
.call(force.drag);

g.append("svg:circle")
.attr("r", 5);

g.append("svg:text")
.attr("x", 10)
.attr("dy", ".31em")
.text(function(d) { return d.name; });

This does have a drawback, though, which is that later nodes' circles
will be drawn over earlier nodes' text labels. Also, there's a nice
technique where you draw the text twice, first with a thick white
stroke, such that the text has a white halo that improves legibility.
I used this in yesterday's example of mobile patent suits:

http://bl.ocks.org/1153292

This involves adding two different svg:g layers: one for the circles,
and one on top for the labels. In terms of SVG:

<svg:g>
<svg:circle class="node" cx="d.x" cy="d.y" r="5"/>
<svg:circle class="node" cx="d.x" cy="d.y" r="5"/>

</svg:g>
<svg:g>
<svg:text class="label" x="d.x + 10" y="d.y" dy=".35em" text="d.name"/>
<svg:text class="label" x="d.x + 10" y="d.y" dy=".35em" text="d.name"/>

</svg:g>

In terms of D3, first you add the svg:g for the circles:

var circle = svg.append("svg:g").selectAll("circle")
.data(nodes)
.enter().append("svg:circle")
.attr("r", 6)
.call(force.drag);

Then a second svg:g for the labels:

var text = svg.append("svg:g").selectAll("g")
.data(nodes)
.enter().append("svg:g");

text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.attr("class", "shadow")
.text(function(d) { return d.name; });

text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.name; });

It's a bit more work because you're mapping the nodes twice (once for
the circles, and once for the labels). Versus in the simpler example,
you map once to an svg:g element that contains both a circle and a
label. But the benefit of the second approach is more legible text,
which is a big plus.

Mike

Russell Jurney

unread,
Aug 18, 2011, 11:50:17 PM8/18/11
to d3...@googlegroups.com
Thanks - I've tried that, and I pasted your code.  It does not work.

I've tried adjusting the CSS - no effect.

Russell Jurney

unread,
Aug 18, 2011, 11:51:32 PM8/18/11
to d3...@googlegroups.com
I'll try this - thanks!

Guilherme Simões

unread,
Jun 22, 2012, 9:45:33 PM6/22/12
to d3...@googlegroups.com
Mike, I stumbled upon your post after a few google searches and your example helped me tremendously. Thanks and cheers!

Seth Setiadha

unread,
Sep 11, 2012, 3:12:47 AM9/11/12
to d3...@googlegroups.com, mbos...@cs.stanford.edu
i still can't figure out how to do this after hours :(
i literally copy-paste your code

Alexey Morozov

unread,
Oct 14, 2012, 5:47:59 PM10/14/12
to d3...@googlegroups.com, mbos...@cs.stanford.edu

Mike,

Thank you so much for your code! I reused it here. Can't thank you enough!

Alexey

Haleh

unread,
Oct 30, 2012, 4:12:07 PM10/30/12
to d3...@googlegroups.com, mbos...@cs.stanford.edu
I used it too. Thank you so much Mike. I suggest following the link http://bl.ocks.org/1153292

Shawn Mathew

unread,
Mar 19, 2013, 7:31:26 PM3/19/13
to d3...@googlegroups.com, mbos...@cs.stanford.edu
I've tried your code:

var g = svg.selectAll("g.node")
      .data(nodes)
    .enter().append("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + ","
+ d.y + ")"; })
      .call(force.drag);

  g.append("svg:circle")
      .attr("r", 5);

  g.append("svg:text")
      .attr("x", 10)
      .attr("dy", ".31em")
      .text(function(d) { return d.name; });

But my text still doesn't move with the nodes, they are static, anybody have any ideas?

On Thursday, August 18, 2011 11:45:34 PM UTC-4, Mike Bostock wrote:

Ravi Suhag

unread,
Jan 10, 2014, 9:34:39 AM1/10/14
to d3...@googlegroups.com
var nodes = scope.data.slice();
          force.nodes(nodes).start();

          var node = d3.select("svg").selectAll('.nodes')
            .data(scope.data)
            .enter()
            .append('g')
            .call(force.drag);

          var circle=node.append('circle')
            .attr("class", "node")
            .attr('r', r)
            .style("fill", function(d) {
              return color(d._id);
            });

          var text=node.append('text')
            .attr("class", "text")
            .text("sdsd");



          force.on("tick", function() {
            circle.attr("cx", function(d) {
              return d.x = Math.max(r, Math.min(width - r, d.x));
            })
              .attr("cy", function(d) {
                return d.y = Math.max(r, Math.min(height - r, d.y));
              });
            text.attr("x", function(d) {
              return d.x = Math.max(r, Math.min(width - r, d.x));
            })
            .attr("y", function(d) {
              return d.y = Math.max(r, Math.min(height- r, d.y));
            })

          });

Zhanzhan Cheng

unread,
Jun 28, 2015, 12:52:35 PM6/28/15
to d3...@googlegroups.com, mbos...@cs.stanford.edu
I encounter the same problem with you. Do you know how to fix that?  Thanks! 
Reply all
Reply to author
Forward
0 new messages