block by renecnielsen f296ff12f3bea4a68f02

Sporthorse Foal Registrations II

Full Screen

an iteration on Sporthorse Foal Registrations by phoebebright

an example of using d3 + crossfilter together to make an svg map with linked bar charts

these additions and modifications were made made along the way:

d3 google group thread on working with external svg files

an external svg example

an iteration on that example

jsfiddle with .each() technique

a comment:

when you mouse over the bar for Northern Ireland, none of those counties are shaded, even though there appears to be data for those counties. this is something to investigate more. if you know why this is, tweet at me or comment on the github gist.

forked from micahstubbs‘s block: Sporthorse Foal Registrations II

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- thanks to //carisenda.com/sandbox/choropleth/ -->

    <meta charset="utf-8" />
    <title>Irish Sporthorse Foal Registrations</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
    <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.js"></script>

    <link href='//fonts.googleapis.com/css?family=Carrois+Gothic' rel='stylesheet' type='text/css'>

    <style type="text/css" media="screen">
        body, html {
            font-family: 'Carrois Gothic', sans-serif;
            padding: 0;
            margin: 0;
            background-color: #fff;
        }

        #container {
            width: 800px;
            margin-left: auto;
            margin-right: auto;
        }
        h1 {
            text-align: center;
        }

        ul {
            list-style: none;
            margin-left: 0;
            padding-left: 1em;
            text-indent: -1em;
        }

        .year_label, .year_total {
            fill: black;
            text-align:center;
            font-family: 'Carrois Gothic', sans-serif;
            font-size: 18px;
        }
        .year_total {

            font-size: 12px;
        }

        .slide {
            fill: rgb(247,251,255);
        }


        .enabled {
            fill: rgb(238,238,238);
            color: black;
        }

        .bar {
            background: red;
        }
        .county_list {
            background: #6bdd8d;
            font-size: 12px;
            margin: 1px;
            padding: 2px;
        }
        #map, #stats, #selectbar {
            float:left;
        }

        #stats {
            width: 200px;
        }

        #nav {
            height: 140px;
            vertical-align: bottom;
        }

        .slide_txt_val {
            vertical-align: bottom;
            font-size: smaller;
        }
        .big_year {
            font: 200 60px "Helvetica Neue";
            fill: #ddd;
        }

        #selectbar {
          opacity: 0;
        }

    </style>

</head>
<body>
<!--<h1>Sporthorse Foal Registrations</h1>-->
<div id="container">
<div id="nav"></div>
<div id="selectbar">
  Breed code<br />Sire's Breedcode
</div>
<div id="map">
</div> <!-- map -->

