Skip to content

Instantly share code, notes, and snippets.

@bricedev
Last active August 10, 2017 13:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bricedev/f80fdbc2c03dbc1ae4e8 to your computer and use it in GitHub Desktop.
Save bricedev/f80fdbc2c03dbc1ae4e8 to your computer and use it in GitHub Desktop.
Diverging Stacked Bar Chart (even)

I have been using the diverging Stacked Bar Chart exemple by wpoely86 for a while. I tried to make it a bit more dynamic using less hardcoded constants. It works regardless the number of rows and the Likert scale length (odd or even).

Check this other example with an odd length of likert scale and more rows.

rows Not at all Strongly disagree Disagree Agree Strongly agree Absolutely
row 1 396 430 482 583 720 400
row 2 169 73 299 836 309 824
row 3 435 188 435 601 619 615
row 4 2 543 165 252 994 787
row 5 970 396 14 540 794 391
row 6 616 115 792 947 735 441
row 7 339 389 294 557 494 278
row 8 378 203 319 842 314 105
row 9 789 686 487 54 396 456
row 10 81 176 536 392 91 943
row 11 201 402 524 730 965 519
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 80, right: 20, bottom: 20, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], .3);
var x = d3.scale.linear()
.rangeRound([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.tickFormat(d3.format(",%"))
.orient("top");
var yAxis = d3.svg.axis()
.scale(y)
.tickSize(0)
.orient("left");
var color = d3.scale.ordinal()
.range(["#d73027","#f46d43","#fdae61","#a6d96a","#66bd63","#1a9850"]);
var svg = d3.select('body').append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("data.csv", function(error, data) {
var rateNames = d3.keys(data[0]).filter(function(key) { return key !== "rows"; });
var rowsNames = data.map(function(d) { return d.rows; });
var neutralIndex = Math.floor(rateNames.length/2);
color.domain(rateNames);
data.forEach(function(row) {
row.total = d3.sum(rateNames.map(function(name) { return +row[name]; }));
rateNames.forEach(function(name) { row['relative'+name] = (row.total !==0 ? +row[name]/row.total : 0); });
var x0 = -1 * d3.sum(rateNames.map(function(name,i) { return i < neutralIndex ? +row['relative'+name] : 0; }));
if (rateNames.length & 1) x0 += -1 * row['relative' + rateNames[neutralIndex] ]/2;
var idx = 0;
row.boxes = rateNames.map(function(name) {
return {name: name, x0: x0, x1: x0 += row['relative'+name], total: row.total, absolute: row[name]};
});
});
var min = d3.min(data, function(d) { return d.boxes["0"].x0; });
var max = d3.max(data, function(d) { return d.boxes[d.boxes.length-1].x1; });
x.domain([min, max]).nice();
y.domain(rowsNames);
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var rows = svg.selectAll(".row")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(0," + y(d.rows) + ")"; })
.on("mouseover", function(d) {
svg.selectAll('.y').selectAll('text').filter(function(text) { return text===d.rows; })
.transition().duration(100).style('font','15px sans-serif');
})
.on("mouseout", function(d) {
svg.selectAll('.y').selectAll('text').filter(function(text) { return text===d.rows; })
.transition().duration(100).style('font','10px sans-serif');
});
var bars = rows.selectAll("rect")
.data(function(d) { return d.boxes; })
.enter().append("g");
bars.append("rect")
.attr("height", y.rangeBand())
.attr("x", function(d) { return x(d.x0); })
.attr("width", function(d) { return x(d.x1) - x(d.x0); })
.style("fill", function(d) { return color(d.name); });
bars.append("text")
.attr("x", function(d) { return x(d.x0); })
.attr("y", y.rangeBand()/2)
.attr("dy", "0.5em")
.attr("dx", "0.5em")
.style("text-anchor", "begin")
.text(function(d) { return d.absolute !== 0 && (d.x1-d.x0)>0.04 ? d.absolute : "" });
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y2", height);
var legend = svg.selectAll(".legend")
.data(rateNames)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + width/rateNames.length * i + ",-55)"; });
legend.append("rect")
.attr("x", 0)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 22)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.text(function(d) { return d; });
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment