Labels for Sunburst Diagram

4,889 views
Skip to first unread message

Thomas Haymore

unread,
Sep 16, 2011, 6:15:30 PM9/16/11
to d3-js
First off, D3 is simply amazing. I'm getting started using it to
build some concept maps and other visualizations, and have been
playing around with the sunburst example. I've successfully adapted
the sunburst tutorial to my own data and it even transitions correctly
with the "Size" and "Count" buttons.

However, I need labels (interactive labels, if possible) for each of
the sectors in the sunburst diagram. I tried the following code to
add an `svg:text` element to each path, but that didn't work:

.append("svg:text")
.attr("class", "nodetext")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function (d) { return d.name;});

[The full script is available here: http://pastebin.com/8nBanf4u

Is there something about D3 that is prohibiting labels for the
sunburst diagram? Or am I totally lost when it comes to SVG?

Mike Bostock

unread,
Sep 16, 2011, 6:16:25 PM9/16/11
to d3...@googlegroups.com
You might be interested in the "Sunburst Layout with Labels" example
on the wiki:

https://github.com/mbostock/d3/wiki

Mike

Thomas Haymore

unread,
Sep 16, 2011, 6:19:12 PM9/16/11
to d3-js
Oh man -- how did I miss that? Thanks for taking the time to make up
for my carelessness. Thought I had searched the whole site.

And thanks for making D3.

Thomas

Aaron Reabow

unread,
Jan 13, 2013, 4:18:21 AM1/13/13
to d3...@googlegroups.com
This sunburst visualisation is amazing.

i have quite a deep nesting on my json file, so this is working well to drill down into the data.

I am really struggling with these labels however.  


d3.json("flare.json", function(error, root) {
  var path = svg.selectAll("path")
      .data(partition.nodes(root))
    .enter().append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color((d.children ? d : d.parent).name); })
 .on("click", click);

      path.append("svg:text")
      .attr("transform", function(d) { return "rotate(" + (d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180 + ")"; })
      .attr("x", function(d) { return Math.sqrt(d.y); })
      .attr("dx", "6") // margin
      .attr("dy", ".35em") // vertical-align
      .text(function(d) { return d.data.key; });
  
 function click(d) {
    path.transition()
      .duration(750)
      .attrTween("d", arcTween(d));
  }
 
});

I get an error saying that: "Uncaught TypeError: Cannot read property 'key' of undefined "

which refers back to this anonymous function: .text(function(d) { return d.data.key; });

Any thoughts on why this method isn't recognised?

(And btw, D3.js really beats the professional packages we have been playing with at work!)

phoebebright

unread,
Jan 13, 2013, 6:25:41 AM1/13/13
to d3...@googlegroups.com
Should it just be d.key?

Some time ago I went through similar problem adding lables and this is the result: http://protembla.com/wheel.html
The code is not good quality but it might help.  Text is set in the label function.

Phoebe.

Aaron Reabow

unread,
Jan 14, 2013, 8:22:14 AM1/14/13
to d3...@googlegroups.com
it should be d.key, thank you!

I looked at the page you recommended.  It looks like they hacked it a little.  Great to have it as a backup when I get tired of trying to do it the 'right' way

Aaron Reabow

unread,
Jan 14, 2013, 9:00:22 AM1/14/13
to d3...@googlegroups.com
actually, once you remove the data in d.data.key everything is permitted:  d.key, d,name, d.size, d.joio9ohkh etc.  

so it looks like I am still a little stuck  (Phoebe, I see that you went through this frustration on groups a little while back, so thanks for the input)

Phoebe Bright

unread,
Jan 14, 2013, 12:06:38 PM1/14/13
to d3...@googlegroups.com
Aaron,

If you want to put your code in tributary or jsfiddle I'm happy to have a look.  No guarantees!

Phoebe.

Aaron Reabow

unread,
Jan 18, 2013, 1:23:27 AM1/18/13
to d3...@googlegroups.com
Many thanks for the offer.

I am honing in on the problem (I needed to go back over the first principles a little)

