Skip to content

Instantly share code, notes, and snippets.

@alansmithy
Last active November 5, 2015 18:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alansmithy/3838b9d7070cd18a7017 to your computer and use it in GitHub Desktop.
Save alansmithy/3838b9d7070cd18a7017 to your computer and use it in GitHub Desktop.
'Squeezed'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tax credit changes and the low income family</title>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
body, text{font-family:metric,sans-serif;}
h2{font-weight:500;font-size:21px;margin-bottom:-10px;}
body{background-color:#dedede}
.axis text{font-size:11px;}
.axis path{fill:none;stroke:none;}
.axis line{stroke:#555;stroke-width:1px;}
.y line{stroke-dasharray:2,2}
.area{fill-opacity:0.8;}
.source{font-size:11px;fill:#555;}
.subtitle{font-weight:500;font-size:18px;}
.value{font-weight:500;font-size:18px;}
.origin line{stroke:#828778;stroke-dasharray:0,0}
#container {
width: 600px;
margin-left: auto;
margin-right: auto;
margin-top: 30px;
background-color: white;
box-shadow: 2px 2px 4px 5px #ccc;
}
#intro{
padding-left:50px;
padding-top:10px;
padding-right:50px;
}
p{color:gray;}
</style>
</head>
<body>
<div id="container">
<div id="intro">
<h2>Squeezed: Tax credit changes and the low income family</h2>
<p>The House of Lords recently blocked Chancellor George Osborne's plans to make cuts of £4.6bn to income subsidies for people on low incomes, known as tax credits. The government argues that other changes, including an increase in the minimum wage and raising the tax allowance will offset the cuts for most households. But those changes are set to take effect over the coming years, while the tax credit cuts will be imposed from April next year. The graphic below shows House of Commons Library research on how the planned changes would affect a low income family*.</p>
</div>
</div>
<script type="text/javascript">
//Width, height, padding, colours
var width = 600;
var height = 250;
var padding = {left:50,right:80,top:30,bottom:50};
var w = width-(padding.left+padding.right);
var h = height-(padding.top+padding.bottom);
var colour = ["#5999B3","#D9AB44","#0079A1"];
var labelColour = ["#666","#111","#fff"];
var labelPlacement = [[[280,-30],[280,5],[280,70]],[[280,-18],[280,5],[280,70]]];
var source="Source: House of Commons Library; *Single-earner couple or lone parent, with 2 children, working 35 hrs a week";
//should load this from a csv and create this structure
var data=[];
var desc=["Without budget changes applied","With budget changes applied"];
//ignoring budget
data[0] = [
{
label: "child benefit",
value: [
{ x: "2016", y: 1794 },
{ x: "2017", y: 1794 },
{ x: "2018", y: 1815 },
{ x: "2019", y: 1846 },
{ x: "2020", y: 1880 },
{ x: "2021", y: 1914 }
]
},
{
label: "tax credit",
value: [
{ x: "2016", y: 8504 },
{ x: "2017", y: 8280 },
{ x: "2018", y: 8223 },
{ x: "2019", y: 8183 },
{ x: "2020", y: 8131 },
{ x: "2021", y: 8132 }
]
},
{
label: "net earnings",
value: [
{ x: "2016", y: 11401 },
{ x: "2017", y: 11774 },
{ x: "2018", y: 12116 },
{ x: "2019", y: 12539 },
{ x: "2020", y: 13026 },
{ x: "2021", y: 13693 }
]
}
]
//data with budget applied
data[1] = [
{
label: "child benefit",
value: [
{ x: "2016", y: 1794 },
{ x: "2017", y: 1794 },
{ x: "2018", y: 1794 },
{ x: "2019", y: 1794 },
{ x: "2020", y: 1794 },
{ x: "2021", y: 1828 }
]
},
{
label: "tax credit",
value: [
{ x: "2016", y: 8504 },
{ x: "2017", y: 6426 },
{ x: "2018", y: 5988 },
{ x: "2019", y: 5550 },
{ x: "2020", y: 5068 },
{ x: "2021", y: 4753 }
]
},
{
label: "net earnings",
value: [
{ x: "2016", y: 11402 },
{ x: "2017", y: 12102 },
{ x: "2018", y: 12769 },
{ x: "2019", y: 13441 },
{ x: "2020", y: 14179 },
{ x: "2021", y: 15120 }
]
}
];
//Set up stack method
var stackIndex=0;
var stack = d3.layout.stack()
.values(function(d) {
return d.value;
})
.order("reverse");
//'stack' the data [inject y0 components];
stack(data[0]);
stack(data[1]);
//extract and parse dates
var parseDate = d3.time.format("%Y").parse;
var dates = [];
data[0].forEach(function(obj,i){
obj.value.forEach(function(vals,i){
vals.x=parseDate(vals.x);
dates.push(vals.x);
})
})
data[1].forEach(function(obj,i){
obj.value.forEach(function(vals,i){
vals.x=parseDate(vals.x);
})
})
//determine max value - need to do this for both
var maxValue = 0;
data[0].forEach(function(obj,i){
obj.value.forEach(function(vals,i){
maxValue = d3.max([maxValue,(vals.y+vals.y0)]);
})
})
//create svg
var svg = d3.select("#container").append("svg")
.attr("width",width)
.attr("height",height)
//title etc
svg.append("text")
.attr("class","source")
.attr("x",padding.left)
.attr("y",height-10)
.text(source);
svg.append("text")
.attr("id","subtitle")
.attr("class","subtitle")
.attr("x",padding.left)
.attr("y",15)
.text(desc[stackIndex]);
//Set up scales
var xScale = d3.time.scale()
.domain(d3.extent(dates))
.range([0,w]);
var yScale = d3.scale.linear()
.domain([0,maxValue])
.range([h,0]);
//Axis generators
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickSize(-w)
.ticks(5);
//Create axes
svg.append("g")
.attr("class", "axis x")
.attr("transform","translate("+padding.left+","+(height-padding.bottom+5)+")")
.call(xAxis);
var yAxis = svg.append("g")
.attr("class", "axis y")
.attr("transform","translate("+padding.left+","+padding.top+")")
.call(yAxis);
//style 0 line
yAxis.selectAll(".tick").filter(function(d, i) {
return d==0;
}).classed('origin',function(d,i){
return (d == 0);
});
//Configure area generator
var area = d3.svg.area()
.x(function(d) {
return xScale(d.x);
})
.y0(function(d) {
return yScale(d.y0);
})
.y1(function(d) {
return yScale(d.y0 + d.y);
});
//Make a path for each element
var pathGrp = svg.append("g")
.attr("transform","translate("+padding.left+","+padding.top+")");
var paths = pathGrp.selectAll("path")
.data(data[stackIndex])
.enter()
.append("path")
.attr("class", "area")
.attr("d", function(d) {
return area(d.value);
})
.attr("stroke", "none")
.attr("fill", function(d, i) {
return colour[i];
});
//labels for stacks
var labelGrp = svg.append("g")
.attr("transform","translate("+padding.left+","+padding.right+")")
var labels = labelGrp.selectAll("text")
.data(data[stackIndex])
.enter()
.append("text")
.attr("text-anchor","middle")
.attr("fill",function(d,i){return labelColour[i]})
.attr("x",function(d,i){return labelPlacement[stackIndex][i][0]})
.attr("y",function(d,i){return labelPlacement[stackIndex][i][1]})
.text(function(d){return d.label;})
//annotate totals
var commaFormat = d3.format(',');
var total = [];
total[0] = data[0][0].value[5].y0+data[0][0].value[5].y;
total[1] = data[1][0].value[5].y0+data[1][0].value[5].y;
var label = svg.append("g").attr("id","anno")
.attr("transform","translate("+padding.left+","+padding.top+")")
.append("text")
.attr("class","value")
.attr("x",function(){return 10+xScale(dates[dates.length-1])})
.attr("y",function(){return 5+yScale(total[stackIndex])})
.text("£"+commaFormat(total[stackIndex]))
var marker = d3.select("#anno").append("circle")
.attr("cx",function(){return xScale(dates[dates.length-1])})
.attr("cy",function(){return yScale(total[stackIndex])})
.attr("r",5)
.attr("fill","red");
function changeStack(index){
//rebind data and transition
paths.datum(function(d,i){
return data[index][i];
})
.transition()
.duration(1000)
.attr("d", function(d) {
return area(d.value);
})
.each("end", function(){
d3.select("#subtitle").text(desc[stackIndex]);
});
label.transition()
.duration(1000)
.attr("y",function(){
return 5+yScale(total[stackIndex])
})
.each("end", function(){
label.text("£"+commaFormat(total[stackIndex]))
});
marker.transition()
.duration(1000)
.attr("cy",function(){
return yScale(total[stackIndex])
})
labels.transition()
.duration(1000)
.attr("y",function(d,i){return labelPlacement[stackIndex][i][1]})
}
setInterval(function(){
if (stackIndex==0){
stackIndex=1;
} else {
stackIndex=0;
};
changeStack(stackIndex)
}, 3000);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment