block by davo 4fd75255d0c4ed3e312a

Diferencia porcentual votos positivos al FPV entre PASO 2011 y 2015 — Por provincia

Full Screen

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

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Diferencia votos positivos al FPV entre PASO 2011 y 2015</title>
  <script src="//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="//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>

elecciones.csv

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