I have a flare.json file  (following the structure of Mike's)  of indeterminate depth.  So I need to be able to do d.children.children.name for instance.

The tutorials are helping, and I seem to be making some progress.

This is a very cool library, and the time isn't misspent.

Phoebe Bright

unread,
Jan 18, 2013, 4:49:18 AM1/18/13
to d3...@googlegroups.com
One of the things that I wish I had learned earlier in my D3 journey was understanding data.  I spent ages creating the format of data that the each example wanted and actually it is easy to access data in any format.  Understanding d3.nest was a really useful detour for me and I often serve cvs now and format as I want.  Hope that helps.
Enjoy your journey.

Phoebe.

Aaron Reabow

unread,
Jan 19, 2013, 8:30:33 AM1/19/13
to d3...@googlegroups.com
okay, got it

I just tried what I would have done for a python dictionary and voila!

.data(partition.nodes(root['children'][0]['children'][0]))

I totally agree that understanding the data structures are the most important.

I still have quite a lot of playing around before the penny drops.

When i get some time, a json tutorial seems in order.

Phoebe Bright

unread,
Jan 19, 2013, 6:19:18 PM1/19/13
to d3...@googlegroups.com
Hurragh!

I found Scott Murray's tutorial a great help, he talks about data here: http://alignedleft.com/tutorials/d3/data-types/

Remember JSON is just a javascript variable made up of lists [] or dictionaries {} and what confused me was that some examples have json like [ { }, { } ] and others were { "data" : [...] } or some such,  once I twigged JSON was just the same as say var = [ {}, {} ];  it all got much easier.  You may well have got that immediately, but it was one of the obvious things that took a while for me to find out.

Phoebe.

JonScrut

unread,
Mar 3, 2013, 7:08:52 PM3/3/13
to d3...@googlegroups.com
Hi,

Do you have an example of how you got this to work? I am trying to get labels on the zoomable sunburst chart and can't manage it.

Thanks!

Phoebe Bright

unread,
Mar 4, 2013, 5:14:53 AM3/4/13
to d3...@googlegroups.com
I'm embarrassed to share this code - I was a very newbie!  But it might help: http://protembla.com/wheel.html

Phoebe.

--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

JonScrut

unread,
Mar 4, 2013, 5:53:31 AM3/4/13
to d3...@googlegroups.com
Hi,

Thanks Phoebe, I did have a look at this already but it seemed quite complicated to just add the text labels. I'm just starting out with D3.

The original code of the Zoomable sunburst (http://bl.ocks.org/mbostock/4348373) basically just has this:


d3.json("/d/4063550/flare.json", function(error, root) {

  var path = svg.selectAll("path")
      .data(partition.nodes(root))
    .enter().append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color((d.children ? d : d.parent).name); })
      .on("click"
, click);

  
function click(d) {
    path.transition()
      .duration(750)
      .attrTween("d"
, arcTween(d));
  }
});

d3.select(self.frameElement).style("height", height + "px");

Do you know of a simple way to add the text labels to the arcs? Or is this as complicated as your fix looks?!
I see you have lots of conditional references to whether certain rings are being shown and that's making it hard for me
to know where to start.

I guess it's just some simplifying of your code? I tried changing the variables vis to svg. but no joy...


