Remake del gráfico publicado en el artículo de La Nación: «Cómo variaron los resultados del FPV entre las PASO de 2011 y las de 2015»
Basado en «D3 Slopegraph I» de @zbjornson
Remake del gráfico publicado en el artículo de La Nación: «Cómo variaron los resultados del FPV entre las PASO de 2011 y las de 2015»
Basado en «D3 Slopegraph I» de @zbjornson
| Provincia | 2011 | 2015 | Diferencia | |
|---|---|---|---|---|
| Santa Cruz | 65.54 | 44.35 | -21.19 | |
| Neuquen | 55.29 | 35.63 | -19.66 | |
| Cordoba | 34.25 | 14.66 | -19.6 | |
| Salta | 62.68 | 43.8 | -18.89 | |
| Jujuy | 58.01 | 41.68 | -16.33 | |
| Rio Negro | 60.08 | 44.62 | -15.46 | |
| Tierra del Fgo. | 61.66 | 47.02 | -14.64 | |
| San Luis | 34.15 | 19.58 | -14.58 | |
| Sgo. del Estero | 80.45 | 66.03 | -14.42 | |
| Buenos Aires | 53.35 | 39.49 | -13.86 | |
| Mendoza | 46.94 | 33.2 | -13.74 | |
| Corrientes | 63.42 | 50.24 | -13.17 | |
| Catamarca | 63.43 | 51.59 | -11.85 | |
| San Juan | 65.26 | 54.48 | -10.78 | |
| La Rioja | 50.52 | 40.58 | -9.95 | |
| Formosa | 69.68 | 60.14 | -9.54 | |
| La Pampa | 47.93 | 39.84 | -8.1 | |
| Tucuman | 65.15 | 57.14 | -8.01 | |
| CABA | 30.17 | 23.25 | -6.93 | |
| Misiones | 64.1 | 57.44 | -6.66 | |
| Entre Rios | 45.85 | 39.45 | -6.4 | |
| Chaco | 60.35 | 54.65 | -5.7 | |
| Santa Fe | 37.91 | 32.95 | -4.96 | |
| Chubut | 51.56 | 47.32 | -4.25 |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Diferencia votos positivos al FPV entre PASO 2011 y 2015</title> | |
| <script src="http://mbostock.github.com/d3/d3.v2.min.js?2.8.1"></script> | |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
| <style> | |
| body { color: #444; background: #f3f3f3; font: normal 12px "Adobe Garamond Pro", "Palatino", serif; margin: 2em; } | |
| header { margin: 0 0 20px 220px; border-bottom: 1px solid #6c6c6c; width: 360px; position: relative; } | |
| h1 { font-size: 28px; font-weight: normal; text-shadow: #fff 0 1px 0; margin: 0 0 0 0; padding: 0; } | |
| small { color: #a3a3a3; font-size: 12px; position: absolute; bottom: -2.8em; left: 0;} | |
| a { color: #a3a3a3; } | |
| span.label_year:hover { cursor: ew-resize; } | |
| text.label { fill: #444; } | |
| text.label.start { text-anchor: end; } | |
| line.slope { stroke: #444; stroke-width: 1; } | |
| .missing text.label { display: none; } | |
| .missing line.slope { display: none; } | |
| .over text.label { fill: #bb2629; } | |
| .over line.slope { stroke: #bb2629; stroke-width: 2; } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1> | |
| Diferencia votos positivos al FPV entre PASO 2011 y 2015 | |
| </h1> | |
| <small>Datos del artículo <a href="http://www.lanacion.com.ar/1820011-como-variaron-los-resultados-del-fpv-entre-las-paso-de-2011-y-las-de-2015">Cómo variaron los resultados del FPV entre las PASO de 2011 y las de 2015</a></small> | |
| </header> | |
| <div id="chart"></div> | |
| </body> | |
| <script> | |
| d3.csv("elecciones.csv", function(csv) { | |
| //var csv = cs.slice(1,50); | |
| data = csv; | |
| // console.log("CSV", csv); | |
| var | |
| // Extract years from the dataset | |
| years = d3.keys(csv[0]).filter( function(d) { return d.match(/^\d/) }), // Return numerical keys | |
| // Extract names of countries from the dataset | |
| countries = csv.map( function(d) { return d["Provincia"] }), | |
| // Return true for countries without start/end values | |
| missing = function(d) { return !d.start || !d.end; }, | |
| font_size = 12, | |
| margin = 20, | |
| width = 800, | |
| height = 5 * countries.length * font_size + margin, | |
| chart = d3.select("#chart").append("svg") | |
| .attr("width", width) | |
| .attr("height", height); | |
| //Ignore this code ... makes bl.ocks.org show this in an acceptable-sized iframe. | |
| var styleElement = parent.document.getElementById('styles_js'); if (!styleElement) {styleElement = parent.document.createElement('style'); styleElement.type = 'text/css'; styleElement.id = 'styles_js'; parent.document.getElementsByTagName('head')[0].appendChild(styleElement); } styleElement.appendChild(document.createTextNode('iframe{height:'+height+'px;}')); | |
| // Scales | |
| var slope = d3.scale.linear() | |
| .domain( [83, 29] ) | |
| .range([margin, height]); | |
| var year_scale = d3.scale.linear() | |
| .domain([ parseInt(d3.first(years)), parseInt(d3.last(years)) ]) | |
| .clamp(true); | |
| // Update the chart graphics based on new data for selected year | |
| var update = function() { | |
| var | |
| // Extract country names and start/end values from the dataset | |
| data = csv | |
| .map( function(d, i) { | |
| var r = { | |
| label: d["Provincia"], | |
| start: d3.round(parseFloat(d['2011']),3), | |
| end: d3.round(parseFloat(d['2015']),3) | |
| }; | |
| // console.log(r); | |
| return r; | |
| }) | |
| // Sort in descending order | |
| .sort( function(a,b) { | |
| return d3.max([a.start, a.end]) > d3.max([b.start, b.end]) ? | |
| -1 : | |
| d3.max([a.start, a.end]) < d3.max([b.start, b.end]) ? | |
| 1 : 0; | |
| } ), | |
| // Compute the minimum and maximum value in the dataset | |
| extent = [ csv.map(function(d) { | |
| return d3.entries(d) | |
| .filter(function(d) { return d.key.match(/^\d/) }) | |
| .map(function(d) { return d.value }) | |
| }) ]; | |
| //Go through the list of countries in order, adding additional space as necessary. | |
| var min_h_spacing = 1.2 * font_size, // 1.2 is standard font height:line space ratio | |
| previousY = 0, | |
| thisY, | |
| additionalSpacing; | |
| //Preset the Y positions (necessary only for the lower side) | |
| //These are used as suggested positions. | |
| data.forEach(function(d) { | |
| d.startY = slope(d.start); | |
| d.endY = slope(d.end); | |
| }); | |
| //Loop over the higher side (right) values, adding space to both sides if there's a collision | |
| data | |
| .sort(function(a,b) { | |
| if (a.end == b.end) return 0; | |
| return (a.end < b.end) ? -1 : +1; | |
| }) | |
| .forEach(function(d) { | |
| thisY = d.endY; //position "suggestion" | |
| additionalSpacing = d3.max([0, d3.min([(min_h_spacing - (thisY - previousY)), min_h_spacing])]); | |
| //Adjust all Y positions lower than this end's original Y position by the delta offset to preserve slopes: | |
| data.forEach(function(dd) { | |
| if (dd.startY >= d.endY) dd.startY += additionalSpacing; | |
| if (dd.endY >= d.endY) dd.endY += additionalSpacing; | |
| }); | |
| previousY = thisY; | |
| }); | |
| //Loop over the lower side (left) values, adding space to both sides if there's a collision | |
| previousY = 0; | |
| data | |
| .sort(function(a,b) { | |
| if (a.startY == b.startY) return 0; | |
| return (a.startY < b.startY) ? -1 : +1; | |
| }) | |
| .forEach(function(d) { | |
| thisY = d.startY; //position "suggestion" | |
| additionalSpacing = d3.max([0, d3.min([(min_h_spacing - (thisY - previousY)), min_h_spacing])]); | |
| //Adjust all Y positions lower than this start's original Y position by the delta offset to preserve slopes: | |
| data.forEach(function(dd) { | |
| if (dd.endY >= d.startY) dd.endY += additionalSpacing; | |
| if (dd.startY >= d.startY) dd.startY += additionalSpacing; | |
| }); | |
| previousY = thisY; | |
| }); | |
| // Countries | |
| var country = chart.selectAll("g.country") | |
| .data( data ); | |
| country | |
| .enter() | |
| .append("g") | |
| .attr("class", "country"); | |
| country | |
| .classed("missing", function(d) { return missing(d); }); | |
| country | |
| .on("mouseover", function(d,i) { return d3.select(this).classed("over", true); }) | |
| .on("mouseout", function(d,i) { return d3.select(this).classed("over", false); }); | |
| // ** Left column | |
| var left_column = country | |
| .selectAll("text.label.start") | |
| .data( function(d) { return [d]; } ); | |
| left_column | |
| .enter() | |
| .append("text") | |
| .classed("label start", true) | |
| .attr("xml:space", "preserve") | |
| .style("font-size", font_size) | |
| .attr("x", 200) | |
| .attr("y", 0); | |
| left_column | |
| .attr("y", function(d,i) { return d.startY; }) | |
| .text(function(d) { return d.label+ " " + d3.round(d.start, 2) + "%"; }); | |
| // ** Right column | |
| var right_column = country | |
| .selectAll("text.label.end") | |
| .data( function(d) { return [d]; } ); | |
| right_column | |
| .enter() | |
| .append("text") | |
| .classed("label end", true) | |
| .attr("xml:space", "preserve") | |
| .style("font-size", font_size) | |
| .attr("x", width-200) | |
| .attr("y", 0); | |
| right_column | |
| .attr("y", function(d,i) { return d.endY; }) | |
| .text(function(d) { return d3.round(d.end, 2) + "% " + d.label; }); | |
| // ** Slope lines | |
| var line = country | |
| .selectAll("line.slope") | |
| .data( function(d) { return [d]; } ); | |
| line | |
| .enter() | |
| .append("line") | |
| .attr("x1", 210) | |
| .attr("x2", width-210) | |
| .attr("opacity", 0) | |
| .attr("y1", 0) | |
| .attr("y2", 0); | |
| line | |
| .classed("slope", function(d) { return d.start || d.end; }) | |
| .attr("opacity", 1) | |
| .attr("y1", function(d,i) { return d.start && d.end ? Math.round( d.startY - font_size/2 + 2) : null; }) | |
| .attr("y2", function(d,i) { return d.start && d.end ? Math.round( d.endY - font_size/2 + 2) : null; }); | |
| return chart; | |
| }; | |
| return update( d3.first(years), d3.last(years) ); | |
| }, {}); | |
| </script> | |
| </html> |