<div id="stats"></div>
</div>
<script>

  var w = 700,
      bar_h = 100,    // height of div holding bars
      bar_top_margin = 30,  // space above top of highest bar
      bar_padding = 10; // width between bars + padding
      default_height = 30;  // default height of top bar

  d3.csv("foalreg.csv", function(csv) {

    // load and organise data

    // clean data
    csv.forEach(function(v) {
      v.year = parseInt(v.year);
      v.foals = parseInt(v.foals);
      v.mares = parseInt(v.mares);
      v.coverings = parseInt(v.coverings);
    });

    // create crossfilter
    var cf = crossfilter(csv);

    // create dimensions
    cf.county = cf.dimension(function(d) { return d.county; });
    cf.year = cf.dimension(function(d) { return d.year; });
    cf.foals = cf.dimension(function(d) { return d.foals; });

    // totals by year
    var t1 = cf.year.group()
      .reduceSum(function(d) { return d.foals; })
      .top(Infinity);

    // convert to an associative array
    var year_foals = new Array();
    t1.forEach(function(v) {
      year_foals[v.key] = v.value;
    })

    console.log('cf.county.top(3)', cf.county.top(3));

    // load svg map
    d3.xml("ireland.svg", "image/svg+xml", function(xml) {
      var importedNode = document.importNode(xml.documentElement, true);
      d3.select("div#map")
        .each(function() {
          this.appendChild(importedNode);
        })
      drawYearBars(cf);
      updateChart(cf, 1999);
    });

    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////

    function drawYearBars(cf) {

      // create histogram/tabs at top
      var year_range = [1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011];

      // get a list of the years for which there is data
      var yrs = cf.year.group()
        .reduceSum(function(d) { return d.foals; })
        .top(Infinity)
      
      var got_years = new Array();

      yrs.forEach(function(v) {
          got_years[v.key] = v.value;
      })

      // scale for histogram
      var bar_height = d3.scale.linear()
        .domain([0, d3.max(yrs, function(d) { return d.value; })])
        .range([0, bar_h]);

      var bar_width = ( w / (year_range.length-1) ) - bar_padding;

      var bar_xpos = d3.scale.linear()
        .domain([0, year_range.length])
        .range([0, w]);

      var tabs = d3.select("#nav")
        .append("svg")
        .attr("width", w)
        .attr("height", bar_h + 40);

      tabs.selectAll("rect")
        .data(year_range)
        .enter().append("rect")
        .attr("x", function(d, i) { return bar_xpos(i); })
        .attr("y", function(d) {
            if (got_years[d] != undefined) {
                return bar_h + bar_top_margin - bar_height(got_years[d]);
            } else {
                return bar_h + bar_top_margin - default_height;}
        })
        .attr("height", function(d) {
            if (got_years[d] != undefined) {
                return bar_height(got_years[d]);
            } else {
                return default_height;}
        })
        .attr("width", bar_width)
        .attr("id", function(d) { return d; })
        .attr("class", function(d) {
            var cls = "slide";
            if (d in got_years) {
                cls += " enabled";
            }
            return cls;
        })
        .on('mouseover', function() {
            if (got_years[this.id] != undefined) {
                d3.select(this).style("fill", "#6bdd8d");
                updateChart(cf, this.id);
            }
        })
        .on("mouseout", function(){
            if (got_years[this.id] != undefined) {
                d3.select(this).style("fill", "rgb(238,238,238)");
            }
        })

      // add year labels
      tabs.selectAll(".year_label")
        .data(year_range)
        .enter()
        .append("text")
          .text(function(d) { return d; })
          .attr("class", "year_label")
          .attr("text-anchor", "middle")
          .attr("x", function(d, i) { 
            return bar_xpos(i+1) - (bar_width/2) - (bar_padding/2); 
          })
          .attr("y", function() { 
            return (bar_h + bar_top_margin - 10 ); 
          });

      // add value labels
      tabs.selectAll(".year_total")
        .data(year_range)
        .enter()
        .append("text")
        .text(function(d) {
            if (got_years[d] != undefined) {
                return got_years[d];
            } else {
                return ''}
        })
        .attr("class", "year_total")
        .attr("text-anchor", "middle")
        .attr("x", function(d, i) { return bar_xpos(i+1) - (bar_width/2) - (bar_padding/2); })
        .attr("y", function(d) {
            if (got_years[d] != undefined) {
                return bar_h + bar_top_margin - 5 - bar_height(got_years[d] ) ;
            } else {
                return 0;}
        });
    }

    function updateChart(cf, year) {

      var total_foals,
          data,
          t,
          ext,
          color,
          map,
          counties;

      updateMap(cf, year);

      var county_data = cf.foals.top(Infinity);
      var ext = [0, 900];
      var county_scale = d3.scale.linear()
        .domain(ext)
        .range([0, 150]);

      // show top counties list
      d3.select("#stats")
        .selectAll("div")
        .remove();

      var list = d3.select("#stats")
        .selectAll("div")
        .data(county_data)

      list
        .enter()
        .append("div")
        .attr("class", "county_list")
        .attr("id", function(d) { return d.county + d.year;})
        .text(function(d) {
            return toProper(d.county); })
        .call(div_bar);
      
      list
        .exit().remove();


      function div_bar() {
        this
          .style("height", "16px")
          .style('white-space', 'nowrap') 
          .style("width", function(d) {
            return county_scale(d.foals)+"px";
          })
      }

      // put the year selected on the map
      d3.select(".big_year").remove();

      var year = d3.select("#ireland").append("text")
        .attr("class", "big_year")
        .attr("text-anchor", "end")
        .attr("y", 490)
        .attr("x", 360)
        .text(year);

      setCountyBarMouseoverEvent(cf);

  }

  function updateMap (cf, year) {
    cf.year.filterExact(year);
    total_foals = cf.county.group()
      .reduceSum(function(d) { return d.foals;})
      .top(Infinity);

    data = cf.county.top(Infinity);

    t = cf.foals.groupAll().value();

    ext = d3.extent(data, function(d) { return d.foals; });
    ext = [0,1000];

    color = d3.scale.linear()
      .domain(ext)
      .range(["white", "green"]);

    map = d3.select('#map');

    counties = map.selectAll('path.republic')
      .style('fill', function(d){    // would normally use attr but svg has used style for fill
        var clr = "#fff";

        // only look at items in the counties layer
        if (this.parentNode.id == "republic") {

          var county = this.id.toUpperCase();

          data.forEach(function(v, i, ar) {
              if (v.county == county) {
                  clr =  color(v.foals)
              }
          });
        }
        return clr;

      });

  }

  function setCountyBarMouseoverEvent (cf) {
    d3.selectAll('div.county_list')
      .on('mouseover', function(d) {
        // style the bar gray
        d3.select(this).style("background", "rgb(238,238,238)"); 

        cf.county.filter(d.county);
        updateMap(cf, d.year);
      })
      .on("mouseout", function(d) {
        // style the bar green again
        d3.select(this).style("background", "#6bdd8d");

        var countyID = toProper(d.county);
        cf.county.filterAll();
        updateMap(cf, d.year);

      })
  } //setCountyBarMouseoverEvent

  });


  function toProper(str)
  {
      return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
  }