var path = vis.selectAll(".pie") .data(nodes) .enter().append("path") .attr("id", function(d, i) { return "path-" + i; }) .attr("class", function(d, i) { return "pie ring_" + d.depth +" " + attributes(d)}) .attr("d", arc) //.style("fill", colour) //.style("fill-opacity", opacity) .style("stroke-width", 2) .on("click", click); var text = vis.selectAll("text").data(nodes); var textEnter = text.enter().append("text") .attr("class", function(d, i) { var cls = "ring_" + d.depth; if (d.depth == ringCount) { cls += " timelabel"; } return cls;}) .style("opacity", 1) .attr("text-anchor", function(d) { // ?? HOW DO I CALCULATE THE CORRECT ANCHOR POINT ON OUTER RING??? return x(d.x + d.dx / 2) > Math.PI ? "end" : "start"; }) .attr("dy", ".2em") .attr("transform", function(d) { var multiline = (d.name || "").split(" ").length > 1, angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90, rotate = angle + (multiline ? -.5 : 0); return "rotate(" + rotate + ")translate(" + (y(d.y) + p) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
          })
          .on("click", click);
          
          
      textEnter.append("tspan")
          .attr("color", "#FFF")
          .attr("x", 0)

          .text(label);
          
           
      /* for splitting name across lines
      textEnter.append("tspan")
          .attr("x", 0)
          .attr("dy", "1em")
          .text(function(d) { return d.depth ? d.name.split(" ")[1] || "" : ""; });


Thanks for your help!

Jon

Phoebe Bright

unread,
Mar 4, 2013, 7:31:37 AM3/4/13
to d3...@googlegroups.com
 I based my code on the coffee wheel.
What initially confused me was that I was trying to put the text as a subelement of the wedge but you need to think of it as a new element entriely so you need to start afresh with the data and create some text element.

The final result looks like this:

<text style="fill-opacity: 1; fill: #eeeeee; " text-anchor="start" dy=".2em" transform="rotate(-0.5000000000000284)translate(105.691233065481)rotate(0)">
<tspan x="0">Sugar</tspan>
<tspan x="0" dy="1em">Browning</tspan>
</text>


  // create new text elements and transform them according to the x and y points in the data

  var text = vis.selectAll("text").data(nodes);
  var textEnter = text.enter().append("text")
      .style("fill-opacity", 1)
      .style("fill", function(d) {
        return brightness(d3.rgb(colour(d))) < 125 ? "#eee" : "#000";
      })
      .attr("text-anchor", function(d) {
        return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
      })
      .attr("dy", ".2em")
      .attr("transform", function(d) {
        var multiline = (d.name || "").split(" ").length > 1,
            angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
            rotate = angle + (multiline ? -.5 : 0);
        return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
      })
      .on("click", click);

 // put the first word on the first line within a tspan

  textEnter.append("tspan")
      .attr("x", 0)
      .text(function(d) { return d.depth ? d.name.split(" ")[0] : ""; });

// put the second work on the second line, if there is one.
  textEnter.append("tspan")
      .attr("x", 0)
      .attr("dy", "1em")
      .text(function(d) { return d.depth ? d.name.split(" ")[1] || "" : ""; });

Does that help?

Odanga Madung

unread,
May 9, 2015, 10:19:22 AM5/9/15
to d3...@googlegroups.com
Hello,

I've also been experimenting with sunburst using d3.js and I wish to add a label to the middle of the inner circle when a partition is moused over. The example I'm using is http://bl.ocks.org/mbostock/4063423 and the data is flare.json: Here's a sample of the code in contention
d3.json("flare.json", function(error, root) {
var path = svg.datum(root).selectAll("path")
.data(partition.nodes) //access the nodes
.enter()
.append("path")
.attr("display", function(d) { return d.depth ? null : 'none';}) //hide inner ring 
.attr("d", arc) 
.style("stroke", "#fff")
.style("fill", function(d) { return color((d.children ? d : d.parent).name);})
.style("fill-rule", "evenodd")
.each(stash)
.on("mouseover", mouseover);
function mouseover(d) {

 d3.select("#text")
.append("svg:text")
.transition()
.duration(1000)
.style("opacity", 1)
.style("fill", 'black')
   .text(function(d) { return d.parent.name; });
console.log('columnIndex', mouseover);
 };
Any assistance would be much appreciated

Laurent Cerveau

unread,
May 9, 2015, 10:27:24 AM5/9/15
to d3...@googlegroups.com
Hi Odanga

What is it where you are having problem? For example in your sample code I see that 
- you are not assigning any x and y to the text. 
- you are appending a text element to an element with id “text” (#text selector). Where is this one created ?

If you look at the DOM do you see your elements being created?

laurent

--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Laurent Cerveau 
Technical CEO
Nephorider
Want a clear picture of your AWS infrastructure? :



Odanga Madung

unread,
May 9, 2015, 10:45:18 AM5/9/15
to d3...@googlegroups.com
Hi Laurent,

Thanks for getting back to me. The code that I've written is not showing the desired effect of having the label appear in the middle of the graph.the #text css selector is defined at the beginning with this code
#text {
  font-size: 2.5em;
  text-align: center;
  color: #666;
  position: absolute;
  top: 260px;
  left: 305px;
  width: 140px;
  text-align: center;
  color: #666;
  z-index: -1;
}

From what I can see in my DOM there are no elements to do with the text being created. Is the method (css selection) a sound way of getting the desired effect? 

Odanga Madung

unread,
May 9, 2015, 11:05:13 AM5/9/15
to d3...@googlegroups.com
Hello so here's my #text css
#text {
  font-size: 2.5em;
  text-align: center;
  color: #666;
  position: absolute;
  top: 260px;
  left: 305px;
  width: 140px;
  text-align: center;
  color: #666;
  z-index: -1;
}

If I look at my DOM I don't see any text elements being created. My main problem is that the code I have is not making the text appear in the center of the inner circle upon mouseover. My ultimate goal with this is to be able to have it be highlightable just like Kerry rowden's example bl.ocks.org/kerryrodden/7090426

 

On Saturday, May 9, 2015 at 5:27:24 PM UTC+3, Laurent Cerveau wrote:

Laurent Cerveau

unread,
May 9, 2015, 12:15:09 PM5/9/15
to d3...@googlegroups.com
Let’s get problems one after the other :  in your mouseover handler set a breakpoint to 
1) see if is called
2) When it is called look at the “this" and if it corresponds properly to the area that you are above. You probably want to append your text do d3.select(this) and not with a #text selection
3) You should set x and y to the text element. From then you will be able to find out proper value
4) Now you may want to look at mouseout to remove this elements. Or the mouseenter/mouseleave (for a difference I personnally like the explanation at http://www.stator-afm.com/tutorial/d3-js-mouse-events/)

laurent

On May 9, 2015, at 5:05 PM, Odanga Madung <kvnma...@gmail.com> wrote:

If I look at my DOM I don't see any text elements being created. My main problem is that the code I have is not making the text appear in the center of the inner circle upon mouseover. My ultimate goal with this is to be able to have it be highlightable just like Kerry rowden's example bl.ocks.org/kerryrodden/7090426
 

Odanga Madung

unread,
May 10, 2015, 4:26:56 AM5/10/15
to d3...@googlegroups.com
Thanks for the breakdown Laurent. The explanation link was very helpful and much appreciated. The text however is still not displaying.
 
I have put my code in the fiddle in the link https://jsfiddle.net/odanga/kr2v7r08/

When I look at my console, I can see that the mouseover function is being called. I added an x and y element to the new text element but I stuck with selecting the css because I wasn't sure how I could mouseout using the d3.select(this) selection. 

Odanga

Odanga Madung

unread,
May 11, 2015, 7:27:46 AM5/11/15
to d3...@googlegroups.com
I've put the question on stack overflow or anyone who wishes to provide additional help

Laurent Cerveau

unread,
May 12, 2015, 9:01:17 AM5/12/15
to d3...@googlegroups.com
Hi Odanga

Sorry for the delay in answering. 

To be honest I have been pretty busy and did not have time to look at your fiddle. but the main question I would have would be around

d3.select("#text")
.append("svg:text")
.transition()
.duration(1000)
.style("opacity", 1)
.style("fill", 'black')
    .text(function(d) { return d.parent.name; });


If you set a break point at this line, could you look at what is on d3.select("#text”). If it is emtpy then you will have a problem. Also what happens if you do it without the transition?
Also IMHO haveing an id name text (for selector #text) is not a good idea. Is this will be a unique element you should bettter call it like “legend_text” or anithing more explicit

HTH

laurent

Odanga madung

unread,
May 13, 2015, 4:00:50 AM5/13/15
to d3...@googlegroups.com
Thanks Laurent. I've tried removing the transition but it's still not working. I've changed the selector and changed the text function but still nothing works.

--
You received this message because you are subscribed to a topic in the Google Groups "d3-js" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/d3-js/lhHxcNZCK0I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to d3-js+un...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--

Mr. Odanga Madung,
Co-Founder Odipo Dev   
Taranaki Court, Kilimani, Nairobi.
Check out our latest podcast!
buff.ly/1xeI73J 
 
        
 TEDx Organiser     "INNOVATION REDEFINED"

   




       

                




Reply all
Reply to author
Forward
0 new messages