D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
michalskop
Full window
Github gist
CZ: support by age
Distribution of voters' support by age
Czechia, 10-11/2019
<!DOCTYPE html> <html lang="cs"> <meta charset="utf-8" /> <svg></svg> <script src="https://d3js.org/d3.v4.min.js"></script> <link href="https://fonts.googleapis.com/css?family=Kalam&display=swap" rel="stylesheet"> <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> <style> html { font-family: 'Kalam', cursive; } .weak { opacity: 0.5 } </style> <script> let bins = 6 let binLabels = ['Koalice'] var margin = {top: 100, right: 30, bottom: 100, left: 60} var svg = d3.select("svg") .attr('width', 1500 + margin.left + margin.right) .attr('height', 300 + margin.top + margin.bottom), width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom; var x = d3.scaleLinear() .domain([0, 100]) .range([0, width]), y = d3.scaleLinear() .domain([0, 8]) .range([height, 0]) function age2y(age) { return parseInt(age[0]) } function addProperties( obj, arr , property ) { let merged = obj arr.forEach((item, i) => { if (item[property] == obj[property]) { merged = {...obj, ...item} // console.log(merged) } }); return merged } function compare( a, b, property, reverse=1 ) { if ( a[property] < b[property] ){ return -1 * reverse; } if ( a[property] > b[property] ){ return 1 * reverse; } return 0; } function rebin(obj) { let reobj = obj if (parseInt(obj.bin) == 1 && obj.strength == 'weak') { reobj.bin = 2 } if (parseInt(obj.bin) == 5 && obj.strength == 'weak') { reobj.bin = 4 } reobj.bin = parseInt(obj.bin) return reobj } function getAgeGroups(data) { let ag = [] data.forEach((item, i) => { if (!ag.includes(item.age)) { ag.push(item.age) } }); return ag } d3.csv("data200_2.csv", function(error, data) { d3.csv("parties.csv", function(e, parties) { if (error) throw error; var g = svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") // PREPARE DATA // join data, re-bin weak data let displayData = data.map(function (obj) { // console.log(addProperties(obj, parties, 'party')) return rebin(addProperties(obj, parties, 'party')) }) // order data displayData.sort((a, b) => compare(a, b, 'order', -1)) displayData.sort((a, b) => compare(a, b, 'age', -1)) displayData.sort((a, b) => compare(a, b, 'strength')) displayData.sort((a, b) => compare(a, b, 'bin')) // get age groups ageGroups = getAgeGroups(displayData) // indexes indexes = {} ageGroups.forEach((item, i) => { indexes[item] = {} for (i = 1; i <= bins; i++) { indexes[item][i] = 0 } }); // prepare points let points = [] let lines = [18, 25, 35, 47, 65] let centers = [lines[0] / 2] for (i = 0; i < (bins - 2); i++) { centers.push((lines[i] + lines[i + 1]) / 2) } centers.push((lines[i] + 90) / 2) displayData.forEach((item, i) => { for (i = 0; i < parseInt(item['value']); i++) { let newItem = Object.assign({}, item) if (item.bin == 1) { newItem.x = lines[0] - indexes[item.age][item.bin] } if (item.bin == 2) { newItem.x = lines[1] - indexes[item.age][item.bin] } if (item.bin == 3) { newItem.x = (lines[2] + lines[1]) / 2 + ((indexes[item.age][item.bin] % 2) * 2 - 1) * Math.round(indexes[item.age][item.bin] / 2) } if (item.bin == 4) { newItem.x = lines[2] + 1 + indexes[item.age][item.bin] } if (item.bin == 5) { newItem.x = lines[3] + 1 + indexes[item.age][item.bin] } if (item.bin == 6) { newItem.x = lines[4] + 1 + indexes[item.age][item.bin] } indexes[item.age][item.bin]++ newItem.y = age2y(item.age) points.push(newItem) } }) // DISPLAY points g.selectAll(".icon") .data(points) .enter() .append("text") .attr('font-family', 'FontAwesome') .attr('font-size', 30) .attr('fill', function(d) {return d.color}) .attr('class', function(d) { return d.strength }) .attr('stroke-width', 1) .attr('stroke', '#aaa') .attr('text-anchor',"middle") .attr('x',function(d) {return x(d.x)}) .attr('y',function(d) {return y(d.y)}) .text('\uf183') // display counts counts = [] for (i = 0; i < bins; i++) { c = { 'count': 0, 'x': centers[i] } counts.push(c) } for(var a in indexes) { for(var b in indexes[a]) { counts[b - 1].count = counts[b - 1].count + indexes[a][b] } } svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .selectAll(".counts") .data(counts) .enter() .append("text") .attr("x", function(d) { return x(d.x) }) .attr("y", function() { return y(-1) }) .attr('text-anchor',"middle") .attr("font-size", 48) .attr("font-weight", "bold") .attr("fill", function(d, i) { if (i == counts.length - 1) { return "gray" } else { return "green" } }) .text(function(d) { return d.count }) // bins let dlines = lines dlines[0]++ dlines[1]++ svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .selectAll(".bins") .data(dlines) .enter() .append("line") .attr("x1", function(d) { return x(d) }) .attr("y1", function() { return y(-1)}) .attr("x2", function(d) { return x(d) }) .attr("y2", function() { return y(10)}) .attr("stroke", "green") .attr("stroke-width", 1) .attr("stroke-dasharray", 4) // display ages svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .selectAll(".ages") .data(ageGroups) .enter() .append("text") .attr("x", function() { return x(0) }) .attr("y", function(d, i) { return y(ageGroups.length - i) }) .attr('text-anchor',"end") .attr("font-size", 24) .text(function(d) { return d }) svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .selectAll(".ages") .data(ageGroups) .enter() .append("line") .attr("x1", function() { return x(-2) }) .attr("y1", function(d, i) { return y(ageGroups.length - i - 0.2)}) .attr("x2", function() { return x(100) }) .attr("y2", function(d, i) { return y(ageGroups.length - i - 0.2)}) .attr("stroke", "#aaaaaa") .attr("stroke-width", 1) .attr("stroke-dasharray", 4) svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .append("line") .attr("x1", function() { return x(lines[lines.length - 1]) }) .attr("y1", function() { return y(-1)}) .attr("x2", function() { return x(lines[lines.length - 1]) }) .attr("y2", function() { return y(10)}) .attr("stroke", "#aaaaaa") .attr("stroke-width", 5) }) }) </script> </html>
https://d3js.org/d3.v4.min.js