</script>
</body>
</html>

foalreg.csv

year,county,mares,coverings,foals
1999,CARLOW,38,197,162
1999,CAVAN,42,193,102
1999,CLARE,93,348,259
1999,CORK,134,606,389
1999,DONEGAL,76,182,107
1999,DUBLIN,46,76,57
1999,GALWAY,170,726,478
1999,KERRY,73,179,121
1999,KILDARE,64,148,118
1999,KILKENNY,86,353,249
1999,LAOIS,41,168,122
1999,LEITRIM,29,94,60
1999,LIMERICK,39,186,124
1999,LONGFORD,37,109,74
1999,LOUTH,16,102,70
1999,MAYO,60,262,149
1999,MEATH,67,169,116
1999,MONAGHAN,72,345,190
1999,OFFALY,50,171,127
1999,ROSCOMMON,39,198,135
1999,SLIGO,39,151,96
1999,TIPPERARY,86,419,313
1999,WATERFORD,40,149,106
1999,WESTMEATH,56,195,121
1999,WEXFORD,103,418,303
1999,WICKLOW,61,223,163
1999,NORTHERN IRELAND,234,683,403
1999,ABROAD,73,53,18
2004,CARLOW,30,172,139
2004,CAVAN,108,217,150
2004,CLARE,155,505,420
2004,CORK,232,509,405
2004,DONEGAL,87,212,155
2004,DUBLIN,74,98,77
2004,GALWAY,343,856,602
2004,KERRY,105,260,194
2004,KILDARE,104,165,135
2004,KILKENNY,110,351,288
2004,LAOIS,61,226,180
2004,LEITRIM,32,87,58
2004,LIMERICK,70,232,175
2004,LONGFORD,58,159,133
2004,LOUTH,38,88,50
2004,MAYO,123,327,225
2004,MEATH,73,140,98
2004,MONAGHAN,83,329,234
2004,OFFALY,99,165,134
2004,ROSCOMMON,119,226,164
2004,SLIGO,74,177,134
2004,TIPPERARY,220,551,428
2004,WATERFORD,69,181,137
2004,WESTMEATH,94,171,122
2004,WEXFORD,179,462,398
2004,WICKLOW,128,272,226
2006,CARLOW,78,203,155
2006,CAVAN,70,271,195
2006,CLARE,189,637,490
2006,CORK,221,650,472
2006,DONEGAL,91,237,152
2006,DUBLIN,88,129,92
2006,GALWAY,388,1106,760
2006,KERRY,120,248,183
2006,KILDARE,109,126,95
2006,KILKENNY,144,382,313
2006,LAOIS,90,229,168
2006,LEITRIM,43,120,98
2006,LIMERICK,114,271,193
2006,LONGFORD,74,166,115
2006,LOUTH,36,94,66
2006,MAYO,181,435,280
2006,MEATH,100,153,108
2006,MONAGHAN,90,335,247
2006,OFFALY,105,219,147
2006,ROSCOMMON,130,335,241
2006,SLIGO,92,236,185
2006,TIPPERARY,212,678,493
2006,WATERFORD,104,206,155
2006,WESTMEATH,87,214,150
2006,WEXFORD,216,484,393
2006,WICKLOW,116,372,269
2006,NORTHERN IRELAND,399,817,585
2006,ABROAD,188,64,48
2007,CARLOW,58,202,154
2007,CAVAN,68,297,207
2007,CLARE,151,644,508
2007,CORK,200,687,512
2007,DONEGAL,82,271,171
2007,DUBLIN,60,131,87
2007,GALWAY,315,1227,865
2007,KERRY,118,325,236
2007,KILDARE,74,184,140
2007,KILKENNY,129,397,317
2007,LAOIS,67,282,175
2007,LEITRIM,28,137,112
2007,LIMERICK,102,305,209
2007,LONGFORD,50,177,105
2007,LOUTH,29,111,64
2007,MAYO,140,455,307
2007,MEATH,77,196,149
2007,MONAGHAN,87,340,204
2007,OFFALY,78,220,165
2007,ROSCOMMON,98,349,253
2007,SLIGO,75,258,192
2007,TIPPERARY,181,710,544
2007,WATERFORD,69,230,189
2007,WESTMEATH,83,247,187
2007,WEXFORD,191,584,471
2007,WICKLOW,131,405,304
2007,NORTHERN IRELAND,380,870,585