Skip to content

Instantly share code, notes, and snippets.

@Malicia
Created May 13, 2016 08:42
Show Gist options
  • Save Malicia/d09b3ae6b3ce3435a0ca4ec73b137528 to your computer and use it in GitHub Desktop.
Save Malicia/d09b3ae6b3ce3435a0ca4ec73b137528 to your computer and use it in GitHub Desktop.
Stacked Bars
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3-legend/1.1.0/d3-legend.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3-tip/0.6.3/d3-tip.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
.axis text {
font-family: 'Open Sans', sans-serif;
font-size: 19pt;
}
.axis .label {
font-size: 20pt;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.color-legend text {
font-family: 'Open Sans', sans-serif;
font-size: 19pt;
}
.d3-tip {
font-family: 'Open Sans', sans-serif;
font-size: 19pt;
line-height: 1;
padding: 7px;
background: black;
color: lightgray;
border-radius: 20px;
}
</style>
</head>
<body>
<script>
var outerWidth = 960;
var outerHeight = 500;
var margin = { left: 130, top: 44, right: 30, bottom: 47 };
var barPadding = 0.2;
var xColumn = "country";
var yColumn = "population";
var colorColumn = "religion";
var layerColumn = colorColumn;
var hoveredColorValue;
var hoveredStrokeColor = "black";
var innerWidth = outerWidth - margin.left - margin.right;
var innerHeight = outerHeight - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// This is the layer where the bars are drawn.
var baseBarLayer = g.append("g");
// This layer contains a semi-transparent overlay
// that fades out the base bars.
var overlayRect = g.append("g")
.append("rect")
.attr("width", innerWidth)
.attr("height", innerHeight)
.style("pointer-events", "none");
// This contains the subset of bars rendered on top
// when you hover over the entries in the color legend.
var foregroundBarLayer = g.append("g");
var xAxisG = g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + innerHeight + ")");
var yAxisG = g.append("g")
.attr("class", "y axis");
var colorLegendG = g.append("g")
.attr("class", "color-legend")
.attr("transform", "translate(596, 0)");
var xScale = d3.scale.ordinal().rangeBands([0, innerWidth], barPadding);
var yScale = d3.scale.linear().range([innerHeight, 0]);
var colorScale = d3.scale.category10();
var tipNumberFormat = d3.format(",");
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return [
d[colorColumn],
" in ",
d[xColumn],
": ",
tipNumberFormat(d[yColumn])
].join("");
});
g.call(tip);
// Use a modified SI formatter that uses "B" for Billion.
var siFormat = d3.format("s");
var customTickFormat = function (d){
return siFormat(d).replace("G", "B");
};
var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
.outerTickSize(0);
var yAxis = d3.svg.axis().scale(yScale).orient("left")
.ticks(5)
.tickFormat(customTickFormat)
.outerTickSize(0);
var colorLegend = d3.legend.color()
.scale(colorScale)
.shapePadding(6.24)
.shapeWidth(25)
.shapeHeight(25)
.labelOffset(5);
function render(data){
var nested = d3.nest()
.key(function (d){ return d[layerColumn]; })
.entries(data);
var stack = d3.layout.stack()
.y(function (d){ return d[yColumn]; })
.values(function (d){ return d.values; });
var layers = stack(nested.reverse()).reverse();
xScale.domain(layers[0].values.map(function (d){
return d[xColumn];
}));
yScale.domain([
0,
d3.max(layers, function (layer){
return d3.max(layer.values, function (d){
return d.y0 + d.y;
});
})
]);
colorScale.domain(layers.map(function (layer){
return layer.key;
}));
xAxisG.call(xAxis);
yAxisG.call(yAxis);
renderBars(baseBarLayer, layers);
if(hoveredColorValue){
setOverlayTransparency(0.7);
renderBars(foregroundBarLayer, layers.filter(function (layer){
return layer.key === hoveredColorValue;
}));
} else {
setOverlayTransparency(0.0);
renderBars(foregroundBarLayer, []);
}
colorLegendG.call(colorLegend);
// Move the text down a bit.
colorLegendG.selectAll("text").attr("y", 4);
listenForHover(colorLegendG.selectAll("rect"), data);
listenForHover(colorLegendG.selectAll("text"), data);
}
function setOverlayTransparency(alpha){
overlayRect
.transition().duration(400)
.attr("fill", "rgba(255, 255, 255, " + alpha + ")");
}
function renderBars(g, layers){
var layerGs = g.selectAll(".layer").data(layers);
layerGs.enter().append("g").attr("class", "layer");
layerGs.exit().remove();
layerGs.style("fill", function (d){
return colorScale(d.key);
});
var bars = layerGs.selectAll("rect").data(function (d){
return d.values;
});
bars.enter().append("rect")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
bars.exit().remove();
bars
.attr("x", function (d){ return xScale(d[xColumn]); })
.attr("y", function (d){ return yScale(d.y0 + d.y); })
.attr("width", xScale.rangeBand())
.attr("height", function (d){ return innerHeight - yScale(d.y); });
}
function listenForHover(selection, data){
selection
.on("mouseover", function (d){
hoveredColorValue = d;
render(data);
})
.on("mouseout", function (d){
hoveredColorValue = null;
render(data);
})
.style("cursor", "pointer");
}
function type(d){
d.population = +d.population;
return d;
}
d3.csv("religionByCountryTop5.csv", type, render);
</script>
</body>
</html>
country religion population
China Christian 68410000
China Muslim 24690000
China Unaffiliated 700680000
China Hindu 20000
China Buddhist 244130000
China Folk Religions 294320000
China Other Religions 9080000
China Jewish 0
India Christian 31130000
India Muslim 176190000
India Unaffiliated 870000
India Hindu 973750000
India Buddhist 9250000
India Folk Religions 5840000
India Other Religions 27560000
India Jewish 10000
USA Christian 243060000
USA Muslim 2770000
USA Unaffiliated 50980000
USA Hindu 1790000
USA Buddhist 3570000
USA Folk Religions 630000
USA Other Religions 1900000
USA Jewish 5690000
Indonesia Christian 23660000
Indonesia Muslim 209120000
Indonesia Unaffiliated 240000
Indonesia Hindu 4050000
Indonesia Buddhist 1720000
Indonesia Folk Religions 750000
Indonesia Other Religions 340000
Indonesia Jewish 0
Brazil Christian 173300000
Brazil Muslim 40000
Brazil Unaffiliated 15410000
Brazil Hindu 0
Brazil Buddhist 250000
Brazil Folk Religions 5540000
Brazil Other Religions 300000
Brazil Jewish 110000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment