D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
patiencehaggin
Full window
Github gist
Haggin Health & Wealth Animated
Built with
blockbuilder.org
<!DOCTYPE html> <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