Skip to content

Instantly share code, notes, and snippets.

@roblevy
Last active July 20, 2017 09:20
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 roblevy/bff5a5a8e450ab9935bc692c6ccec9e3 to your computer and use it in GitHub Desktop.
Save roblevy/bff5a5a8e450ab9935bc692c6ccec9e3 to your computer and use it in GitHub Desktop.
BBC pay ranked by gender
border: no
license: gpl-3.0

A visulisation of the infamous BBC pay release.

On the left, people are ranked by pay according to gender. The most well-paid man is top-left, the most well-paid woman is top-right.

On the right, people are ranked by pay overall.

A perfectly distributed pay scheme would see all lines being almost horizontal. Downward sloping lines represent people who do worse in the ranking overall than their within-gender ranking would suggest.

overall_rank name genre role gender pay pay_low pay_high
1 Chris Evans Multi-genre Presenter Male 2200-2249 2200 2249
2 Gary Lineker Sport Presenter Male 1750-1799 1750 1799
3 Graham Norton Multi-genre Presenter Male 850-899 850 899
4 Jeremy Vine Multi-genre Presenter Male 700-749 700 749
5 John Humphrys Multi-genre Presenter Male 600-649 600 649
6 Huw Edwards Multi-genre Presenter Male 550-599 550 599
7 Steve Wright Radio Presenter Male 500-549 500 549
8 Claudia Winkleman Multi-genre Presenter Female 450-499 450 499
9 Matt Baker Multi-genre Commentator and presenter Male 450-499 450 499
10 Alan Shearer Sport Presenter Male 400-449 400 449
11 Alex Jones TV non-scripted (factual and entertainment) Presenter Female 400-449 400 449
12 Andrew Marr Multi-genre Presenter Male 400-449 400 449
13 Nicky Campbell Radio Presenter Male 400-449 400 449
14 Stephen Nolan Multi-genre Presenter Male 400-449 400 449
15 Derek Thompson TV Scripted (Drama and Comedy) Actor Male 350-399 350 399
16 Fiona Bruce Multi-genre Presenter Female 350-399 350 399
17 Nicholas Grimshaw Radio Presenter Male 350-399 350 399
18 Simon Mayo Radio Presenter Male 350-399 350 399
19 Tess Daly TV non-scripted (factual and entertainment) Presenter Female 350-399 350 399
20 Vanessa Feltz Radio Presenter Female 350-399 350 399
21 Eddie Mair News and current affairs Presenter Male 300-349 300 349
22 Lauren Laverne Radio Presenter Female 300-349 300 349
23 Nick Knowles TV non-scripted (factual and entertainment) Presenter Male 300-349 300 349
24 Sue Barker Sport Presenter Female 300-349 300 349
25 Amanda Mealing TV Scripted (Drama and Comedy) Actor Female 250-299 250 299
26 Brian Cox Multi-genre Presenter Male 250-299 250 299
27 Evan Davis Multi-genre Presenter Male 250-299 250 299
28 George Alagiah News and current affairs Presenter Male 250-299 250 299
29 Jason Mohammad Sport Presenter Male 250-299 250 299
30 Ken Bruce Radio Presenter Male 250-299 250 299
31 Nicholas Robinson News and current affairs Presenter Male 250-299 250 299
32 Scott Mills Radio Presenter Male 250-299 250 299
33 Trevor Nelson Radio Presenter Male 250-299 250 299
34 Zoe Ball Multi-genre Presenter Female 250-299 250 299
35 Adam Woodyatt TV Scripted (Drama and Comedy) Actor Male 200-249 200 249
36 Alan Yentob TV non-scripted (factual and entertainment) Presenter Male 200-249 200 249
37 Andrew Neil News and current affairs Presenter Male 200-249 200 249
38 Bruno Tonioli TV non-scripted (factual and entertainment) Contributor Male 200-249 200 249
39 Dan Walker Multi-genre Presenter Male 200-249 200 249
40 Dannii Minogue TV non-scripted (factual and entertainment) Contributor Female 200-249 200 249
41 Danny Dyer TV Scripted (Drama and Comedy) Actor Male 200-249 200 249
42 David Jason TV Scripted (Drama and Comedy) Actor Male 200-249 200 249
43 Emilia Fox TV Scripted (Drama and Comedy) Actor Female 200-249 200 249
44 Gabby Logan Sport Presenter Female 200-249 200 249
45 Gary Barlow TV non-scripted (factual and entertainment) Contributor Male 200-249 200 249
46 John Inverdale Sport Presenter Male 200-249 200 249
47 Jonathan Sopel News and current affairs Correspondent Male 200-249 200 249
48 Jools Holland Multi-genre Presenter Male 200-249 200 249
49 Laura Kuenssberg News and current affairs Correspondent Female 200-249 200 249
50 Len Goodman TV non-scripted (factual and entertainment) Contributor Male 200-249 200 249
51 Mark Chapman Multi-genre Presenter Male 200-249 200 249
52 Mark Radcliffe Radio Presenter Male 200-249 200 249
53 Martha Kearney News and current affairs Presenter Female 200-249 200 249
54 Mishal Husain News and current affairs Presenter Female 200-249 200 249
55 Peter Capaldi TV Scripted (Drama and Comedy) Actor Male 200-249 200 249
56 Rosie Marcel TV Scripted (Drama and Comedy) Actor Female 200-249 200 249
57 Victoria Derbyshire News and current affairs Presenter Female 200-249 200 249
58 Adrian Chiles Radio Presenter Male 150-199 150 199
59 Ben Brown News and current affairs Presenter Male 150-199 150 199
60 Catherine Shipton TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
61 Clare Balding Sport Presenter Female 150-199 150 199
62 Craig Horwood TV non-scripted (factual and entertainment) Contributor Male 150-199 150 199
63 Darcey Bussell TV non-scripted (factual and entertainment) Contributor Female 150-199 150 199
64 Diane Parish TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
65 Gavin Esler News and current affairs Presenter Male 150-199 150 199
66 Gillian Taylforth TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
67 Greg James Radio Presenter Male 150-199 150 199
68 Guy Henry TV Scripted (Drama and Comedy) Actor Male 150-199 150 199
69 Hugh Quarshie TV Scripted (Drama and Comedy) Actor Male 150-199 150 199
70 James Naughtie News and current affairs Correspondent and presenter Male 150-199 150 199
71 Jemma Redgrave TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
72 Jeremy Bowen News and current affairs Correspondent Male 150-199 150 199
73 Jo Whiley Radio Presenter Female 150-199 150 199
74 John McEnroe Sport Presenter and commentator Male 150-199 150 199
75 John Pienaar News and current affairs Correspondent Male 150-199 150 199
76 John Simpson News and current affairs Correspondent Male 150-199 150 199
77 Jonathan Agnew Sport Presenter and commentator Male 150-199 150 199
78 Jonathan Davies Sport Contributor Male 150-199 150 199
79 Justin Webb News and current affairs Presenter Male 150-199 150 199
80 Kamal Ahmed News and current affairs Correspondent Male 150-199 150 199
81 Kirsty Wark News and current affairs Presenter Female 150-199 150 199
82 Lacey Turner TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
83 Laurie Brett TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
84 Letitia Dean TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
85 Linda Henry TV Scripted (Drama and Comedy) Actor Female 150-199 150 199
86 Mark Easton News and current affairs Correspondent Male 150-199 150 199
87 Mel Giedroyc TV non-scripted (factual and entertainment) Presenter Female 150-199 150 199
88 Moira Stuart Radio Presenter Female 150-199 150 199
89 Naga Munchetty Multi-genre Presenter and contributor Female 150-199 150 199
90 Paul Martin TV non-scripted (factual and entertainment) Presenter Male 150-199 150 199
91 Scott Maslen TV Scripted (Drama and Comedy) Actor Male 150-199 150 199
92 Shaun Keavney Radio Presenter Male 150-199 150 199
93 Simon Schama TV non-scripted (factual and entertainment) Presenter Male 150-199 150 199
94 Sophie Raworth News and current affairs Presenter Female 150-199 150 199
95 Tameka Empson TV Scripted (Drama and Comedy) Actor and contributor Female 150-199 150 199
96 Tim Roth TV Scripted (Drama and Comedy) Actor Male 150-199 150 199
var w = 640, h = 800;
var margin = 20;
var top_margin = margin * 4;
var svg = d3.select('body').append('svg')
.attr('width', w)
.attr('height', h);
var left = 4 * w / 16, left_female = 5 * w / 16;
var right = 3 * w / 4;
var left_scale_m = d3.scaleLinear(), left_scale_f = d3.scaleLinear(),
right_scale = d3.scaleLinear();
var female_colour = '#fc8d59', male_colour = '#91bfdb';
var radius = 4;
// Create detail for each data point
var set_values = function(d, i) {
d['rank'] = i + 1;
d['lhs_y'] = d.gender == 'Male' ? left_scale_m(d.rank) : left_scale_f(d.rank);
d['lhs_x'] = d['gender'] == 'Male' ? left : left_female;
d['rhs_y'] = right_scale(d.overall_rank);
d['rhs_x'] = right;
}
var mouse_over = function(d) {
d3.selectAll('[id^="' + d.name + '"]').classed('selected', true);
}
var mouse_out = function(d) {
d3.selectAll('[id^="' + d.name + '"]').classed('selected', false);
}
d3.csv('bbc_pay.csv', function(error, data) {
// Split into male and female
var f = data.filter(function(d) { return d.gender == 'Female'; });
var m = data.filter(function(d) { return d.gender == 'Male'; });
// Set the scales
left_scale_m.domain([1, m.length]).range([top_margin, h - margin]);
left_scale_f.domain([1, f.length]).range([top_margin, h - margin]);
right_scale.domain([1, data.length]).range([top_margin, h - margin]);
// Set the details
f.forEach(set_values);
m.forEach(set_values);
data = m.concat(f);
// Links
var links = [];
var names = [];
for (var i in data) {
var d = data[i];
names.push(d.name);
links.push({'name': d.name, 'gender': d.gender, 'xy': [
{'x': d.rhs_x, 'y': d.rhs_y},
{'x': d.rhs_x - (d.rhs_x - d.lhs_x) / 5, 'y': d.rhs_y},
{'x': d.lhs_x + (d.rhs_x - d.lhs_x) / 5, 'y': d.lhs_y},
{'x': d.lhs_x, 'y': d.gender == 'Male' ?
m.filter(function(e) { return e.overall_rank == d.overall_rank})[0].lhs_y :
f.filter(function(e) { return e.overall_rank == d.overall_rank})[0].lhs_y}]});
}
var link_line = d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.curve(d3.curveBasis);
svg.append('g').selectAll('path').data(links).enter().append('path')
.attr('d', function(d) { return link_line(d.xy); })
.style('stroke', function(d, i) { return data[i].colour; })
.style('fill', 'none')
.attr('class', function(d) { return d.gender == 'Male' ? 'm' : 'f' })
.attr('id', function(d, i) { return names[i] + " link"; });
// LHS
var lhs = svg.append('g').attr('id', 'lhs');
lhs.selectAll('circle').data(data).enter().append('circle')
.attr('cx', function(d) { return d.lhs_x; })
.attr('cy', function(d) { return d.lhs_y; })
.attr('r', radius)
.attr('id', function(d) { return d.name + " l"; })
.attr('overall_rank', function(d) { return d.overall_rank; })
.attr('rank', function(d) { return d.rank; })
.attr('class', function(d) { return d.gender == 'Male' ? 'm' : 'f' })
.classed('lhs', true);
// RHS
var rhs = svg.append('g').attr('id', 'rhs');
rhs.selectAll('.rhs').data(data).enter().append('circle')
.attr('cx', function(d) { return d.rhs_x; })
.attr('cy', function(d) { return d.rhs_y; })
.attr('r', radius)
.attr('id', function(d) { return d.name + " r"; })
.attr('overall_rank', function(d) { return d.overall_rank; })
.attr('rank', function(d) { return d.rank; })
.attr('class', function(d) { return d.gender == 'Male' ? 'm' : 'f' })
.classed('rhs', true);
// Text
svg.append('g').selectAll('text').data(data).enter().append('text')
.text(function(d) { return d.name; })
.attr('x', function(d) { return d.rhs_x + 10; })
.attr('y', function(d) { return d.rhs_y + 5; })
.attr('id', function(d) { return d.name + " text"; })
.attr('class', function(d) { return d.gender == 'Male' ? 'm' : 'f' })
// Interactivity
d3.selectAll('circle, path')
.on('mouseover', mouse_over)
.on('mouseout', mouse_out);
// Labels
svg.append('text')
.text('Best-paid man')
.classed('label', true)
.attr('transform', 'translate(' + left + ',' + (top_margin - 10) + ') rotate(-30)');
svg.append('text')
.text('Best-paid woman')
.classed('label', true)
.attr('transform', 'translate(' +left_female + ',' + (top_margin - 10) + ') rotate(-30)');
svg.append('text')
.text('Best-paid person')
.classed('label', true)
.attr('transform', 'translate(' + right + ',' + (top_margin - 10) + ') rotate(-30)');
});
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.4/d3.min.js"></script>
<style>
* {
font-family: sans-serif;
}
path {
stroke-opacity: 0.4;
stroke-width: 3px;
}
text {
fill: #555555;
}
text.m, text.f {
visibility: hidden;
}
circle.m {
fill: #91bfdb;
stroke: #91bfdb;
stroke-width: 0;
}
circle.f {
fill: #fc8d59;
stroke: #fc8d59;
stroke-width: 0;
}
path.m {
stroke: #91bfdb;
}
path.f {
stroke: #fc8d59;
}
circle.selected {
stroke-width: 4;
}
path.selected {
stroke-width: 8;
}
text.selected{
visibility: visible;
}
</style>
</head>
<body>
<div>
Hover over to see who's who.
</div>
<script src='bbc_pay.js'></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment