d3.js Core SVG concepts used in D3.js visualization Correctly appending an SVG element


Example

This is a relatively common mistake: You created an rect element, in a bar chart for instance, and you want to add a text label (let's say, the value of that bar). So, using the same variable that you used to append the rect and define its x and y position, you append your text element. Very logic, you may think. But this will not work.

How does this mistake occur?

Let's see a concrete example, a very basic code for creating a bar chart (fiddle here):

var data = [210, 36, 322, 59, 123, 350, 290];

var width = 400, height = 300;

var svg = d3.select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height);

var bars = svg.selectAll(".myBars")
    .data(data)
    .enter()
    .append("rect");

bars.attr("x", 10)
    .attr("y", function(d,i){ return 10 + i*40})
    .attr("width", function(d){ return d})
    .attr("height", 30);

Which gives us this result:

enter image description here

But you want to add some text elements, maybe a simple value to each bar. So, you do this:

bars.append("text")
   .attr("x", 10)
   .attr("y", function(d,i){ return 10 + i*40})
   .text(function(d){ return d});

And, voilĂ : nothing happens! If you doubt it, here is the fiddle.

"But I'm seeing the tag!"

If you inspect the SVG created by this last code, you're gonna see this:

enter image description here

And at this point a lot of people say: "But I'm seeing the text tag, it's appended!". Yes, it is, but this doesn't mean it will work. You can append anything! See this, for example:

svg.append("crazyTag");

It will give you this result:

<svg>
    <crazyTag></crazyTag>
</svg>

But you don't expect any result just because the tag is there, do you?

Append SVG elements the correct way

Learn what SVG elements can hold children, reading the specifications. In our last example, the code doesn't work because rect elements cannot contain text elements. So, how to display our texts?

Create another variable, and append the text to the SVG:

var texts = svg.selectAll(".myTexts")
    .data(data)
    .enter()
    .append("text");

texts.attr("x", function(d){ return d + 16})
    .attr("y", function(d,i){ return 30 + i*40})
    .text(function(d){ return d});

And this is the outcome:

enter image description here

And here is the fiddle.