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:
.style('white-space', 'nowrap')
so that for Northern Ireland
and 1999
the bar’s text fit’s within the bar’s heightcf
crossfilter object is filtered for only that county. then, updateMap
function is called, which re-renders the map with only the selected county shaded. on mouseout of the county bar, the cf object is unfiltered and the updatemMap
function is called once again. Now all of the counties on the map have data-driven fill colors.index.html
and into a separate file, ireland.svg
. this is more difficult that you might think. these links proved to be quite helpful:d3 google group thread on working with external svg files
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
<!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>
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