Adding the bar chart and baby name

In the previous section, we added the g elements and assigned those to the bars variable. In this section, we're going to calculate the width of the inpidual rectangles and add those and some text to the g:

var yScale = d3.scaleLinear() 
.domain([0, d3.max(both, function (d) { return d.amount; })])
.range([0, width]);

bars.append('rect')
.attr("height", barWidth)
.attr("width", function (d) { return yScale(d.amount); })
.attr("class", function (d) { return d.sex === 'F' ? 'female' : 'male'; });

bars.append("text")
.attr("x", function (d) { return yScale(d.amount) - 5 ; })
.attr("y", barWidth / 2)
.attr("dy", ".35em")
.text(function(d) { return d.name; });

Here we see something new: the d3.scaleLinear function. With a d3.scaleLinear, we can let D3 calculate how the number of times a name was given (the amount property) maps to a specific width. We want to use the full width (width property, which has a value of 720) of the chart for our bars, so that would mean that the highest value in our input data should map to that value:

  • The name Emma, which occurred 20355 times, should map to a value of 720
  • The name Olivia, which occurred 19553 times, should map to a value of 720 * (19553/20355)
  • The name Mia, which occurred 14820 times, should map to a value of 720 * (14820/20355)
  • And so on...

Now, we could calculate this ourselves and set the size of the rect accordingly, but using the d3.scaleLinear is much easier, and provides additional functionality. Let's look at the definition a bit closer:

var yScale = d3.scaleLinear() 
.domain([0, d3.max(both, function (d) { return d.amount; })])
.range([0, width]);

What we do here, is we define a linear scale, whose input domain is set from 0 to the maximum amount in our data. This input domain is mapped to an output range starting at 0 and ending at width. The result, yScale, is a function which we can now use to map the input domain to the output range: for example, yScale(1234) returns 43.64922623434046.

Once you've got a scale, you can use a couple of functions to change its behavior:

This is just a small part of the scales support provided by D3. In the rest of the book, we'll explore more of the scales options that are available.

With the scale defined, we can use that to create our rect and text elements in the same way we did in our previous example:

bars.append('rect') 
.attr("height", barWidth)
.attr("width", function (d) { return yScale(d.amount); })
.attr("class", function (d) { return d.sex === 'F' ? 'female' : 'male'; });

Here we create a rect with a fixed height, and a width which is defined by the yScale and the number of times the name was used. We also add a class to the rect so that we can set its colors (and other styling attributes) through CSS. In the case where sex is F, we set the class female and in the other case we set the class male.

To position the text element, we do pretty much the same:

bars.append("text") 
.attr("class", "label")
.attr("x", function (d) { return yScale(d.amount) - 5 ; })
.attr("y", barWidth / 2)
.attr("dy", ".35em")
.text(function(d) { return d.name; });

We create a new text element, position it at the end of the bar, set a custom CSS class, and finally set its value to d.name. The dy attribute might seem a bit strange, but this allows us to position the text nicely in the middle of the bar chart. If we opened the example at this point, we'd see something like this:

We can see that all the information is in there, but it still looks kind of ugly. In the following section, we add some CSS to improve what the chart looks like.