Creating a bar chart

A bar chart is a visualization that uses either horizontal (row charts) or vertical (column charts) rectangular bars with length proportional to the values that they represent. In this recipe we will implement a column chart using D3. A column chart is capable of visually representing two variables at the same time with its y axis; in other words, the bar height, and its x axis. The x axis values can be either discrete or continuous (for example, a histogram). In our example we choose to visualize continuous values on the x axis and hence effectively implementing a histogram. However, the same techniques can be applied when working with discrete values.

Getting ready

Open your local copy of the following file in your web browser:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter8/bar-chart.html

How to do it...

The following code example shows the important implementation aspects of a histogram with accessors and peripheral graphic implementation details omitted.

...
var _width = 600, _height = 250,
  _margins = {top: 30, left: 30, right: 30, bottom: 30},
  _x, _y,
  _data = [],
  _colors = d3.scale.category10(),
  _svg,
  _bodyG;

  _chart.render = function () {
    if (!_svg) {
      _svg = d3.select("body").append("svg")
        .attr("height", _height)
        .attr("width", _width);

    renderAxes(_svg);

    defineBodyClip(_svg);
  }

  renderBody(_svg);
};
...
function renderBody(svg) {
  if (!_bodyG)
    _bodyG = svg.append("g")
      .attr("class", "body")
      .attr("transform", "translate(" 
        + xStart() 
        + "," 
        + yEnd() + ")")
      .attr("clip-path", "url(#body-clip)");

  renderBars();
  }

function renderBars() {
  var padding = 2; // <-A
  
  _bodyG.selectAll("rect.bar")
    .data(_data)
    .enter()
    .append("rect") // <-B
    .attr("class", "bar");

  _bodyG.selectAll("rect.bar")
    .data(_data)                    
    .transition()
    .attr("x", function (d) { 
      return _x(d.x); // <-C
    })
    .attr("y", function (d) { 
      return _y(d.y); // <-D 
    })
    .attr("height", function (d) { 
      return yStart() - _y(d.y); // <-E
    })
    .attr("width", function(d){
      return Math.floor(quadrantWidth() / _data.length) - padding;
  });
}
...

This recipe generates the following visualization:

How to do it...

Bar chart (histogram)

How it works...

One major difference here is that the bar chart implementation does not support multiple data series. Therefore instead of using a 2-dimensional array storing multiple data series as we did with other charts so far, in this implementation, the _data array simply stores a single set of data points directly. Main bar chart related visualization logic resides in the renderBars function.

function renderBars() {
  var padding = 2; // <-A
  ...
}

In the first step, we defined the padding between bars (line A), so later on we can automatically calculate the width of each bar. Afterwards we generate an svg:rect element (the bars) for each data point (line B).

_bodyG.selectAll("rect.bar")
  .data(_data)
  .enter()
  .append("rect") // <-B
  .attr("class", "bar");

Then in the update section we place each bar at the correct coordinates using its x and y attributes (line C and D) and extend each bar all the way down to touch the x axis with an adaptive height calculated on line E.

_bodyG.selectAll("rect.bar")
  .data(_data)
  .transition()
  .attr("x", function (d) { 
    return _x(d.x); // <-C
  })
  .attr("y", function (d) { 
    return _y(d.y); // <-D 
  })
  .attr("height", function (d) { 
    return yStart() - _y(d.y); // <-E
  })

Finally we calculate the optimal width for each bar using the number of bars as well as the padding value we have defined earlier.

.attr("width", function(d){
  return Math.floor(quadrantWidth() / _data.length) - padding;
});

Of course in a more flexible implementation, we can make the padding configurable instead of being fixed to 2 pixels.

See also

Before planning to implement your own reusable chart for your next visualization project, make sure you also check out the following open source reusable chart projects based on D3:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset