D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
michalskop
Full window
Github gist
CZ: Euroelections 2019
<!DOCTYPE html> <html lang="cs"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="author" content="Michal Škop, KohoVolit.eu"> <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"> <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css"> <script src="//d3js.org/d3.v3.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <script src="d3.tip.js"></script> <script src="regression.js"></script> <style type="text/css"> text { font-family: sans-serif; } .tick { fill-opacity: 0; stroke: #000000; stroke-width: 1; } .domain { fill: none; fill-opacity: 0; stroke: black; stroke-width: 1; } .axis line { fill: none; fill-opacity: 0; stroke: black; stroke-width: 1; shape-rendering: crispEdges; } .axis text { font-family: sans-serif; font-size: 15px; } .axis { } circle { fill-opacity: .8; stroke-opacity: 0.99; stroke-width: 1; /*fill: #456;*/ /*stroke: #456;*/ } circle:hover { stroke-opacity: 1; fill-opacity: 1; } path { fill-opacity: 0; stroke: black; stroke-width: 1; fill: none; } .label { font-family: sans-serif; font-size: 15px; } /* this is because of Bootstrap - very important! */ svg:not(:root) { overflow: visible; } /* D3 tips */ .d3-tip { line-height: 1; /*font-weight: bold;*/ padding: 12px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 2px; } .d3-tip small { font-size: 0.5em; } /* Style northward tooltips differently */ .d3-tip.n:after { margin: -1px 0 0 0; top: 100%; left: 0; } .stronger { color: yellow; font-weight: bold; } .top { width: 100vw; padding: 10px; color: white; /*font-size: 3em;*/ /*background-color: #fed201;*/ } #center-line { stroke:rgb(255,0,0); stroke-width: 1; } .info { padding: 10px; width: 100vw; } </style> </head> <body> <h1 class="text-center top bg-primary"> OKRESY ČR eurovolby 2019<br /> <small><span id="subtitle"></span></small> </h1> <div class="row"> <div id="chart" class="col-md-9"></div> <div class="col-md-3"> <div class="alert alert-info"> <i class="fa fa-info-circle"></i> Color legend:<br /> <img src="okresy.png" width="200" /> </div> </div> </div> <div class="alert alert-info info"> <i class="fa fa-info-circle"></i> <br /> Comparison between 2 parties or 2 groups of parties<br /> Parameters:<br /> <ul> <li> <strong>x</strong> party on x axis (e.g., <i>x=Nevoliči</i> or <i>x=ODS,Piráti,STAN+TOP</i>) </li> <li> <strong>y</strong> party on y axis (e.g., <i>y=ANO</i> or <i>y=ANO,EU TROLL,KSČM,ČSSD</i>) </li> <li> <strong>level</strong> is level of detail: <i>1</i> regions, <i>2</i> sub-regions, <i>3</i> municipalities, <i>2_nonvoters</i> sub-regions including non voters (e.g., <i>level=3</i> or <i>level=2_nonvoters</i>) </li> </ul> Examples:<br /> <ul> <li> <a href="https://bl.ocks.org/michalskop/raw/291b1e431ae74d1612b7ef218c1f3dfe/?x=Nevoliči&y=ODS,Piráti,STAN+TOP,KDU-ČSL,Hlas&level=2_nonvoters">Non voters vs. ODS+Piráti+STAN+TOP+KDU-ČSL+Hlas on sub-regional level including non voters</a> </li> <li> <a href="https://bl.ocks.org/michalskop/raw/291b1e431ae74d1612b7ef218c1f3dfe/?x=Piráti&y=SPD&level=2">KDU-ČSL vs. SPD on sub-regional level (excluding non voters)</a> </li> </ul> </div> <script> if (getUrlParameter('level')) { var level = getUrlParameter('level'); } else var level = "2"; var csv = "regions_" + level + ".csv" if (getUrlParameter('x')) { var xs = getUrlParameter('x'); xs = xs.split(','); } else var xs = ['ANO']; if (getUrlParameter('y')) { var ys = getUrlParameter('y'); ys = ys.split(','); } else var ys = ['ODS', 'Piráti', 'KDU-ČSL', 'STAN+TOP']; if (getUrlParameter('maxrange')) var maxrange = parseFloat(getUrlParameter('maxrange')); else var maxrange = 35 var margin = {top: 20, right: 20, bottom: 30, left: 50}, width = 700 - margin.left - margin.right, height = 550 - margin.top - margin.bottom; d3.csv(csv, function(data) { data.sort(function(a, b) { return parseFloat(b.population) - parseFloat(a.population); }); // find ranges for axes: var maxpopulation = 0; var maxy = 0 var maxx = 0 for (var k in data){ data[k]['xn'] = sumInRegion(data[k],xs) data[k]['yn'] = sumInRegion(data[k],ys) if (parseInt(data[k]['population']) > maxpopulation) maxpopulation = parseInt(data[k]['population']); data[k]['id'] = k; if (data[k]['xn']/data[k]['population'] > maxx) maxx = data[k]['xn']/data[k]['population']; if (data[k]['yn']/data[k]['population'] > maxy) maxy = data[k]['yn']/data[k]['population']; } if (getUrlParameter('maxdomain')) if (isNumeric(getUrlParameter('maxdomain'))) var maxdomain = getUrlParameter('maxdomain'); else var maxdomain = maxpopulation; else var maxdomain = maxpopulation; var x = d3.scale.linear() .range([0, width]) .domain([0,1.1*maxx]); var y = d3.scale.linear() .range([height, 0]) .domain([0,1.1*maxy]); var r = d3.scale.sqrt() .domain([0, maxdomain]) .range([1, maxrange]); var formatAsPercentage = d3.format("%"); titlex = createTitle(xs) titley = createTitle(ys) $("#subtitle").html(titlex + " vs. " + titley); var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .tickFormat(formatAsPercentage); var yAxis = d3.svg.axis() .scale(y) .orient("left") .tickFormat(formatAsPercentage); var svg = d3.select("#chart").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 + ")"); /* Initialize tooltip */ var tip = changetooltip(); /* Invoke the tip in the context of your visualization */ svg.call(tip); // Add tooltip div var div = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 1e-6); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text(titley); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("x", x(maxx)) .attr("dy", "-1em") .style("text-anchor", "end") .text(titlex); svg.append("line") .attr("x1", x(0)) .attr("y1", y(0)) .attr("x2", function() { return x(Math.min(maxx, maxy))}) .attr("y2", function() { return y(Math.min(maxx, maxy))}) .attr("id", "center-line") .style("stroke-dasharray", ("3, 5")); nodes = data .map(function(d) { return { x: x(d.xn/d.population), y: y(d.yn/d.population), xn: d.xn, yn: d.yn, r: r(d.population), name: d.name, id: d.id, color: group2color(d.group), xp: Math.round((d.xn / d.population) * 1000) / 10, yp: Math.round((d.yn / d.population) * 1000) / 10 } }); dats = []; for (i in nodes) { dats.push([nodes[i].x,nodes[i].y]); } dats.sort(function(a, b) { return parseFloat(a[0]) - parseFloat(b[0]); }); var myRegression = regression('polynomial', dats, 3); var bubbles = svg.selectAll("svg") .data(nodes) .enter().append("svg:svg").append("svg:circle") .attr("cx", function (d) { return d.x }) .attr("cy", function (d) {return d.y}) .attr("r", function (d) {return d.r}) //.attr("stroke-width", function(d) {return d.r2}) .attr("title", function(d) {return d.name;}) .attr("fill",function(d) { return d.color }) .attr("stroke",function(d) { return d.color }) .on("mouseover", tip.show) .on("mouseout", tip.hide); var line = d3.svg.line() .interpolate("basis-open") .tension(0.1) // <=== THERE IT IS! .x(function(d) { return d[0]; }) .y(function(d) { return d[1]; }); svg.append("path") .attr("d",line(myRegression['points'])); }); //tooltip function changetooltip() { tip = d3.tip().attr('class', 'd3-tip').html(function(d) { html = '<span class="stronger">' + d.name + "</span><br>" + titlex + ": " + d.xp + "% " + d.xn + "<br>" + titley + ": " + d.yp + "% " + d.yn; return html; }); return tip; } function createTitle(arr) { ar = [] for (k in arr) { ar.push(arr[k]) } return ar.join(" + "); } function sumInRegion(items,arr) { var s = 0 for (var k in items) { if ($.inArray(k,arr) >= 0) { s = s + parseInt(items[k]) } } return s } //helper function for default values function getUrlParameter(sParam) { var sPageURL = decodeURIComponent(window.location.search.substring(1)), sURLVariables = sPageURL.split('&'), sParameterName, i; for (i = 0; i < sURLVariables.length; i++) { sParameterName = sURLVariables[i].split('='); if (sParameterName[0] === sParam) { return sParameterName[1] === undefined ? true : sParameterName[1]; } } } // helper function for coloring by region // function region2color(r){ // if (r == 'Hlavní město Praha') return '#b276b2'; // if (r == 'Středočeský kraj') return '#f17cb0'; // if ((r == 'Plzeňský kraj') || (r == 'Jihočeský kraj')) return '#5DA5DA' //'#aec7e8'; // if ((r == 'Ústecký kraj') || (r == 'Karlovarský kraj')) return '#FAA43A'; // if ((r == 'Královéhradecký kraj') || (r == 'Pardubický kraj') || (r == 'Liberecký kraj')) return '#60bd68'; // if ((r == 'Zlínský kraj') || (r == 'Olomoucký kraj')) return '#decf3f'; // if ((r == 'Jihomoravský kraj') || (r == 'Kraj Vysočina')) return '#b2912f'; // if (r == 'Moravskoslezský kraj') return '#f15854'; // return '#4d4d4d'; // } // helper function for coloring by region function region2color(r){ if (r == '1100') return '#b276b2'; if (r == '2100') return '#f17cb0'; if ((r == '3100') || (r == '3200')) return '#5DA5DA' //'#aec7e8'; if ((r == '4100') || (r == '4200')) return '#FAA43A'; if ((r == '5100') || (r == '5200') || (r == '5300')) return '#60bd68'; if ((r == '6100') || (r == '6200')) return '#b2912f'; if ((r == '7100') || (r == '7200')) return '#decf3f'; if (r == '8100') return '#f15854'; return '#4d4d4d'; } function group2color(g){ if (g == "Praha") { return "#C6A373" } if (g == "Bible Belt") { return "#53AFB5" } if (g == "Neviditelní") { return "#B9504C" } if (g == "Jádro") { return "#118AB2" } } // helper function function toObjectWithId(arr) { var rv = {}; for (var i = 0; i < arr.length; ++i) rv[arr[i]['id']] = arr[i]; return rv; } </script> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-8592359-13', 'ocks.org'); ga('send', 'pageview'); </script> </html>
https://d3js.org/d3.v3.min.js
https://code.jquery.com/jquery-1.11.1.min.js