Skip to content

Instantly share code, notes, and snippets.

@borgar
Last active January 1, 2020 09:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save borgar/31b5be022e67ca4ff6b52fe5ee670f9e to your computer and use it in GitHub Desktop.
Save borgar/31b5be022e67ca4ff6b52fe5ee670f9e to your computer and use it in GitHub Desktop.
Constituency bias
license: mit
height: 507
border: no
scrolling: yes

We tend to talk about political party support as a percentage measure of the entire contry: “My party now has 18% support!” This is a useful, but it is also useful to remember that parties different level of support from constituency to constituency.

Some parties may have a relatively evenly spread support through the country. Some may have more following in urban or rural areas, because their policies harmonize better with the people of those constituencies.

The plot explores political party constiuency bias in Iceland among four “traditional” parties. Each circle represents the proportion of valid votes in a constituency over the last 5 elections. The black line is the average.

When there is a difference in how many votes are required in a constituency to get a seat in parliament, a party with strong support in a constituency where fewer votes are behind each MP may benefit.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
text {
font: 12px sans-serif;
fill: #555;
}
text.title {
font-size: 14px;
}
.avg {
stroke: #555;
stroke-width: .75;
}
.dot {
stroke: white;
stroke-width: .75;
}
.dot-2003 { fill: #EFCCFF; }
.dot-2007 { fill: #E6B2FF; }
.dot-2009 { fill: #DD99FF; }
.dot-2013 { fill: #D57FFF; }
.dot-2016 { fill: #CC66FF; }
.axis-y line {
stroke: #ddd;
}
.axis-y .zero {
stroke: #aaa;
stroke-dasharray: none;
}
.axis-y path,
.axis-x path {
display: none;
}
body:hover .err,
body:hover .have-err {
stroke: black;
}
</style>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js"></script>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var margin = {top: 40, right: 10, bottom: 20, left: 40},
width = 470 - margin.left - margin.right,
height = 220 - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.2),
y = d3.scaleLinear().rangeRound([height, 0]);
var voters = {};
d3.csv('registry.csv', (err, registry) => {
registry.forEach(d => {
var sum = 0;
registry.columns.slice(1).forEach(c => {
if (!voters[d.year]) { voters[d.year] = {}; }
voters[d.year][c] = +d[c];
sum += voters[d.year][c];
});
voters[d.year].sum = sum;
});
d3.csv('partybias.csv', (err, table) => {
table.forEach(d => {
d.year = +d.year;
d.votes = +d.votes;
d.votes_total = +d.votes_total;
d.votes_year = voters[d.year].sum;
d.votes_c = voters[d.year][d.constituency];
})
plot(data(table.filter(d => d.party === 'B')),
'Framsóknarflokkurinn');
plot(data(table.filter(d => d.party === 'D')),
'Sjálfstæðisflokkurinn');
plot(data(table.filter(d => d.party === 'V')),
'Vinstrihreyfingin - grænt framboð');
plot(data(table.filter(d => d.party === 'S')),
'Samfylkingin');
// draw a legend
var svg = d3.select("body").append("svg")
.attr("width", (width + margin.left + margin.right)*2)
.attr("height", 50);
var legend = svg.selectAll('g')
.data(registry.map(d => d.year))
.enter().append('g');
legend.append('text')
.text(String)
.call(sel => {
var offs = 0;
sel.each((s, i, t) => {
d3.select(t[i].parentNode)
.attr('transform', `translate(${margin.left + offs},30)`);
offs += t[i].getComputedTextLength() + 30;
});
});
legend.append('circle')
.attr("class", d => `dot dot-${d}`)
.attr("r", x.bandwidth() / 15)
.attr("cx", -x.bandwidth() / 7.5)
.attr("cy", -5);
});
});
function data (data, log) {
var getVal = d => (d.votes / d.votes_c);
var _data = d3.nest()
.key(d => d.constituency)
.key(d => d.year)
.entries(data);
_data.forEach(d => {
var val = [];
d.values.forEach(h => {
var _v = h.values.map(getVal);
h.total = d3.sum(_v);
h.mean = d3.mean(_v);
val = val.concat(_v);
})
d.total = d3.sum(val);
d.mean = d3.mean(val);
});
return _data;
}
function plot ( data, title ) {
var max_val = .4;
var min_val = 0;
y.domain([ min_val, max_val ]);
x.domain(data.map(d => d.key));
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
svg.append("g")
.attr("class", "axis axis-x")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x).tickSize(3));
svg.append("g")
.attr("class", "axis axis-y")
.call(d3.axisLeft(y).tickSize(-width).ticks(5, "%"))
.selectAll('line')
.attr('class', d => d ? '' : 'zero');
svg.append("text")
.attr("class", "title")
.attr("x", width/2)
.attr("y", -18)
.attr("dy", ".32em")
.attr("text-anchor", "middle")
.text(title);
var polls = svg.selectAll(".dots")
.data(data).enter()
.append("g")
.attr("class", "dots")
.attr("transform", d => `translate(${x(d.key)},0)`)
.selectAll(".dot")
.data(p => p.values)
.enter();
polls.append('circle')
.attr("class", d => `dot dot-${d.key}`)
.attr("r", x.bandwidth() / 15)
.attr("cx", (d, i, p) => {
var b = x.bandwidth();
return b / 2 + ( i + -( p.length - 1) / 2 ) * b / 5
})
.attr("cy", d => y(d.mean));
svg.selectAll(".avg")
.data(data).enter()
.append("line")
.attr("class", "avg")
.attr("x1", d => x(d.key))
.attr("y1", d => y(d.mean))
.attr("x2", d => x(d.key) + x.bandwidth())
.attr("y2", d => y(d.mean))
}
</script>
year party constituency votes votes_total
2003 B NV 4057 32484
2003 B NA 7722 32484
2003 B SU 5934 32484
2003 B SV 6387 32484
2003 B RS 4185 32484
2003 B RN 4199 32484
2003 D NV 5532 61701
2003 D NA 5544 61701
2003 D SU 7307 61701
2003 D SV 16456 61701
2003 D RS 14029 61701
2003 D RN 12833 61701
2003 F NV 2666 13523
2003 F NA 1329 13523
2003 F SU 2188 13523
2003 F SV 2890 13523
2003 F RS 2448 13523
2003 F RN 2002 13523
2003 N NV 122 1791
2003 N NA 136 1791
2003 N SU 166 1791
2003 N SV 399 1791
2003 N RS 504 1791
2003 N RN 464 1791
2003 S NV 4346 56700
2003 S NA 5503 56700
2003 S SU 7426 56700
2003 S SV 14029 56700
2003 S RS 12286 56700
2003 S RN 13110 56700
2003 T NV 0 844
2003 T NA 0 844
2003 T SU 844 844
2003 T SV 0 844
2003 T RS 0 844
2003 T RN 0 844
2003 V NV 1987 16129
2003 V NA 3329 16129
2003 V SU 1167 16129
2003 V SV 2671 16129
2003 V RS 3438 16129
2003 V RN 3537 16129
2007 B NV 3362 21349
2007 B NA 5726 21349
2007 B SU 4745 21349
2007 B SV 3250 21349
2007 B RS 2080 21349
2007 B RN 2186 21349
2007 D NV 5199 66749
2007 D NA 6522 66749
2007 D SU 9120 66749
2007 D SV 19307 66749
2007 D RS 13841 66749
2007 D RN 12760 66749
2007 F NV 2432 13233
2007 F NA 1378 13233
2007 F SU 1771 13233
2007 F SV 3051 13233
2007 F RS 2385 13233
2007 F RN 2216 13233
2007 I NV 255 5953
2007 I NA 278 5953
2007 I SU 435 5953
2007 I SV 1599 5953
2007 I RS 1680 5953
2007 I RN 1706 5953
2007 S NV 3793 48742
2007 S NA 4840 48742
2007 S SU 6783 48742
2007 S SV 12845 48742
2007 S RS 10233 48742
2007 S RN 10248 48742
2007 V NV 2855 26136
2007 V NA 4558 26136
2007 V SU 2498 26136
2007 V SV 5232 26136
2007 V RS 5065 26136
2007 V RN 5928 26136
2009 B NV 3967 27699
2009 B NA 5905 27699
2009 B SU 5390 27699
2009 B SV 5627 27699
2009 B RS 3435 27699
2009 B RN 3375 27699
2009 D NV 4037 44371
2009 D NA 4079 44371
2009 D SU 7073 44371
2009 D SV 13463 44371
2009 D RS 8211 44371
2009 D RN 7508 44371
2009 F NV 929 4148
2009 F NA 384 4148
2009 F SU 838 4148
2009 F SV 741 4148
2009 F RS 700 4148
2009 F RN 556 4148
2009 O NV 587 13519
2009 O NA 690 13519
2009 O SU 1381 13519
2009 O SV 4428 13519
2009 O RS 3076 13519
2009 O RN 3357 13519
2009 P NV 66 1107
2009 P NA 61 1107
2009 P SU 127 1107
2009 P SV 302 1107
2009 P RS 226 1107
2009 P RN 325 1107
2009 S NV 4001 55758
2009 S NA 5312 55758
2009 S SU 7541 55758
2009 S SV 15669 55758
2009 S RS 11667 55758
2009 S RN 11568 55758
2009 V NV 4018 40581
2009 V NA 6937 40581
2009 V SU 4615 40581
2009 V SV 8473 40581
2009 V RS 8106 40581
2009 V RN 8432 40581
2013 A NV 792 15584
2013 A NA 1537 15584
2013 A SU 1202 15584
2013 A SV 4687 15584
2013 A RS 3790 15584
2013 A RN 3576 15584
2013 B NV 6104 46173
2013 B NA 8173 46173
2013 B SU 9262 46173
2013 B SV 10944 46173
2013 B RS 5931 46173
2013 B RN 5759 46173
2013 D NV 4282 50455
2013 D NA 5327 50455
2013 D SU 7594 50455
2013 D SV 15608 50455
2013 D RS 9464 50455
2013 D RN 8180 50455
2013 G NV 208 3262
2013 G NA 296 3262
2013 G SU 702 3262
2013 G SV 925 3262
2013 G RS 575 3262
2013 G RN 556 3262
2013 H NV 0 126
2013 H NA 0 126
2013 H SU 0 126
2013 H SV 0 126
2013 H RS 55 126
2013 H RN 71 126
2013 I NV 161 5707
2013 I NA 241 5707
2013 I SU 786 5707
2013 I SV 1838 5707
2013 I RS 1394 5707
2013 I RN 1287 5707
2013 J NV 774 2021
2013 J NA 306 2021
2013 J SU 412 2021
2013 J SV 188 2021
2013 J RS 161 2021
2013 J RN 180 2021
2013 K NV 0 222
2013 K NA 0 222
2013 K SU 0 222
2013 K SV 0 222
2013 K RS 222 222
2013 K RN 0 222
2013 L NV 251 4658
2013 L NA 313 4658
2013 L SU 431 4658
2013 L SV 1241 4658
2013 L RS 1025 4658
2013 L RN 1397 4658
2013 M NV 326 326
2013 M NA 0 326
2013 M SU 0 326
2013 M SV 0 326
2013 M RS 0 326
2013 M RN 0 326
2013 R NV 0 118
2013 R NA 0 118
2013 R SU 0 118
2013 R SV 0 118
2013 R RS 54 118
2013 R RN 64 118
2013 S NV 2122 24294
2013 S NA 2505 24294
2013 S SU 2734 24294
2013 S SV 6932 24294
2013 S RS 5007 24294
2013 S RN 4994 24294
2013 T NV 328 5855
2013 T NA 460 5855
2013 T SU 904 5855
2013 T SV 1927 5855
2013 T RS 1163 5855
2013 T RN 1073 5855
2013 V NV 1470 20546
2013 V NA 3733 20546
2013 V SU 1581 20546
2013 V SV 3995 20546
2013 V RS 4279 20546
2013 V RN 5488 20546
2013 P NV 537 9648
2013 P NA 716 9648
2013 P SU 1268 9648
2013 P SV 2541 9648
2013 P RS 2179 9648
2013 P RN 2407 9648
2016 A NV 590 13578
2016 A NA 774 13578
2016 A SU 1565 13578
2016 A SV 5458 13578
2016 A RS 2518 13578
2016 A RN 2673 13578
2016 B NV 3482 21791
2016 B NA 4542 21791
2016 B SU 5154 21791
2016 B SV 4062 21791
2016 B RS 2564 21791
2016 B RN 1987 21791
2016 C NV 1044 19870
2016 C NA 1482 19870
2016 C SU 1983 19870
2016 C SV 6857 19870
2016 C RS 4440 19870
2016 C RN 4064 19870
2016 D NV 4951 54990
2016 D NA 6014 54990
2016 D SU 8509 54990
2016 D SV 18049 54990
2016 D RS 8929 54990
2016 D RN 8538 54990
2016 E NV 90 303
2016 E NA 0 303
2016 E SU 213 303
2016 E SV 0 303
2016 E RS 0 303
2016 E RN 0 303
2016 F NV 412 6707
2016 F NA 645 6707
2016 F SU 973 6707
2016 F SV 1742 6707
2016 F RS 1614 6707
2016 F RN 1321 6707
2016 H NV 0 33
2016 H NA 0 33
2016 H SU 0 33
2016 H SV 0 33
2016 H RS 33 33
2016 H RN 0 33
2016 P NV 1823 27449
2016 P NA 2265 27449
2016 P SU 3458 27449
2016 P SV 7227 27449
2016 P RS 6021 27449
2016 P RN 6655 27449
2016 R NV 0 571
2016 R NA 211 571
2016 R SU 74 571
2016 R SV 103 571
2016 R RS 79 571
2016 R RN 104 571
2016 S NV 1054 10893
2016 S NA 1816 10893
2016 S SU 1725 10893
2016 S SV 2532 10893
2016 S RS 1944 10893
2016 S RN 1822 10893
2016 T NV 282 3275
2016 T NA 415 3275
2016 T SU 611 3275
2016 T SV 893 3275
2016 T RS 578 3275
2016 T RN 496 3275
2016 V NV 3032 30166
2016 V NA 4539 30166
2016 V SU 2751 30166
2016 V SV 6378 30166
2016 V RS 6148 30166
2016 V RN 7318 30166
year NV NA SU SV RS RN
2003 21247 27298 28344 48842 42761 42812
2007 21126 27881 30592 54584 43391 43756
2009 21293 28352 32482 58202 43747 43767
2013 21318 29035 33619 63125 45187 45523
2016 21481 29564 35436 68240 45770 46051
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment