Skip to content

Instantly share code, notes, and snippets.

@tstpierre
Created March 21, 2014 00:13
Show Gist options
  • Save tstpierre/9676855 to your computer and use it in GitHub Desktop.
Save tstpierre/9676855 to your computer and use it in GitHub Desktop.
Stacked bars baseline at one series
{"description":"Stacked bars baseline at one series","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/WBk4s7E.png","ajax-caching":true}
/*modified from Mike Bostock at http://bl.ocks.org/3943967 */
var data = [
{
"SalaryGrade": "54",
"NumEmployeesInTopThirdPercentile": 18,
"NumEmployeesInMiddleThirdPercentile": 21,
"NumEmployeesInBottomThirdPercentile": 20
},
{
"SalaryGrade": "50",
"NumEmployeesInTopThirdPercentile": 10,
"NumEmployeesInMiddleThirdPercentile": 14,
"NumEmployeesInBottomThirdPercentile": 14
},
{
"SalaryGrade": "55",
"NumEmployeesInTopThirdPercentile": 50,
"NumEmployeesInMiddleThirdPercentile": 17,
"NumEmployeesInBottomThirdPercentile": 10
},
{
"SalaryGrade": "56",
"NumEmployeesInTopThirdPercentile": 50,
"NumEmployeesInMiddleThirdPercentile": 12,
"NumEmployeesInBottomThirdPercentile": 55
},
{
"SalaryGrade": "51",
"NumEmployeesInTopThirdPercentile": 80,
"NumEmployeesInMiddleThirdPercentile": 10,
"NumEmployeesInBottomThirdPercentile": 20
},
{
"SalaryGrade": "52",
"NumEmployeesInTopThirdPercentile": 32,
"NumEmployeesInMiddleThirdPercentile": 25,
"NumEmployeesInBottomThirdPercentile": 26
},
{
"SalaryGrade": "34",
"NumEmployeesInTopThirdPercentile": 10,
"NumEmployeesInMiddleThirdPercentile": 10,
"NumEmployeesInBottomThirdPercentile": 20
},
{
"SalaryGrade": "77",
"NumEmployeesInTopThirdPercentile": 10,
"NumEmployeesInMiddleThirdPercentile": 30,
"NumEmployeesInBottomThirdPercentile": 50
}
];
var getTop = function (data) {
var series = [];
var i=0;
data.forEach(function (d) {
series.push({ id: i, grade: d.SalaryGrade, value: d.NumEmployeesInTopThirdPercentile });
i++;
});
return series;
};
var getMid = function (data) {
var series = [];
var i=0;
data.forEach(function (d) {
series.push({ id: i, grade: d.SalaryGrade, value: d.NumEmployeesInMiddleThirdPercentile });
i++;
});
return series;
};
var getBot = function (data) {
var series = [];
var i=0;
data.forEach(function (d) {
series.push({ id: i, grade: d.SalaryGrade, value: d.NumEmployeesInBottomThirdPercentile });
i++;
});
return series;
};
var getDomainHeight = function (data) {
var top = 0,
mid = 0,
bot = 0;
data.forEach(function (d) {
if(d.NumEmployeesInTopThirdPercentile > top) top = d.NumEmployeesInTopThirdPercentile;
if(d.NumEmployeesInMiddleThirdPercentile > mid) mid = d.NumEmployeesInMiddleThirdPercentile;
if(d.NumEmployeesInBottomThirdPercentile > bot) bot = d.NumEmployeesInBottomThirdPercentile;
});
return top + bot + mid;
}
var topSeries = getTop(data),
midSeries = getMid(data),
botSeries = getBot(data);
var labels = data.map(function(d) {return d.SalaryGrade;});
var margin = {top: 30, right: 10, bottom: 50, left: 50},
width = 677 - margin.left - margin.right,
height = 414 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(d3.range(data.length))
.rangeRoundBands([0, width], 0.45);
var domainHeight = getDomainHeight(data);
var y = d3.scale.linear()
.domain([0, domainHeight * 1.25])
.range([height, 80]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(1)
.tickPadding(6)
.tickValues(labels)
.orient("bottom");
var svg = d3.select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var topBars = svg.selectAll(".top-bar")
.data(topSeries)
.enter().append("rect")
.attr("class", "top-bar")
.style("fill", "#1BB189")
.attr("x", function (d) { return x(d.id); })
.attr("width", x.rangeBand())
.attr("y", function (d) { return y(d.value) - height * (3 / 4); })
.attr("height", 0)
.attr("data-target-height", function (d) { return height - y(d.value); })
.transition()
.attr("height", function (d) { return height - y(d.value); })
.duration(500);
var topLabels = svg.selectAll("text").
data(topSeries).
enter().
append("svg:text").
attr("x", function (d, index) { return x(index) + x.rangeBand(); }).
attr("y", function (d) { return height * (1 / 4); }).
attr("dx", -x.rangeBand() / 2).
attr("dy", function (d) {
var topH = d3.select(topBars[0][d.id]).attr("data-target-height");
return -1 * (topH / 2);
}).
attr("text-anchor", "middle").
text(function (d) {
if (d.value === 0) return "";
return d.value;
}).
attr("fill", "white");
var midBars = svg.selectAll(".mid-bar")
.data(midSeries)
.enter().append("rect")
.attr("class", "mid-bar")
.style("fill", "#FFFAA6")
.attr("x", function (d) { return x(d.id); })
.attr("width", x.rangeBand())
.attr("y", function (d) { return height * (1 / 4); })
.attr("height", 0)
.attr("data-target-height", function (d) { return height - y(d.value); })
.transition()
.attr("height", function (d) { return height - y(d.value); })
.duration(500);
var botBars = svg.selectAll(".bot-bar")
.data(botSeries)
.enter().append("rect")
.attr("class", "bot-bar")
.style("fill", "#E66051")
.attr("x", function (d) { return x(d.id); })
.attr("width", x.rangeBand())
.attr("y", function (d) {
var midY = d3.select(midBars[0][d.id]).attr("y");
var midH = d3.select(midBars[0][d.id]).attr("data-target-height");
return parseFloat(midY) + parseFloat(midH);
})
.attr("height", 0)
.transition()
.attr("height", function (d) { return height - y(d.value); })
.duration(500);
var topAccentBounds = svg.selectAll(".top-bounds")
.data(topSeries).enter()
.append("g");
topAccentBounds.append("svg:rect")
.attr("class", "top-bounds")
.attr("x", function(d) { return x(d.id) - 3; })
.attr("y", height * (1/4) -1)
.attr("width", x.rangeBand() + 6)
.attr("height", 3)
.attr("fill", "#2D2F3C")
.style("stroke", "#2D2F3C")
.style("stroke-width", 1);
topAccentBounds.append("svg:line")
.attr("class", "top-line")
.attr("x1", function(d) { return x(d.id) - 3; })
.attr("y1", height * (1/4) + 0.5)
.attr("x2", function(d) { return x(d.id) + x.rangeBand() + 3; })
.attr("y2", height * (1/4) + 0.5)
.style("stroke", "#D2D0D8")
.style("stroke-width", 2)
.style("stroke-dasharray", ("5, 3"));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("transform", "translate(" + width / 2 + ",0)")
.attr("x", 0)
.attr("y", 25)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Grades");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment