Skip to content

Instantly share code, notes, and snippets.

@bricedev
Last active March 24, 2016 15:50
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save bricedev/a7c02c493896a33d5f37 to your computer and use it in GitHub Desktop.
Diverging Stacked Bar Chart (odd)

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 even length of likert scale and more rows.

rows Strongly disagree Disagree Medium Agree Strongly agree
row 1 24 294 594 1927 376
row 2 2 2 0 7 0
row 3 2 0 2 4 2
row 4 0 2 1 7 6
row 5 0 1 3 16 4
row 6 1 1 2 9 3
row 7 0 0 1 4 0
row 8 0 0 0 0 2
<!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(["#ca0020","#f4a582","#d5d5d5","#92c5de","#0571b0"]);
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