Block-a-Day #4. French departments (an administrative division that contains multiple districts) are positioned on a triangular plot according to the percentage of their labor force in three categories: I. agriculture, II. industry, and III. commerce, transportation, and services. From an idea by Jacques Bertin.
Click on a category or arrow to reorient the chart.
Data Sources: Jacques Bertin, Semiology of Graphics, p. 100
What I Learned: Rotation transforms never do what you expect on the first try. Actually, I knew that one already.
What I'd Do With More Time: I'm sure there's a way to get the triangle to rotate smoothly around its center, but I just ran out of time to figure it out. If you know, ping me @cmgiven.
Just what it sounds like. For fifteen days, I will make a D3.js v4 block every single day. Rules:
xxxxxxxxxx
<meta charset="utf-8">
<style>
.axis .domain { display: none; }
line.grid {
stroke: #999;
}
line.dash {
stroke: #333;
stroke-width: .5;
}
text.label {
text-transform: uppercase;
font-family: monospace;
font-weight: 700;
font-size: 24px;
letter-spacing: 0.1;
}
path.arrow, text.label {
fill: #333;
cursor: pointer;
}
circle {
fill: rgba(100,75,170,.8);
stroke: rgb(100,75,170);
stroke-width: 1;
}
</style>
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var margin = { top: 50, bottom: 200 }
var width = 960
var height = 800 - margin.top - margin.bottom
var side = height * 2 / Math.sqrt(3)
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + ((width - side) / 2) + ',' + (margin.top + 0.5) + ')')
.append('g')
var sideScale = d3.scaleLinear()
.domain([0, 1])
.range([0, side])
var perpScale = d3.scaleLinear()
.domain([0, 1])
.range([height, 0])
var r = d3.scaleSqrt().range([0, 10])
var axis = d3.axisLeft()
.scale(perpScale)
.tickFormat(function (n) { return (n * 100).toFixed(0) })
.tickSize(side * -0.3)
.tickPadding(5)
var axes = svg.selectAll('.axis')
.data(['i', 'ii', 'iii'])
.enter().append('g')
.attr('class', function (d) { return 'axis ' + d })
.attr('transform', function (d) {
return d === 'iii' ? ''
: 'rotate(' + (d === 'i' ? 240 : 120) + ',' + (side * 0.5) + ',' + (height / 3 * 2) + ')'
})
.call(axis)
axes.selectAll('line')
.attr('class', 'dash')
.attr('transform', 'translate(' + (side * 0.2) + ',0)')
.attr('stroke-dasharray', '9,7')
.attr('y1', 0)
.attr('y2', 0)
axes.selectAll('text')
.attr('transform', 'translate(' + (side * 0.2) + ',-5)')
axes.selectAll('.tick')
.append('line')
.attr('class', 'grid')
.attr('x1', function (d) { return side * (d * 0.5) })
.attr('x2', function (d) { return side * (-d * 0.5 + 1) })
.attr('y1', 0)
.attr('y2', 0)
axes.append('path')
.attr('class', 'arrow')
.attr('d', 'M0 0 L5 9 L2 9 L2 15 L-2 15 L-2 9 L-5 9 Z')
.attr('transform', 'translate(' + (side * 0.5) + ',10)')
.on('click', rotate)
axes.append('text')
.attr('class', 'label')
.attr('x', side * 0.5)
.attr('y', -6)
.attr('text-anchor', 'middle')
.attr('letter-spacing', '-8px')
.text(function (d) { return d })
.on('click', rotate)
function rotate(d) {
var angle = d === 'i' ? 120 : d === 'ii' ? 240 : 0
svg.transition().duration(600)
.attr('transform', 'rotate(' + angle + ',' + (side / 2) + ',' + (height / 3 * 2) + ')')
}
d3.csv('data.csv', function (d) {
var i = +d.i
var ii = +d.ii
var iii = +d.iii
var total = i + ii + iii
var iShare = i / total
var iiShare = ii / total
var iiiShare = iii / total
return {
department: d.department,
total: total,
i: i,
ii: ii,
iii: iii,
iShare: iShare,
iiShare: iiShare,
iiiShare: iiiShare,
x: iiShare + (iiiShare * 0.5)
}
}, function (error, data) {
if (error) { throw error }
r.domain([0, d3.max(data, function (d) { return d.total })])
svg.selectAll('.point')
.data(data)
.enter().append('circle')
.attr('class', 'point')
.attr('r', function (d) { return r(d.total) })
.attr('cx', function (d) { return sideScale(d.x) })
.attr('cy', function (d) { return perpScale(d.iiiShare) })
.append('title')
.text(function (d) { return d.department })
})
</script>
</body>
https://d3js.org/d3.v4.min.js