Skip to content

Instantly share code, notes, and snippets.

@ginseng666
Last active August 29, 2015 14:18
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 ginseng666/08e5776ace8e52ac9c45 to your computer and use it in GitHub Desktop.
Save ginseng666/08e5776ace8e52ac9c45 to your computer and use it in GitHub Desktop.
Slope Chart: Election Results, Lower Austria, 1995 vs. 2015
number name eligible_voters_1995 eligible_voters_2015 invalid_votes_1995 invalid_votes_2015 valid_votes_1995 valid_votes_2015 seats_to_fill_1995 seats_to_fill_2015 oevp_votes_1995 oevp_votes_2015 oevp_seats_1995 oevp_seats_2015 spoe_votes_1995 spoe_votes_2015 spoe_seats_1995 spoe_seats_2015
30401 Wiener Neustadt 31099 36431 536 290 20834 20619 40 40 4419 6998 9 14 10355 8310 22 17
30501 Allhartsberg 1325 1805 40 42 1132 1419 19 21 775 1154 14 17 198 265 3 4
30502 Amstetten 18538 20428 436 330 13360 11432 41 41 2938 2812 9 10 5944 5310 19 20
30503 Ardagger 2379 2985 54 65 1957 2294 23 23 1332 1659 16 17 242 279 3 3
30504 Aschbach-Markt 2585 3206 54 31 2048 2320 23 23 1426 1142 16 12 350 276 4 2
30506 Behamberg 2219 2918 65 36 1821 2029 21 23 1194 1189 14 14 457 564 5 6
30507 Biberbach 1519 1979 16 38 1261 1490 19 21 911 1047 14 15 259 199 4 3
30508 Ennsdorf 1755 2551 22 22 1368 1628 21 21 187 438 3 6 890 1002 14 13
30509 Ernsthofen 1636 1985 32 18 1366 1470 21 21 753 795 12 12 613 613 9 9
30510 Ertl 822 1115 13 19 666 828 19 19 624 737 18 17 42 91 1 2
30511 Euratsfeld 1616 2197 47 48 1391 1820 21 21 1126 1341 18 16 155 257 2 3
30512 Ferschnitz 1096 1541 13 26 979 1276 19 19 810 958 17 15 122 218 2 3
30514 Haag 4102 4901 90 44 3073 3168 29 29 1374 1631 14 16 657 665 6 6
30515 Haidershofen 2546 3139 42 47 1962 2213 23 23 1170 1553 14 17 577 389 7 4
30516 Hollenstein an der Ybbs 1589 1819 28 54 1375 1443 19 19 562 686 8 9 751 757 11 10
30517 Kematen an der Ybbs 2001 2278 79 49 1625 1620 21 21 823 1013 11 13 802 607 10 8
30520 Neuhofen an der Ybbs 1797 2521 34 68 1541 1692 21 21 1126 1120 16 14 164 265 2 3
30521 Neustadtl an der Donau 1880 2027 36 30 1512 1603 21 21 1122 1205 16 16 390 241 5 3
30522 Oed-oehling 1107 1612 30 31 852 1151 19 19 595 896 14 15 201 139 4 2
30524 Opponitz 805 812 20 17 673 657 19 15 225 414 6 10 226 147 7 3
30526 St. Georgen am Reith 500 622 13 11 420 579 15 15 165 284 6 7 255 295 9 8
30527 St. Georgen am Ybbsfelde 1743 2439 44 47 1461 1715 21 21 892 1043 13 13 386 426 6 5
30529 St. Pantaleon-Erla 1801 2329 35 60 1535 1651 21 21 432 729 6 9 1018 742 14 10
30530 St. Peter in der Au 3561 4536 61 89 2890 3197 25 29 2110 2129 19 20 450 688 4 6
30531 St. Valentin 7219 8293 164 139 5415 4857 33 33 1496 1242 9 8 2634 2952 17 21
30532 Seitenstetten 2350 2875 30 58 1907 2095 21 23 1246 1301 15 15 237 501 2 5
30533 Sonntagberg 3566 3644 102 47 2835 2752 25 23 793 1607 7 14 1661 921 15 8
30534 Strengberg 1633 1776 32 48 1258 1257 21 21 838 846 15 15 313 277 5 4
30536 Viehdorf 905 1195 23 22 775 952 19 19 569 831 15 17 140 121 3 2
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Election Results, Lower Austria, 1995 vs. 2015</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
text
{
font-size:10pt;
}
line
{
stroke:black;
}
.heading
{
font-size:14pt;
fill:steelblue;
}
label
{
color:steelblue;
font-size:14pt;
padding:0.2em;
}
label.checked
{
background-color:#efefef;
}
</style>
</head>
<body>
<div id="switch"></div>
<div id="chart"></div>
<script type="text/javascript">
var width=800;
var height=700;
var data, datastore, res95, res15, pos, line;
var parties=["oevp","spoe"]; //parties for the radio buttons
var check=0;
var svg=d3.select("#chart").append("svg").attr("width",width).attr("height",height);
d3.csv("data.csv", function(data)
{
for (i=0;i<data.length;i++)
{
data[i].oevp_95=+(data[i].oevp_votes_1995/data[i].valid_votes_1995*100).toFixed(2); //calculating the percentages
data[i].oevp_15=+(data[i].oevp_votes_2015/data[i].valid_votes_2015*100).toFixed(2);
data[i].spoe_95=+(data[i].spoe_votes_1995/data[i].valid_votes_1995*100).toFixed(2);
data[i].spoe_15=+(data[i].spoe_votes_2015/data[i].valid_votes_2015*100).toFixed(2);
data[i].idname=data[i].name.replace(/[\.,\s+]/g, ''); //to avoid spaces and dots in the class of the element for proper selection
}
d3.select("#switch")
.selectAll("input")
.data(parties)
.enter()
.append("label")
.attr("id",function(d){return d;})
.classed("checked", function(d,i){return i===check ? true : false;})
.text(function(d){return d.toUpperCase();})
.append("input")
.attr("type","radio")
.attr("name","party")
.attr("value",function(d){return d;})
.attr("onChange",function(d){return "draw('"+d+"')";})
.property("checked", function(d, i) {return (i===check)}); //add the radio buttons, depending on the number of available parties
svg
.append("text")
.attr("x", 200)
.attr("y",20)
.attr("text-anchor", "end")
.attr("class","heading")
.text("1995");
svg
.append("text")
.attr("x", 500)
.attr("y",20)
.attr("text-anchor", "start")
.attr("class","heading")
.text("2015");
datastore=data; //somehow the data-variable is undefined in the draw-function below, not sure why
pos=(height-30)/datastore.length; //fixed multiplier for the y-positions (might be easier done with d3.axis)
datastore.sort(function(a,b){return d3.descending(a.oevp_95,b.oevp_95);}) //make the left side
res95=svg.selectAll(".res95").data(datastore).enter().append("text");
res95
.attr("x",200)
.attr("y",function(d,i){d.pos95=45+i*pos; return 50+i*pos;})
.attr("text-anchor","end")
.text(function(d){return d.name+": "+d.oevp_95;})
.attr("class",function(d){return d.idname;})
.on("mouseover",function(){d3.selectAll("text."+this.className.baseVal)
.style("font-weight","bold")
.style("fill","red");
d3.selectAll("line."+this.className.baseVal).style("stroke","red");})
.on("mouseout",function(){d3.selectAll("text."+this.className.baseVal)
.style("font-weight","normal")
.style("fill","black");
d3.selectAll("line."+this.className.baseVal).style("stroke","black");}); //different selection for text and line, because changing the stroke-value would also affect the text
datastore.sort(function(a,b){return d3.descending(a.oevp_15,b.oevp_15);}) //make the right side
res15=svg.selectAll(".res15").data(datastore).enter().append("text");
res15
.attr("x",500)
.attr("y",function(d,i){d.pos15=45+i*pos; return 50+i*pos;})
.attr("text-anchor","start")
.text(function(d){return d.name+": "+d.oevp_15;})
.attr("class",function(d){return d.idname;})
.on("mouseover",function(){d3.selectAll("text."+this.className.baseVal)
.style("font-weight","bold")
.style("fill","red");
d3.selectAll("line."+this.className.baseVal).style("stroke","red");})
.on("mouseout",function(){d3.selectAll("text."+this.className.baseVal)
.style("font-weight","normal")
.style("fill","black");
d3.selectAll("line."+this.className.baseVal).style("stroke","black");});
line=svg.selectAll("line").data(datastore).enter().append("line"); //draw a line between left and right
line
.attr("x1",210)
.attr("x2",490)
.attr("y1",function(d,i){return d.pos95;})
.attr("y2",function(d){return d.pos15;})
.attr("class",function(d){return d.idname;});
});
function draw(choice)
{
d3.selectAll("label").classed("checked",false);
d3.select("#"+choice).classed("checked",true);
party_95=choice+"_95"; //construct the name of the object property based on the radio button
party_15=choice+"_15"; //construct the name of the object property based on the radio button
datastore.sort(function(a,b){return d3.descending(a[party_95],b[party_95]);});
for (i=0; i<datastore.length;i++) //this part seems necessary to get an updated index for the list - not very elegant, but i have not found a better solution yet
{
datastore[i].pos95=i;
}
datastore.sort(function(a,b){return d3.descending(a[party_15],b[party_15]);}); //the same for the right side
for (i=0; i<datastore.length;i++)
{
datastore[i].pos15=i;
}
res95
.transition()
.duration(500)
.attr("y",function(d){return (50+d.pos95*pos);})
.text(function(d){return d.name+": "+d[party_95];});
res15
.transition()
.duration(500)
.attr("y",function(d){return (50+d.pos15*pos);})
.text(function(d){return d.name+": "+d[party_15];});
line
.transition()
.duration(500)
.attr("y1",function(d){return 45+d.pos95*pos;})
.attr("y2",function(d){return 45+d.pos15*pos;});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment