D3 is an interactive JavaScript library for data visualization. It uses Scalar Vector Graphics (SVG) coupled with HTML and CSS to display charts and figures that illustrate the numeric data. You can also use D3 to make stacked bar charts. Here is a step-by-step guide on how to make a stacked bar chart using D3.
Before even starting to code, we need a data set to base our chart on. For this example, we will take an array of objects where each object has five attributes: year
, alex
, mindy
, sean
, and karen
. We will then take an array of colors associated with each of our stacked bars. Next, we will combine them and create layers with year assigned to x
and the bars (values of alex, mindy, sean, and karen) assigned to y
:
var data = [
{ year: "2006", alex: "104", mindy: "152", sean: "90", karen: "162" },
{ year: "2007", alex: "122", mindy: "184", sean: "99", karen: "143" },
{ year: "2008", alex: "50", mindy: "201", sean: "127", karen: "114" },
{ year: "2009", alex: "150", mindy: "134", sean: "139", karen: "80" }
];
var colors = ["#C9D6DF", "#F7EECF", "#E3E1B2", "#F9CAC8"];
var dataset = d3.layout.stack()(["alex", "mindy", "sean", "karen"].map(function(fruit) {
return data.map(function(d) {
return {x: d3.time.format("%Y").parse(d.year), y: +d[fruit]};
});
}));
We make an svg
variable and define its constraints keeping in mind the height, width, and margin:
var margin = 50;
var width = 600;
height = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin + 40 )
.attr("height", height + margin + 20)
.append("g")
.attr("transform", "translate(" + (margin+30)/2 + "," + margin/2 + ")")
For discrete data visualization on the x-axis, we need to construct an ordinal scale. The ordinal scale makes discrete bands for our values on the x-axis and then induces padding to separate the bars in the bar chart.
For our y-axis, we use a linear scale to show the sales:
var xScale = d3.scale.ordinal()
.domain(dataset[0].map(function(d) { return d.x; }))
.rangeRoundBands([0, width], 0.5);
var yScale = d3.scale.linear()
.domain([0, 600])
.range([height, 0]);
After setting scales, we need to draw axes. For each axes, we supply the corresponding scale (xScale
or yScale
) and then specify the ticks. After that, we call our defined xAxis
and yAxis
and translate where necessary:
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(6)
.tickSize(-width, 0, 0)
.tickFormat( function(d) { return "$" + d } );
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(d3.time.format("%Y"));
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
We need to add the x-axis label and y-axis label to our plot. For this purpose, we first append text to our svg
, and then set the position, style, and actual text attribute. To rotate our text for the y-axis, we use transform and specify the angle of rotation:
// X label
svg.append('text')
.attr('x', width/2)
.attr('y', height + 30)
.attr('text-anchor', 'middle')
.style('font-family', 'Helvetica')
.style('font-size', 12)
.text('Year');
// Y label
svg.append('text')
.attr('text-anchor', 'middle')
.attr('transform', 'translate(-30,' + height/2 + ')rotate(-90)')
.style('font-family', 'Helvetica')
.style('font-size', 12)
.text('Sale');
Finally, we need to plot the stacked bars. To do that, we first make subgroups of each bar for the associated x value and assign them to their appropriate color. Then, we need to specify the x
position, y
position, height
, and width
of each stacked bar. The x
position and width
can be found out using the xScale
– it’s finding out the y
position and height
for each bar is the tricky part.
To find the y
position of the sub-bar of one year, we add the previous bar’s height to the current bar. To find out the height
of the sub-bar of one year, we first calculate the total height of the current bar and the previous bar, and then we subtract the previous bar’s height.
var groups = svg.selectAll("g.bars")
.data(dataset)
.enter().append("g")
.attr("class", "bars")
.style("fill", function(d, i) { return colors[i]; })
.style("stroke", "#000");
var rect = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d) { return xScale(d.x); })
.attr("y", function(d) { return yScale(d.y0 + d.y); })
.attr("height", function(d) { return yScale(d.y0) - yScale(d.y0 + d.y); })
.attr("width", xScale.rangeBand())
Free Resources