|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8"> |
|
<title>NZ Sheep Density</title> |
|
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script> |
|
<style type="text/css"> |
|
|
|
body { |
|
background-color: steelblue; |
|
} |
|
|
|
svg { |
|
background-color: steelblue; |
|
} |
|
|
|
#container { |
|
width: 1200px; |
|
margin: 0px auto 0px auto; |
|
background-color: steelblue; |
|
padding |
|
} |
|
|
|
.totalContainer { |
|
/* Place the map and barplot containers side-by-side */ |
|
display: inline-block; |
|
width: 49%; |
|
} |
|
|
|
path { |
|
stroke: lightgray; |
|
} |
|
|
|
.description { |
|
fill:navy; |
|
font-family: helvetica; |
|
} |
|
|
|
.highlight { |
|
fill: lightgray; |
|
} |
|
|
|
.yeartitle { |
|
fill: white; |
|
font-family: helvetica; |
|
font-size: 28px; |
|
font-weight: bold; |
|
} |
|
|
|
.axis--x path, |
|
|
|
.axis--x line { |
|
fill: none; |
|
stroke: none; |
|
} |
|
.axis--x text { |
|
fill: white; |
|
font-family: helvetica; |
|
font-size: 11px; |
|
font-weight:bold; |
|
} |
|
|
|
.axis--y path, |
|
|
|
.axis--y line { |
|
fill: none; |
|
stroke: lightgray; |
|
} |
|
|
|
.axis--y text { |
|
fill: white; |
|
font-family: helvetica; |
|
font-size: 11px; |
|
font-weight:bold; |
|
} |
|
|
|
.label { |
|
fill:white; |
|
font-family: helvetica; |
|
} |
|
|
|
.chartTitle { |
|
fill:white; |
|
font-family: helvetica; |
|
font-weight: bold; |
|
font-size: 18px; |
|
} |
|
|
|
</style> |
|
</head> |
|
<body> |
|
|
|
<div id=container> |
|
<div class="totalContainer" id="mapContainer"></div> |
|
<div class="totalContainer" id="bargraphContainer"></div> |
|
</div> |
|
|
|
<script type="text/javascript"> |
|
|
|
//Width and height of containers |
|
var w = d3.select(".totalContainer").node().clientWidth; |
|
var h = 800; |
|
|
|
//height of bargraph and padding |
|
var h_bar = h/2; |
|
var padding = 60; |
|
var bottompadding =150; |
|
|
|
//Color Scale |
|
var color = d3.scale.quantize() |
|
.domain([ 1, 310]) |
|
.range(['#edf8e9','#c7e9c0','#a1d99b','#74c476','#41ab5d','#238b45','#005a32']); //ColorBrewer: Green/Sequential/n=7 |
|
|
|
|
|
//Define Projection |
|
var projection = d3.geo.mercator() |
|
.center([ 172.5, -41 ]) |
|
.translate([ w/2, h/2 ]) |
|
.scale([ h*3 ]); |
|
|
|
//Define path generator |
|
var path = d3.geo.path() |
|
.projection(projection); |
|
|
|
//---------------------------------------------------------------------------------------------------------// |
|
// Load Data |
|
//---------------------------------------------------------------------------------------------------------// |
|
|
|
|
|
//Load in sheep data (by region) |
|
d3.csv("sheepdat.csv", function(data) { |
|
|
|
//Load in sheep data (total) |
|
d3.csv("sheepdattotal.csv", function(totaldata) { |
|
|
|
//Load in GeoJSON data |
|
d3.json("NZL_adm1.json", function(json) { |
|
|
|
//---------------------------------------------------------------------------------------------------------// |
|
// Make Map |
|
//---------------------------------------------------------------------------------------------------------// |
|
|
|
//Merge the regional sheep data and GeoJSON into a single array |
|
// |
|
//Loop through once for each sheep data entry |
|
for (var i = 0; i < data.length; i++) { |
|
|
|
//Grab region name |
|
var dataRegionCode = data[i].region; |
|
|
|
//Grab year |
|
var currentyear = +data[i].year; |
|
|
|
//Grab density value |
|
var dataValue = +data[i].density; |
|
|
|
//Restrict to 2015 (default year for map) |
|
if (currentyear == 2015){ |
|
|
|
//Find the corresponding region inside the GeoJSON |
|
for (var j = 0; j < json.features.length; j++) { |
|
|
|
//We'll check if the json region name matches csv region name |
|
var jsonRegionCode = json.features[j].properties.NAME_1; |
|
|
|
if (dataRegionCode == jsonRegionCode) { |
|
|
|
//Copy the density value into the GeoJSON |
|
json.features[j].properties.sheepdensity = dataValue; |
|
|
|
//Stop looking through the JSON |
|
break; |
|
|
|
} |
|
} |
|
} |
|
} |
|
|
|
//Create SVG element for map |
|
var svg = d3.select("#mapContainer") |
|
.append("svg") |
|
.attr("id", "map") |
|
.attr("width", w) |
|
.attr("height", h); |
|
|
|
//Create groups |
|
var groups = svg.selectAll("g") |
|
.attr("id","graphsgroup"); |
|
|
|
//Bind data and create one path per GeoJSON feature |
|
var regions = groups.data(json.features) |
|
.enter() |
|
.append("path") |
|
.attr("d", path) |
|
.attr("fill", function(d) { |
|
return color(d.properties.sheepdensity); |
|
}) |
|
.attr("opacity",0) //Start hidden for initial transition in |
|
|
|
//Make mouseover (affecting both charts) |
|
.on("mouseover",function(d){ |
|
|
|
//highlight the region on the map |
|
d3.select(this) |
|
.classed("highlight",true); |
|
|
|
//define variable for selected region name |
|
var thisName = d.properties.NAME_1 ; |
|
|
|
//Dim the bars for national average |
|
totalbars.transition() |
|
.duration(500) |
|
.attr("opacity",.2); |
|
|
|
//hide title with (National Average) |
|
figuretitle.transition() |
|
.attr("opacity",0); |
|
|
|
//show title with correct region name |
|
regiontext.filter(function(d){ |
|
if (thisName == d.properties.NAME_1) { |
|
return true; |
|
} |
|
}) |
|
.transition() |
|
.attr("opacity",1); |
|
|
|
//Show barplot for specified region |
|
barplots.filter(function(d) { |
|
if (thisName == d.region) { |
|
return true; //…then it's a match |
|
} |
|
}) |
|
.transition() |
|
.duration(500) |
|
.delay(function(d,i){return i*20;}) |
|
.attr("opacity",.8); //don't give full opacity so can still see national average |
|
}) |
|
|
|
//Put everything back to default on mouseout |
|
.on("mouseout", function(d) { |
|
|
|
//remove highlighted region |
|
d3.select(this) |
|
.classed("highlight",false); |
|
|
|
//bring back national average bars |
|
totalbars.transition() |
|
.duration(500) |
|
.attr("opacity",1); |
|
|
|
//bring back original figure title |
|
figuretitle.transition() |
|
.attr("opacity",1); |
|
|
|
//hide region specific title |
|
regiontext.transition() |
|
.attr("opacity",0); |
|
|
|
//hide region specific bars |
|
barplots.transition() |
|
.attr("opacity",0); |
|
}); |
|
|
|
//Add year next to map |
|
yeartext = groups.data(totaldata) |
|
.enter() |
|
.append("text") |
|
.attr("class","yeartitle") |
|
.attr("text-anchor","left") |
|
.attr("x",2*padding) |
|
.attr("y",h-h_bar-padding) |
|
.text(function(d){ |
|
return d.year; |
|
}) |
|
.attr("opacity",0); //hide at first so will transition in |
|
|
|
//Create Legend for colors |
|
|
|
//define range of values for each color |
|
var legenddat = color.range().map(function(d) { |
|
d = color.invertExtent(d); |
|
if (d[0] == null) d[0] = x.domain()[0]; |
|
if (d[1] == null) d[1] = x.domain()[1]; |
|
return d; |
|
}); |
|
|
|
var squarewidth = 30 |
|
|
|
//create group |
|
var key = svg.selectAll("g") |
|
.data(legenddat) |
|
.enter() |
|
.append("g") |
|
|
|
//make rectangles |
|
var keysquares = key.append("rect") |
|
.attr("x",function(d,i){ |
|
return w/2 +squarewidth*i; |
|
}) |
|
.attr("y", h - bottompadding) |
|
.attr("width",squarewidth) |
|
.attr("height",squarewidth) |
|
.attr("fill",function(d,i){ |
|
return ['#edf8e9','#c7e9c0','#a1d99b','#74c476','#41ab5d','#238b45','#005a32'][i]; |
|
}) |
|
.attr("opacity",0); |
|
|
|
//add labels |
|
var keytext = key.append("text") |
|
.attr("x",function(d,i){ |
|
return w/2 +squarewidth*i; |
|
}) |
|
.attr("y", h - bottompadding - 3) |
|
.text(function(d,i){ |
|
return "< " + d3.format(".0f")(+d[1]); |
|
}) |
|
.attr("font-size",10) |
|
.attr("font-family","helvetica") |
|
.attr("fill","white") |
|
.attr("opacity",0); |
|
|
|
//---------------------------------------------------------------------------------------------------------// |
|
//Create Bar graphs |
|
//---------------------------------------------------------------------------------------------------------// |
|
|
|
//Create SVG for bar graph |
|
var svg = d3.select("#bargraphContainer") |
|
.append("svg") |
|
.attr("id", "map") |
|
.attr("width", w) |
|
.attr("height", h); |
|
|
|
//create groups |
|
var groups = svg.selectAll("g") |
|
.attr("id","graphsgroup"); |
|
|
|
|
|
//Define x scale |
|
|
|
//get list of years |
|
var xdomain = [] |
|
for (var i = d3.min(data,function(d){ |
|
return d.year; |
|
}); |
|
i <= d3.max(data,function(d){ |
|
return d.year;} |
|
); |
|
i++) { |
|
xdomain.push(i.toString()); |
|
} |
|
|
|
//define scale |
|
var xScale = d3.scale.ordinal() |
|
.domain( xdomain) |
|
.rangeRoundBands([ padding, w - padding ], 0.08); |
|
|
|
//define y scale |
|
var yScale = d3.scale.linear() |
|
.domain([ 0, 320 ]) |
|
.rangeRound([ h - bottompadding, h - bottompadding - h_bar ]); |
|
|
|
|
|
//Add Bars for Region (hidden until mouseover region on map) |
|
var barplots = groups.data(data) //use "data" because region specific csv |
|
.enter() |
|
.append("rect") |
|
.attr("x", function(d) { |
|
return xScale(d.year); |
|
}) |
|
.attr("y", function(d) { |
|
return yScale(d.density); |
|
}) |
|
.attr("width", xScale.rangeBand()) |
|
.attr("height", function(d){ |
|
return h - bottompadding - yScale(d.density); |
|
}) |
|
.attr("fill","white") |
|
.attr("opacity",0); |
|
|
|
//Add Bars for National Average (show by default) |
|
var totalbars = groups.data(totaldata) //use "totaldata" because national average csv |
|
.enter() |
|
.append("rect") |
|
.attr("x", function(d) { |
|
return xScale(d.year); |
|
}) |
|
|
|
.attr("y", function(d) { |
|
return h-bottompadding; |
|
}) |
|
.attr("width", xScale.rangeBand()) |
|
.attr("height", function(d){ |
|
return 0; |
|
}) |
|
.attr("fill", function(d){ |
|
return color(d.density); |
|
}) |
|
.attr("opacity",0) //hide at first so can transition in |
|
|
|
//Create mouseover to highlight bars and change year being displayed on map |
|
.on("mouseover",function(d){ |
|
|
|
//highlight selected bar |
|
d3.select(this) |
|
.classed("highlight",true); |
|
|
|
//define year selected |
|
var thisyear = d.year; |
|
|
|
//Change year shown next to map |
|
yeartext.transition() |
|
.attr("opacity",function(d){ |
|
if(d.year==thisyear){ |
|
return 1; |
|
}else{ |
|
return 0; |
|
} |
|
}); |
|
|
|
//Change Map colors based on year (use similar loop as before but change 2015 to selected year) |
|
|
|
//Loop through once for each data entry |
|
for (var i = 0; i < data.length; i++) { |
|
|
|
//Grab region name |
|
var dataRegionCode = data[i].region; |
|
|
|
//Grab year |
|
var currentyear = +data[i].year; |
|
|
|
//Grab density value |
|
var dataValue = +data[i].density; |
|
|
|
//Restrict to year highlighted on barplot ---This is what differs in the loop from the original selection! |
|
if (currentyear == d.year){ |
|
|
|
//Find the corresponding region inside the GeoJSON |
|
for (var j = 0; j < json.features.length; j++) { |
|
|
|
//Check if region from json matches region from csv |
|
var jsonRegionCode = json.features[j].properties.NAME_1; |
|
|
|
if (dataRegionCode == jsonRegionCode) { |
|
|
|
//Copy the data value into the GeoJSON |
|
json.features[j].properties.sheepdensity = dataValue; |
|
|
|
//Stop looking through the JSON |
|
break; |
|
|
|
} |
|
} |
|
} |
|
} |
|
//Change region colors with updated values |
|
regions.transition() |
|
.attr("fill", function(d) { |
|
return color(d.properties.sheepdensity); |
|
}); |
|
}) |
|
|
|
//Return to default (2015) on mouseout |
|
.on("mouseout",function(d){ |
|
|
|
//remove highlight |
|
d3.select(this) |
|
.classed("highlight",false); |
|
|
|
//change year back |
|
yeartext.transition() |
|
.attr("opacity",function(d){ |
|
if(d.year==2015){ |
|
return 1; |
|
} else { |
|
return 0; |
|
} |
|
}); |
|
|
|
//Change Map colors back to 2015 |
|
|
|
//same as original loop |
|
for (var i = 0; i < data.length; i++) { |
|
var dataRegionCode = data[i].region; |
|
var currentyear = +data[i].year; |
|
var dataValue = +data[i].density; |
|
if (currentyear == 2015){ |
|
for (var j = 0; j < json.features.length; j++) { |
|
var jsonRegionCode = json.features[j].properties.NAME_1; |
|
if (dataRegionCode == jsonRegionCode) { |
|
json.features[j].properties.sheepdensity = dataValue; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
//update colors again |
|
regions.transition() |
|
.attr("fill", function(d) { |
|
return color(d.properties.sheepdensity); |
|
}) |
|
}); |
|
|
|
//Add x axis |
|
var xAxis = d3.svg.axis() |
|
.scale(xScale) |
|
.orient("bottom") |
|
.ticks(14); |
|
|
|
var xAx = svg.append("g") |
|
.attr("class", "axis--x") |
|
.attr("transform", "translate(0," + (h - bottompadding) + ")") |
|
.attr("opacity",0) //hide before initial transition in |
|
.call(xAxis); |
|
|
|
//Create y axis |
|
var yAxis = d3.svg.axis() |
|
.scale(yScale) |
|
.orient("left") |
|
.ticks(5); |
|
|
|
var yAx = svg.append("g") |
|
.attr("class", "axis--y") |
|
.attr("transform", "translate(" + padding + ",0)") |
|
.attr("opacity",0) //hide before initial transition in |
|
.call(yAxis); |
|
|
|
|
|
//Create y axis label |
|
var ylabel = svg.append("text") |
|
.attr("class","label") |
|
.attr("text-anchor","middle") |
|
.text("sheep per square km ") |
|
.attr("transform","translate(" + padding/3 +","+ h*.6 +") rotate(-90)" ) |
|
.attr("opacity",0); //hide before initial transition in |
|
|
|
//Create Figure Title |
|
var figuretitle = svg.append("text") |
|
.attr("class","chartTitle") |
|
.attr("x",2*padding) |
|
.attr("y",h-h_bar-bottompadding) |
|
.attr("text-anchor","left") |
|
.text("Sheep Density (National Average)") |
|
.attr("opacity",0); //hide before initial transition in |
|
|
|
|
|
//Create Text for Region (hidden until mouseover on map) |
|
var regiontext = groups.data(json.features) |
|
.enter() |
|
.append("text") |
|
.attr("class","chartTitle") |
|
.attr("text-anchor","left") |
|
.attr("x",2*padding) |
|
.attr("y",h-h_bar-bottompadding) |
|
.text(function(d){ |
|
return "Sheep Density ("+d.properties.NAME_1+" Region)"; |
|
}) |
|
.attr("opacity",0); |
|
|
|
//Add text descriptions |
|
|
|
svg.append("text") |
|
.attr("class","description") |
|
.attr("x",padding) |
|
.attr("y",bottompadding/3) |
|
.text("Interactivity:") |
|
.attr("opacity",0) |
|
.attr("font-weight","bold") |
|
.transition() |
|
.delay(1000) |
|
.duration(1500) |
|
.attr("opacity",1); |
|
svg.append("text") |
|
.attr("class","description") |
|
.attr("x",padding) |
|
.attr("y",bottompadding/3+20) |
|
.text("Hovering over a region on the map will show region-specific changes ") |
|
.attr("opacity",0) |
|
.transition() |
|
.delay(1000) |
|
.duration(1500) |
|
.attr("opacity",1); |
|
svg.append("text") |
|
.attr("class","description") |
|
.attr("x",padding) |
|
.attr("y",bottompadding/3+40) |
|
.text("in sheep density over time in the barplot. Hovering over the barplot will ") |
|
.attr("opacity",0) |
|
.transition() |
|
.delay(1000) |
|
.duration(1500) |
|
.attr("opacity",1); |
|
|
|
svg.append("text") |
|
.attr("class","description") |
|
.attr("x",padding) |
|
.attr("y",bottompadding/3+60) |
|
.text("update the map to show the year highlighted.") |
|
.attr("opacity",0) |
|
.transition() |
|
.delay(1000) |
|
.duration(1500) |
|
.attr("opacity",1); |
|
|
|
//---------------------------------------------------------------------------------------------------------// |
|
// Add initial fade in for each element - start all blue, then show map, then rest of details |
|
//---------------------------------------------------------------------------------------------------------// |
|
|
|
//map |
|
regions.transition() |
|
.duration(1500) |
|
.attr("opacity",1) |
|
.attr("stroke","gray"); |
|
|
|
//year on side of map |
|
yeartext.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",function(d){ |
|
if(d.year==2015){ |
|
return 1; |
|
} else { |
|
return 0; |
|
} |
|
}); |
|
|
|
//Map Key |
|
keysquares.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",1); |
|
|
|
keytext.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",1); |
|
|
|
//bar plot |
|
totalbars.transition() |
|
.duration(1500) |
|
.delay(function(d,i){ |
|
return 1000 +30*i; |
|
}) |
|
.attr("y", function(d) { |
|
return yScale(d.density); |
|
}) |
|
.attr("height", function(d){ |
|
return h - bottompadding - yScale(d.density); |
|
}) |
|
.attr("opacity",1); |
|
|
|
//barplot title |
|
figuretitle.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",1); |
|
|
|
//y axis label |
|
ylabel.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",1); |
|
|
|
//y axis |
|
yAx.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",1); |
|
|
|
//x axis |
|
xAx.transition() |
|
.duration(1500) |
|
.delay(1000) |
|
.attr("opacity",1); |
|
|
|
}); // end json |
|
}); //end csv |
|
}); // end csv |
|
|
|
</script> |
|
</body> |
|
</html> |