D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
Contrastat
Full window
Github gist
Ongoing Unemployment Project
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Bar Chart, Framed</title> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script> <!-- <script type="text/javascript" src="../d3.v3.js"></script> --> <style type="text/css"> body { margin: 0; background-color: white; font-family: Helvetica, Arial, sans-serif; } div { /*background-color: #F2F2F2;*/ background-color: white; } #UnemploymentProject { height: 200px; width: 700px; margin-left: auto; margin-right: auto; margin-top: 50px; padding: 50px; background-color: white; /*box-shadow: 3px 3px 5px 6px #ccc;*/ } #Part1{ width: 700px; margin-left: auto; margin-right: auto; margin-top: 50px; padding: 50px; background-color: white; /*box-shadow: 3px 3px 5px 6px #ccc;*/ } #UnemploymentRate{ width: 700px; margin-left: auto; margin-right: auto; margin-top: 50px; padding: 50px; background-color: white; /*box-shadow: 3px 3px 5px 6px #ccc;*/ } #Part2{ width: 700px; margin-left: auto; margin-right: auto; margin-top: 50px; padding: 50px; background-color: white; /*box-shadow: 3px 3px 5px 6px #ccc;*/ } #Scatter{ width: 700px; margin-left: auto; margin-right: auto; margin-top: 50px; padding: 50px; background-color: white; /*box-shadow: 3px 3px 5px 6px #ccc;*/ } h1 { margin: 0; font-family: Helvetica, Arial, sans-serif; font-size: 48px; font-weight: bold; color: #A01E0C; border-bottom: solid 8px #A01E0C; } h2 { font-family: Helvetica, Arial, sans-serif; font-size: 24px; font-weight: bold; color: black; text-align:justify; } h3 { font-family: Helvetica, Arial, sans-serif; font-size: 16px; font-weight: normal; font-style: italic; color: black; } p { font-family: Helvetica; font-size: 12px; font-weight: normal; color: black; text-align:justify; line-height: 1.3; margin: 15px 0 10px 0; margin-top: 0em; margin-bottom: 0.5em; } a:link { text-decoration: none; color: gray; } a:hover { text-decoration: underline; } a:visited { color: gray; } a:active { color: steelBlue; } svg { background-color: white; } g.bar{ cursor:pointer; } g.bar text { font-size: 9px; /*font-weight: bold;*/ text-anchor: end; opacity: 0; fill: white; } rect:hover { fill: #A01E0C; opacity: 1; color: white; } g.bar:hover text{ cursor:pointer; opacity: 1; color: white; } .line-label { opacity: 1; color: black; font-size: 10px; font-weight: bold; } .highlight path { stroke: rgb(205,10,30); stroke-width: 3; } g.circle text { font-size: 11px; font-weight: bold; text-anchor: end; opacity: 0; } g.circle{ cursor:pointer; } g.circle:hover { fill: #A01E0C; } g.circle:hover text { opacity: 1; } .axis path, .axis line { fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-serif; font-size: 9px; } .y.axis path, .y.axis line { opacity: 0; } .y2.axis path, .y2.axis line { opacity: 1; } /* input[type="button"]:hover{ border: 1px solid #999;color:#0000ff; } input[type="button"]:active{ border: 1px solid #999;color:#0000ff; } */ #buttons{ width: 300px; margin-left: auto; margin-right: auto; margin-top: 10px; padding: 50px; background-color: white; height: 10px; } #YVarSel{ width: 600px; margin-left: auto; margin-right: auto; margin-top: 10px; padding: 50px; background-color: white; height: 5px; } #XVarSel{ width: 800px; margin-left: auto; margin-right: auto; margin-top: 10px; padding: 50px; background-color: white; height: 5px; } .click { padding: 5px 10px; border: 1px solid; background: white; margin: 5px 10px; /*border-radius: 5px;*/ cursor: pointer; transition: background .2s; outline: 0; } .click:hover { background: rgb(182,86,100); border-color: rgb(205,10,30); color: white; } .click.active { background: rgb(140,60,70); background: rgb(205,10,30); color: white; font-weight: bold; } .variableX { padding: 5px 10px; border: 1px solid; background: white; margin: 5px 10px; /*border-radius: 5px;*/ cursor: pointer; transition: background .2s; outline: 0; } .variableX:hover { background: rgb(182,86,100); border-color: rgb(205,10,30); color: white; } .variableX.active { background: rgb(140,60,70); background: rgb(205,10,30); color: white; font-weight: bold; } .variableY { padding: 5px 10px; border: 1px solid; background: white; margin: 5px 10px; /*border-radius: 5px;*/ cursor: pointer; transition: background .2s; outline: 0; } .variableY:hover { background: rgb(182,86,100); border-color: rgb(205,10,30); color: white; } .variableY.active { background: rgb(140,60,70); background: rgb(205,10,30); color: white; font-weight: bold; } .selection{ height: 45px; } </style> </head> <body> <div id="UnemploymentProject"> <h1>Unemployment Rate in Spain</h1> <h2>A visual explanation of the regional differences of unemployment in Spain</h2> <p>(Use this two buttons to switch from CCAA to Province)</p> </div> <div id="Part1" class="selection"> <h1> Unemployment level</h2> <input id = 'UnempBar' name="UnempBar" type="button" value="Hide / Show" onclick= "toggle_visibility('UnemploymentRate')" /> </div> <div id="UnemploymentRate"> <h2> The code below shows the unemployment rate in Spain for the last quarter of 2015.</h2> <p>As we can see, not only the unemployment level in Spain is quite high but there is also a lot of variability among regions regarding that variable. Among the potential candidates to explain it, we selected three variables that we think correlate with low productivity of the labor force: construction sector importance, public sector share of the employent and low education attaintment.</p> </div> <div id="Part2" class="selection"> <h1>Potential Explanation</h1> <input id = 'UnempScatter' name="UnempScatter" type="button" value="Hide / Show" onclick= "toggle_visibility('XVarSel'), toggle_visibility('YVarSel'), toggle_visibility('Scatter')" /> </div> <div id="XVarSel"> </div> <div id="YVarSel"> </div> <div id="Scatter"> <h2> The code below shows the relationship between the unemployment rate and the long term unemployemnt in Spain during the last quarter of 2015 and the level of three variables back at the end of 2005, that is, just before the great recession started.</h2> <p> Although causality is a tough animal to domesticate, a couple of interesting facts arise. For instance, with the exception of Melilla, the highest the proportion of people working in construction (a proxy for the relevance of this activity in the region), the highest the unemployment rate today. The share of employment in the public sector does not seems to explain anything about the current unemployment and finally, those regions with the highest share of people in the work force without having completed the high school are the ones with the highest rate of unemployment, and does a particular good fit in the case of long term unemployment (Long term unemployment refers to the share of people unemployed for two years or more. ). That is, two variables, relevance of construction in the region up to the crisis and low education attaintment seems to be good candidates to explain the variability we observe in the unemployment rate in Spain.</p> </div> <script type="text/javascript"> d3.select("div", "#UnemploymentProject") .append("div") .attr("id", "buttons"); var regiones = ['CCAA', 'Provincia']; var scatterX = ['Share of Low Educatation Attaintment','Construction Share of Employment','Public Sector Share of Employment']; var scatterY = ['Unemployment Rate','Long Term Unemployment Rate']; function transformVar(variable){ if (variable === scatterX[0]){ return 'eso2005'; } else if (variable === scatterX[1]){ return 'const2005'; } else if (variable === scatterX[2]){ return 'publ2005'; } else if (variable === scatterY[0]){ return 'atur2015'; } else if (variable === scatterY[1]){ return 'vlatur2015'; } } var currentRegion = regiones[0]; var auxRegion = regiones[0]; var currentScatterX = transformVar(scatterX[1]); var currentScatterY = transformVar(scatterY[0]); //console.log(currentScatterX) var auxX = scatterX[1]; var auxY = scatterY[0]; //console.log(regiones); function setRegion() { var btn = d3.select("#buttons") .append("div"); btn.selectAll("div") .data(regiones) .enter() .append("button") .attr("type", "button") .attr("class", function(d){ var className = "click"; if (d === currentRegion) { className += " active"; } return className; }) .text(function(d){ return d; }) .on("click", function(d) { d3.select(".click.active").classed("active", false); d3.select(this).classed("active", true); //console.log(d); //console.log(currentRegion); if (d === "CCAA"){ auxRegion = d; updateCharts(); } else if (d === "Provincia"){ auxRegion = d; updateCharts(); } }) } function setVar(xVars, yVars) { var btnX = d3.select("#XVarSel") .append("div") .attr('class', 'varX') .append('h3') .html('Please select the X variable' + "<br/>"); var btnY = d3.select("#YVarSel") .append("div") .attr('class', 'varY') .append('h3') .html('Please select the Y variable' + "<br/>"); btnX.selectAll(".varX") .data(xVars) .enter() .append("button") .attr("type", "button") .attr("class", function(d){ var className = "variableX"; if (d === auxX) { className += " active"; } return className; }) .text(function(d){ return d; }) .on("click", function(d) { d3.select(".variableX.active").classed("active", false); d3.select(this).classed("active", true); //console.log(d) currentScatterX = transformVar(d); //console.log(currentScatterX); //console.log(currentScatterY); updateScatter(); }) btnY.selectAll(".varY") .data(yVars) .enter() .append("button") .attr("type", "button") .attr("class", function(d){ var className = "variableY"; if (d === auxY) { className += " active"; } return className; }) .text(function(d){ return d; }) .on("click", function(d) { d3.select(".variableY.active").classed("active", false); d3.select(this).classed("active", true); //console.log(d); currentScatterY = transformVar(d); //console.log(currentScatterX); //console.log(currentScatterY); updateScatter(); }) } var w = 700; var h = 600; var padding = {top: 20, right: 10, bottom: 30, left: 136}; //Top, right, bottom, left //Bar Chart var widthScale = d3.scale.linear() .range([ 0, w - padding.right - padding.left ]); var heightScale = d3.scale.ordinal() .rangeRoundBands([ padding.top, h - padding.bottom ], 0.1); var xAxis = d3.svg.axis() .scale(widthScale) .orient("bottom"); var yAxis = d3.svg.axis() .scale(heightScale) .orient("left"); var svg = d3.select("#UnemploymentRate") .append("svg") .attr("id", "chart") .attr("width", w) .attr("height", h); var groups = d3.select("#chart") .append('g') .attr("class", "chart"); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(" + padding.left + "," + (h - padding.bottom) + ")") .append("text") .attr("class", "label") .attr("x", w - 150) .attr("y", 28) .style("text-anchor", "end") .text("Unemployment rate in %"); svg.append("g") .attr("class", "y axis") .attr("transform", "translate(" + padding.left + ",0)"); svg.append("g") .attr("class", "espanya line") var lespanya = d3.select(".espanya.line") .append("line") .attr("class", "line") .style("stroke-width", 2) .style("stroke", "black") .style("stroke-dasharray", ("3, 3")) .style("fill", "none"); var container = svg.append("g") .attr("class", "espanya") var lespanya = container .append("line") .attr("class", "line") .style("stroke-width", 2) .style("stroke", "black") .style("stroke-dasharray", ("3, 3")) .style("fill", "none"); var text = container .append("text") .attr("class", "line-label") function drawbars(data){ var espanya = aggregatevalue(data)[0]['2015']; var maximo = highestvalue(data)[0]['id1']; //console.log(data); //console.log(maximo); //console.log(espanya); data = data.filter(function(d) { return d.id1 != "Espanya";}); data.sort(function(a, b) { return d3.descending(+a['2015'],+b['2015']); }); widthScale.domain([ 0, Math.ceil(d3.max(data, function(d) { return +d['2015']; })) ]); heightScale.domain(data.map(function(d) { return d.id1; } )); //console.log(data2); var bar = groups.selectAll(".bar") .data(data) //.attr("x", padding.left) //.attr("y", function(d) { // return heightScale(d.id1); //}) .attr("height", heightScale.rangeBand()) .attr("width", function(d) { return widthScale(d['2015']) }) .attr("fill", function(d) { if (d.id1 === "Espanya") { return "rgb(205, 10, 30)";} else{ return "steelblue";} }) .attr("x", function(d) { return padding.left + widthScale(d['2015']) - 3; }) .attr("y", function(d) { return heightScale(d.id1) + 8; }) .text(function(d) { return Math.round(d['2015']*100)/100 + "%"; }); bar.enter().append("g").attr("class", "bar"); bar.append('rect') .attr("x", padding.left) .attr("y", function(d) { return heightScale(d.id1); }) .attr("height", heightScale.rangeBand()) //.attr("width", function(d) { // return widthScale(d['2015']) //}) .attr("width", 0) .attr("fill", function(d) { if (d.id1 === "Espanya") { return "rgb(205, 10, 30)";} else{ return "steelblue";} }) bar.append("text") .attr("x", function(d) { return padding.left + widthScale(d['2015']) - 3; }) .attr("y", function(d) { return heightScale(d.id1) + 8; }) .text(function(d) { return Math.round(d['2015']*100)/100 + "%"; }); bar.selectAll('rect') .transition() .delay(function(d, i) { return i * 50; }) .duration(1000) .attr("width", function(d) { return widthScale(d['2015']); }); bar.exit().remove(); lespanya.attr("x1", padding.left + widthScale(espanya)) .attr("y1", heightScale(maximo)) .attr("x2", padding.left + widthScale(espanya)) .attr("y2", h - padding.bottom); text.attr("x", padding.left + widthScale(espanya) + 10) .attr("y", 300) .text(function(d){ return "Spain Average unemployment " + Math.round(espanya*100)/100 + "%"; }); svg.select('.x.axis').call(xAxis); svg.select('.y.axis').call(yAxis); } //Scatter Plot var xScale2 = d3.scale.linear() .range([padding.left, w - padding.right - padding.left ]); var yScale2 = d3.scale.linear() .range([padding.top, h - padding.bottom]); var xAxis2 = d3.svg.axis() .scale(xScale2) .orient("bottom") .ticks(5); var yAxis2 = d3.svg.axis() .scale(yScale2) .orient("left") .ticks(5); var svg2 = d3.select("#Scatter") .append("svg") .attr("id", "chart2") .attr("width", w) .attr("height", h); var groups2 = d3.select("#chart2") .append('g') .attr("class", "chart"); svg2.append("g") .attr("class", "x axis") .attr("transform", "translate (0," + (h - padding.bottom + 3) + ")") .append("text") .attr("class", "label") .attr("x", w - padding.left) .attr("y", padding.bottom - 5) .style("text-anchor", "end") .text(function(d){return changeLabel(currentScatterX) + " %"}); svg2.append("g") .attr("class", "y2 axis") .attr("transform", "translate(" + (padding.left - 5) + ",0)") .append("text") .attr("class", "label") .attr("x", 15) .attr("y", 15) .style("text-anchor", "end") .text(function(d){return changeLabel(currentScatterY) + " %"}); //console.log(currentScatterY); //console.log(scatterY[0]); //console.log(changeLabel(currentScatterY)); function drawscatter(data){ data.sort(function(a, b) { return d3.descending(+a[currentScatterY], +b[currentScatterY]); }); yScale2.domain([ d3.max(data, function(d){return +d[currentScatterY];}), d3.min(data, function(d){return +d[currentScatterY];}) ]); xScale2.domain([ d3.min(data, function(d){return +d[currentScatterX];}), d3.max(data, function(d){return +d[currentScatterX];}) ]); //console.log(data); var balls = groups2.selectAll(".circle") .data(data) //.enter() //.append('circle') .attr("cy", function(d){ return yScale2(d[currentScatterY]); }) .attr("cx", function(d){ return xScale2(d[currentScatterX]); }) .attr("r", 3) .attr("fill", function(d) { if (d.id1 === "Espanya") { return "rgb(205, 10, 30)";} else {return "steelblue";} }) .text(function(d) { return d[currentScatterY] + d[currentScatterX] + "%"; }); balls.enter().append("g").attr("class", "circle"); balls.append('circle') .attr("cy", (h - padding.bottom + 3)) .attr("cx", 0) .attr("r", 0) .attr("fill", function(d) { if (d.id1 === "Espanya") { return "rgb(205, 10, 30)";} else {return "steelblue";} }); balls.selectAll('circle') .transition() .delay(function(d, i) { return i * 5; }) .duration(2000) .attr("cy", function(d){ return yScale2(d[currentScatterY]); }) .attr("cx", function(d){ return xScale2(d[currentScatterX]); }) .attr("r", 3) .attr("fill", function(d) { if (d.id1 === "Espanya") { return "rgb(205, 10, 30)";} else {return "steelblue";} }); balls.append("text") .attr("x", function(d) { return xScale2(+d[currentScatterX]); }) .attr("y", function(d) { return yScale2(+d[currentScatterY] + 0.0005); }) .text(function(d) { return d.id1; }); balls.exit().remove(); svg2.select('.x.axis') //.text(function(d){return changeLabel(currentScatterX)}) .call(xAxis2) .select("text") .text(function(d){return changeLabel(currentScatterX) + " %"}); svg2.select('.y2.axis') //.text(function(d){return changeLabel(currentScatterY)}) .call(yAxis2) .select("text") .text(function(d){return changeLabel(currentScatterY) + " %"}); } function changeLabel(label){ if (label === transformVar(scatterX[0])){ return scatterX[0]; } else if (label === transformVar(scatterX[1])){ return scatterX[1]; } else if (label === transformVar(scatterX[2])){ return scatterX[2]; } else if (label === transformVar(scatterY[0])){ return scatterY[0]; } else if (label === transformVar(scatterY[1])){ return scatterY[1]; } } function toggle_visibility(id){ var e = document.getElementById(id); if (e.style.display !== 'none'){ e.style.display = 'none'; } else{ e.style.display = 'block'; } } function datafilter(d){ data = data.filter(function(d) { return d.id1 != "Espanya";}); return data;} function aggregatevalue(d){ agregado = d.filter(function(d) { return d.id1 === "Espanya"; }) return agregado; } function highestvalue(data){ maximo = data.filter(function(d){ return +d['2015'] == d3.max(data, function(d) { return +d['2015'];}) }) return maximo; } /* var toggleColor = (function(){ var currentColor = "white"; return function(){ currentColor = currentColor == "white" ? "magenta" : "white"; d3.select(this).style("fill", currentColor); } })(); */ function updateCharts(){ if (auxRegion === "Provincia"){ updateProv(); } else if (auxRegion === "CCAA"){ updateCCAA(); } } function updateScatter(){ if (auxRegion === "Provincia"){ d3.csv("scatterProv.csv", drawscatter); } else if (auxRegion === "CCAA"){ d3.csv("scatterCCAA.csv", drawscatter); } } function updateProv(){ d3.csv("tasaaturProv.csv", //function(data) { // console.log(data);}) drawbars); d3.csv("scatterProv.csv", //function(data) { // console.log(data);}) drawscatter); } function updateCCAA(){ d3.csv("tasaaturCCAA.csv", //function(data) { // console.log(data);}) drawbars); d3.csv("scatterCCAA.csv", //function(data) { // console.log(data);}) drawscatter); } d3.csv("tasaaturCCAA.csv", //function(data) { // console.log(data);}) drawbars); d3.csv("scatterCCAA.csv", //function(data) { // console.log(data);}) drawscatter); setRegion(); setVar(scatterX, scatterY); </script> <p class="source"> Source: Spanish National Institute of Statistics <a href="https://www.ine.es/dyngs/INEbase/es/operacion.htm?c=Estadistica_C&cid=1254736176918&menu=resultados&secc=1254736030639&idp=1254735976595">Active Population Survey Microdata </a> The raw data comes from the <a href="www.ine.es">Spanish National Statistics Institute (INE)</a>. In order to convert the raw data into an csv output that could be easily managed by D3, I made use of R, particularly the <a href = "https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf"> tidyr and dplyr packages</a>. The R code can be found here. This is just a first step of a much ambicious that will try to characterize unemployment in Spain. So far, the code produces a bar chart with the unemployment rate by CCAA (first level of government) and by province (second level) and a stacked area chart with the total number of unemployed since 2005 by province or CCAA. The objective is to add more features to the html. </p> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js