Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Skeleton file to explore data in Class 3">
<title>Data Reading & Shaping</title>
<style>
</style>
</head>
<body>
<h4 id="counter"></h4>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// Define the margin object with properties for the four sides
var margin = {top: 20, right: 20, bottom: 120, left: 70};
// define width and height as the INNER dimensions of the chart area
var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var findByYear = function(data, year) {
var resultArry = data.find(function(i) {
return i[0] === year
})
if(resultArry) {
return resultArry[1]
}
}
var buildNationForEachYear = function(nation, year) {
var n = {
name: nation.name,
region: nation.region,
income: findByYear(nation.income, year),
population: findByYear(nation.population, year),
lifeExpectancy: findByYear(nation.lifeExpectancy, year)
}
return n
}
var loadDomain = function(xValues, yValues, popValues, dataForYearX) {
return {
x: d3.extent(xValues),
y: d3.extent(yValues),
pop: d3.extent(popValues),
color: d3.nest().key(function(nation) {return nation.region}).object(dataForYearX)
}
}
var loadRange = function() {
return {
x: [0 , width],
y: [height, 0],
pop: [0, 100],
color: ['red', 'orange', 'green', 'cyan', 'blue', 'purple']
}
}
var loadScale = function(domain, range){
return {
x: d3.scaleLog().domain(domain.x).range(range.x),
y: d3.scaleLinear().domain(domain.y).range(range.y),
pop: d3.scaleSqrt().domain(domain.pop).range(range.pop),
color: d3.scaleOrdinal().domain(domain.color).range(range.color)
}
}
var loadAxis = function(scale) {
return {
x: d3.axisBottom().scale(scale.x),
y: d3.axisLeft().scale(scale.y)
}
}
var drawSVG = function() {
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g") // define svg as a G element that translates the origin to the top-left corner of the chart area.
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")") //(translate (20, 20)
return svg;
}
var appendAxes = function(svg, axes){
svg.append('g')
.attr("transform", "translate(0," + height + ")") // Move x-axis down translate(tx, ty) / (0, 500 - margin.top - margin.bottom)
.call(axes.x)
svg
.append('g')
.call(axes.y)
return svg
}
var appendXYLabels = function(svg) {
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Life Expectancy");
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Income per capita");
}
function updateBubblesByYear(svg, data, scale) {
// Initial year
var year = 1800;
// Increment year for data
newYear = year++;
// Set display counter
window.setInterval(
function () {
newYear = year++;
console.log('new year', newYear)
console.log('year', data[newYear]);
document.getElementById("counter").innerHTML = "It is now " + newYear;
}, 1000);
var bubbles = svg.selectAll('circle')
.data(data[newYear], nation => nation) // key function: controls which datum is assigned to which element
// exit. Get rid of data to match the selection
bubbles.exit().remove();
// enter selection. Chain attributes that don't depend on data. Create a circle for every placeholder
var enter = bubbles.enter().append('circle')
// enter + update. Combines 2 selections into one. This recomputes the data join and maintains the desired correspondence between elements and data. Chain attrs dependent on data
bubbles = enter.merge(bubbles)
.attr("cx", function(nation) { return scale.x(nation.income) })
.attr("cy", function(nation) { return scale.y(nation.lifeExpectancy); })
.attr("r", function(nation) { return scale.pop(nation.population)})
.style("fill", function(nation) {return scale.color(nation.region)});
}
// var year = 1800;
// function increase(){
// year++;
// console.log(year);
// return year;
// };
d3.json('nations.json', function(error, nations) {
console.log('Original data');
console.log(nations);
// make an object where keys are years in the data with an empty array to put our nation data for that year
var endPoint = {}
var allIncomeValues = [];
var allLifeExpectancyValues = [];
var allPopulationValues = [];
var nationYears = nations.map(function(nation) {
// Determine Min and Max for each
var incomeMinMax = d3.extent(nation.income, function(i) {return i[0]})
// [1800, 2009]
var lifeMinMax = d3.extent(nation.lifeExpectancy, function(i) {return i[0]})
// [1803, 2000]
var popMinMax = d3.extent(nation.population, function(i) {return i[0]})
// [1900, 2001]
// Merge the arrays
var allMinMax = d3.merge([incomeMinMax, lifeMinMax, popMinMax])
return d3.extent(allMinMax)
})
// nationYears = [1800, 2009, 1803, 2000, 1900, 2001]
var yearMinMax = d3.extent(d3.merge(nationYears))
//[1800, 2009]
for(var year=yearMinMax[0]; year<=yearMinMax[1]; ++year) {
endPoint[year] = [];
nations.forEach(function(nation) {
var newNation = buildNationForEachYear(nation, year)
if (newNation.income) {
allIncomeValues.push(newNation.income);
}
if (newNation.lifeExpectancy){
allLifeExpectancyValues.push(newNation.lifeExpectancy);
}
if (newNation.population){
allPopulationValues.push(newNation.population);
}
// Remove undefined values
if (newNation.income && newNation.lifeExpectancy && newNation.population) {
endPoint[year].push(newNation);
}
})
}
// Newly structured data
console.log('endPoint 1800', endPoint[1800]);
var year = 1800;
newYear = year++;
var domain = loadDomain(allIncomeValues, allLifeExpectancyValues, allPopulationValues, endPoint[newYear]);
var range = loadRange();
var scale = loadScale(domain, range);
var axes = loadAxis(scale)
var svg = drawSVG();
appendAxes(svg, axes);
appendXYLabels(svg);
function updateBubblesByYear(svg, data, scale) {
newYear = year++;
var bubbles = svg.selectAll("circle")
.data(data[newYear], nation=>nation.name) // key function
// exit. Get rid of data to match the selection
bubbles.exit().remove();
// enter selection. Chain attributes that don't depend on data. Create a circle for every placeholder
var enter = bubbles.enter() // Selection of placeholders
.append("circle") // Creates the circles
}
interval = window.setInterval(
function () {
updateBubblesByYear(svg, endPoint, scale);
// or whatever your update function is called
}, 100);
if (year > 2009) {
return clearInterval(interval);
}
});
// Update selection
// Exit
// Enter
// Enter + Update
</script>
</body>
https://d3js.org/d3.v4.min.js