Last active
March 19, 2017 23:28
-
-
Save huembelin/c9a331d9eb828ff793f5cff284c9067c to your computer and use it in GitHub Desktop.
Tax Redistribution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name | value | state | ||
---|---|---|---|---|
1 | gini pre-tax | 0.413 | 0 | |
2 | federal income tax | -0.008 | 1 | |
3 | cantonal income tax | -0.006 | 1 | |
4 | cantonal wealth tax | -0.001 | 1 | |
5 | community income tax | -0.006 | 1 | |
6 | community wealth tax | -0.001 | 1 | |
7 | church tax | -0.001 | 1 | |
21 | social | 0.002 | 2 | |
31 | work related | 0.001 | 2 | |
41 | real etatet | 0.014 | 2 | |
51 | financial | 0.003 | 2 | |
61 | transfers | 0.001 | 2 | |
71 | others | 1e-05 | 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
.bar.total rect { | |
fill: steelblue; | |
} | |
.bar.positive rect { | |
fill: darkolivegreen; | |
} | |
.bar.negative rect { | |
fill: crimson; | |
} | |
.bar line.connector { | |
stroke: grey; | |
stroke-dasharray: 3; | |
} | |
.bar text { | |
fill: black; | |
font: 12px sans-serif; | |
text-anchor: middle; | |
} | |
.axis text { | |
font: 10px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
</style> | |
<h1> Income inequality impact of taxes and deducations </h1> | |
<input type="checkbox" class="myCheckbox" value="1"> Show impact of taxes | |
<input type="checkbox" class="myCheckbox" value="2"> Show impact of deducations | |
<svg class="chart"></svg> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
/// Define size of canvas | |
var margin = {top: 20, right: 30, bottom: 70, left: 40}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom, | |
padding = 0.3; | |
// Scales | |
var x = d3.scale.ordinal() | |
.rangeRoundBands([0, width], padding); | |
var y = d3.scale.linear() | |
.range([height, 0]); | |
// Axis | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom"); | |
var yAxis = d3.svg.axis() | |
.scale(y) | |
.orient("left") | |
// place chart in chart-container | |
var chart = d3.select(".chart") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
// clip-path -> to show bars properly with shorter y-Axis domain | |
chart.append("clipPath") | |
.attr("id","clip") | |
.append("rect") | |
.attr("width",width) | |
.attr("height",height); | |
// round number formater | |
var formatNumber=d3.format(".2n") | |
// here we load the data | |
d3.csv("gData.csv", type, function(error, data) { // data formating is included in form of a later specified "type"-function | |
var gData = data; | |
startData = data.filter(function(d) {return d.state=="0"}) | |
console.log(startData) | |
// Transform data (i.e., finding cumulative values and total) for easier charting | |
var cumulative = 0; | |
for (var i = 0; i < startData.length; i++) { | |
startData[i].start = cumulative; | |
cumulative += startData[i].value; | |
startData[i].end = cumulative; | |
startData[i].class = ( startData[i].value >= 0 ) ? 'positive' : 'negative' | |
} | |
startData.push({ | |
name: 'Gini post-tax', | |
end: cumulative, | |
start: 0, | |
class: 'total' | |
}); | |
// define domains | |
x.domain(startData.map(function(d) { return d.name; })); | |
y.domain([0.35, 0.45]); // shorter to show whats happening | |
// call x-Axis based dynamicaly on x-categories | |
chart.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis) | |
.selectAll(".tick text") | |
.call(wrap, x.rangeBand()); // this is an important part! wrap is defined below | |
// call y-Axis | |
chart.append("g") | |
.attr("class", "y axis") | |
.call(yAxis); | |
console.log(startData) | |
// draw bars | |
var bar = chart.selectAll(".bar") | |
.data(startData, function (d) {return d.name}) // append data with a key | |
.enter().append("g") | |
.attr("class", function(d) { return "bar " + d.class }) | |
.attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; }); | |
bar.append("rect") | |
.attr("y", function(d) { return y( Math.max(d.start, d.end) ); }) | |
.attr("height", function(d) { return Math.abs( y(d.start) - y(d.end) ); }) | |
.attr("width", x.rangeBand()) | |
.attr("clip-path", "url(#clip)") // clip the rectangle | |
/// append value labels | |
bar.append("text") | |
.attr("x", x.rangeBand() / 2) | |
.attr("y", function(d) { return y(d.end) + 5; }) | |
.attr("dy", function(d) { return ((d.class=='negative') ? '-' : '') + "1.5em" }) | |
.text(function(d) { return formatNumber(d.end - d.start);}); | |
// draw connector line | |
bar.filter(function(d) { return d.class != "total" }).append("line") | |
.attr("class", "connector") | |
.attr("x1", x.rangeBand() + 5 ) | |
.attr("y1", function(d) { return y(d.end) } ) | |
.attr("x2", x.rangeBand() / ( 1 - padding) - 5 ) | |
.attr("y2", function(d) { return y(d.end) } ) | |
/// Update condition to fire update function | |
d3.selectAll(".myCheckbox").on("change",update); | |
update(); | |
// define update function | |
function update () { | |
// This part does the filtering based on the checkboxes | |
var choices = ["0"]; | |
d3.selectAll(".myCheckbox").each(function(d){ | |
cb = d3.select(this); | |
if(cb.property("checked")){ | |
choices.push(cb.property("value")); | |
} | |
}); | |
console.log(choices) | |
if(choices.length > 1){ | |
newData = gData.filter(function(d) | |
{ | |
if (d.state == choices[0] || d.state == choices[1] || d.state == choices[2] ) | |
return d;}); | |
} else { | |
newData = startData; | |
} | |
///////////// | |
/// update part with new data | |
var cumulative = 0; | |
for (var i = 0; i < newData.length; i++) { | |
newData[i].start = cumulative; | |
cumulative += newData[i].value; | |
newData[i].end = cumulative; | |
newData[i].class = ( newData[i].value >= 0 ) ? 'positive' : 'negative' | |
} | |
newData.push({ | |
name: 'Gini post-tax', | |
end: cumulative, | |
start: 0, | |
class: 'total' | |
}); | |
// define domains | |
x.domain(newData.map(function(d) { return d.name; })); | |
y.domain([0.35, 0.45]); // shorter to show whats happening | |
// call y-Axis | |
chart.select(".y") | |
.call(yAxis); | |
// call x-Axis based dynamicaly on x-categories | |
chart.select(".x") | |
.call(xAxis) | |
.selectAll(".tick text") | |
.call(wrap, x.rangeBand()); // this is an important part! wrap is defined below | |
// Select all bars | |
var bar = chart.selectAll(".bar") | |
.data(newData, function (d) {return d.name}) | |
.enter().append("g") | |
.attr("class", function(d) { return "bar " + d.class }) | |
.attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; }); | |
// update bars | |
bar.attr("y", function(d) { return y( Math.max(d.start, d.end) ); }) | |
.attr("height", function(d) { return Math.abs( y(d.start) - y(d.end) ); }) | |
.attr("width", x.rangeBand()) | |
.attr("clip-path", "url(#clip)") // clip the rectangle | |
// draw new bars | |
console.log(newData) | |
var bar = chart.selectAll(".bar") | |
.data(newData, function (d) {return d.name}) // append data with a key | |
.enter().append("rect") | |
.attr("y", function(d) { return y( Math.max(d.start, d.end) ); }) | |
.attr("height", function(d) { return Math.abs( y(d.start) - y(d.end) ); }) | |
.attr("width", x.rangeBand()) | |
.attr("clip-path", "url(#clip)") // clip the rectangle | |
// remove bars that are not needed anymore | |
bar.remove(); | |
/// append value labels | |
bar.append("text") | |
.attr("x", x.rangeBand() / 2) | |
.attr("y", function(d) { return y(d.end) + 5; }) | |
.attr("dy", function(d) { return ((d.class=='negative') ? '-' : '') + "1.5em" }) | |
.text(function(d) { return formatNumber(d.end - d.start);}); | |
// draw connector line | |
bar.filter(function(d) { return d.class != "total" }).append("line") | |
.attr("class", "connector") | |
.attr("x1", x.rangeBand() + 5 ) | |
.attr("y1", function(d) { return y(d.end) } ) | |
.attr("x2", x.rangeBand() / ( 1 - padding) - 5 ) | |
.attr("y2", function(d) { return y(d.end) } ) | |
} | |
}); | |
// Part that does not need to be updated | |
// append y-Axis label | |
chart.append("text") | |
.attr("class","ylegend") | |
.attr("x",0) | |
.attr("y",15) | |
.style("text-anchor", "end") | |
.style("font-size",13) | |
.attr("transform", "rotate(-90)") | |
.text("Gini-Coefficient"); | |
/// helper funcions | |
function wrap(text, width) { | |
text.each(function() { | |
var text = d3.select(this), | |
words = text.text().split(/\s+/).reverse(), | |
word, | |
line = [], | |
lineNumber = 0, | |
lineHeight = 1.1, // ems | |
y = text.attr("y"), | |
dy = parseFloat(text.attr("dy")), | |
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em"); | |
while (word = words.pop()) { | |
line.push(word); | |
tspan.text(line.join(" ")); | |
if (tspan.node().getComputedTextLength() > width) { | |
line.pop(); | |
tspan.text(line.join(" ")); | |
line = [word]; | |
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); | |
} | |
} | |
}); | |
} | |
// parse the data | |
function type(d) { | |
d.value = +d.value; | |
return d; | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment