|
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)'); |
|
}); |