Last active
April 20, 2017 17:03
-
-
Save beemyfriend/7ae636bb5e8202b6f926485af2b45e82 to your computer and use it in GitHub Desktop.
D3 Makeover: Week 1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <head> | |
| <link rel='stylesheet' href='../styles.css'> | |
| <style> | |
| div.tooltip{ | |
| position: absolute; | |
| text-align: left; | |
| width: 250px; | |
| height: 90px; | |
| padding: 5px; | |
| font-size: 14px; | |
| background: lightsteelblue; | |
| border: 0px; | |
| border-radius: 8px; | |
| pointer-events: none; | |
| } | |
| #sections > div{ | |
| opacity: .3; | |
| } | |
| #sections div.graph-scroll-active{ | |
| opacity: 1; | |
| } | |
| #container{ | |
| position: relative; | |
| overflow: auto; | |
| } | |
| #sections{ | |
| width: 400px; | |
| float: left; | |
| } | |
| #graph{ | |
| float: left; | |
| left: 400px; | |
| } | |
| #graph.graph-scroll-fixed{ | |
| position: fixed; | |
| top: 0px; | |
| left: 400; | |
| margin-left: 10; | |
| } | |
| body{ | |
| background-color: whitesmoke; | |
| } | |
| svg{ | |
| background-color: none; | |
| position: absolute; | |
| top:0px; | |
| z-index: 2; | |
| } | |
| </style> | |
| </head> | |
| <body>'> | |
| <div id = 'container'> | |
| <div id = 'sections'> | |
| <div> | |
| <h1>ONE LAPTOP PER CHILD</h1> | |
| <b><a href = 'http://one.laptop.org/'>One Laptop Per Child</a></b> is an organization dedicated | |
| to providing low cost laptop computers to the world's poorest | |
| children. The goal is to empower the world's poorest children | |
| through education provided by these laptops. So far, OLPC has | |
| delivered laptops to over 2 million children and teachers in 6 different countries. | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| Ofcourse, the laptops are not evenly distributed among all the | |
| different countries. Some countries receive more laptops than others. | |
| Here the countries are represented by circles. The radii of these | |
| circles correlates to the number of laptops given to children | |
| and teachers of their corresponding countries.<br><br> | |
| <i>The radius is correleated to the square root of the total number of laptops given.</i> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| While it is nice to see the numbers of computers given to a particular | |
| country, it is perhaps even more useful to see the ratio of computer given | |
| to the total population of the country. This may provide us with more information | |
| on the impact <b>OLPC</b> is having on the country. <br><br> | |
| <i>The radius is correlated to the square root of the laptop/population ratio.</i><br><br> | |
| <i>The radius of the circles will stay the same from now on.</i> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| Truth be told, it is hard to compare the size of the circles when | |
| they are layed out on a map. Here is a more conventional map with | |
| continents on the x-axis and the natural log of the total number of | |
| laptops given on the y-axis. Peru and Uruguay quickly stand for receiving | |
| a big portion of these laptops. Indeed, these two countries received | |
| 1.5 million free laptops.<br><br> | |
| <i>If you want to know which country each circle represents, then | |
| simply place your mouse ontop of the circle.</i> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| Here is the same information, but now the natural log of the | |
| laptop/population ratio is plotted on the y-axis. | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| Most of the laptops that <b>OLPC</b> provides go to countries with | |
| at least 20% of their populations below the national poverty line.<br><br> | |
| <i>Poverty information provided by the CIA's <a href = 'https://www.cia.gov/library/publications/the-world-factbook/fields/2046.html'>World Factbook</a></i> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| Most of the countries recieving laptops have high literacy rates. This | |
| suggests that a majority of the children receiving laptops should be | |
| able to take advantage of the free resources provided online (which they | |
| can connect to with their computer)<br><br> | |
| <i>A low literacy rate is a literacy rate of less than 70%, an average | |
| literacy rate is one between 70% and 90%, and a high literacy rate is | |
| one above 90%</i><br><br> | |
| <i>Literacy information provided by the <a href = 'http://data.worldbank.org/indicator'>World Bank</a></i> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| <div> | |
| Most of the countries recieving laptops have an average or | |
| high unemployment rate. The laptops not only provide children with | |
| a new tool for education, but also provides them with a possible | |
| employed future. Indeed, the number of remote jobs, that is jobs where | |
| the location does not matter as long as the employee has a computer, is on the rise. | |
| The children recieving the laptops, whe we suppose are literate, can now | |
| develop skills in order to seek employment in the future.<br><br> | |
| <i>A low unemployment rate is an unemployment rate of less than 4%, an average | |
| unemployment rate is one between 4% and 10%, and a high unemployment rate is | |
| one above 10%</i><br><br> | |
| <i>Literacy information provided by the <a href = 'http://data.worldbank.org/indicator'>World Bank</a></i><br><br><br><br> | |
| <i>The aggregated data can be found in csv format <a href = 'beemyfriend.github.io/Projects/laptops.csv'>here</a></i> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| <br><br><br><br><br><br><br><br><br><br> | |
| </div> | |
| </div> | |
| <div id = 'graph'></div> | |
| </div> | |
| <script src = 'https://d3js.org/d3.v4.js'></script> | |
| <script src = 'https://rawgit.com/beemyfriend/beemyfriend.github.io/master/Projects/graph-scroll.js'></script> | |
| <script> | |
| var width = 900, | |
| height = 600, | |
| margin = { | |
| left: 140, | |
| top: 100, | |
| right:50, | |
| bottom: 50 | |
| }, | |
| animationDuration = 1500, | |
| logBase = Math.E, | |
| circleRRange = [4,40]; | |
| //=============================================// | |
| //create data for .scaleOrdinal. spacing arrays will position | |
| //each data point on the x-axis | |
| //=============================================// | |
| var continents = ["Africa", "Asia", "Central America", "Europe", | |
| "Oceania", "South America", 'None'] | |
| var continentSpacing = []; | |
| for(var i = 0; i < continents.length -1; i++){ | |
| var tot_width = width - margin.left - margin.right; | |
| var spacing = tot_width/(continents.length-1); | |
| continentSpacing.push(margin.left +((i+1) * spacing)) | |
| } | |
| var rangeSpacing = []; | |
| for(var i = 0; i< 4; i++){ | |
| var tot_width = width - margin.left - margin.right; | |
| var spacing = tot_width/4; | |
| rangeSpacing.push(margin.left + ((i+1) * spacing)) | |
| } | |
| var colors = ['#8dd3c7', '#ffffb3', '#fdb462', '#80b1d3', | |
| '#b3de69', '#fccde5', 'grey'] | |
| var colorsBinary = ['lightgrey', 'lightgrey', 'lightgrey', 'lightgrey', | |
| 'lightgrey', 'lightgrey', 'grey'] | |
| var svg = d3.select('#graph') | |
| .append('svg') | |
| .attr('width', width) | |
| .attr('height', height); | |
| //=============================================// | |
| //create scales for graph axis | |
| //=============================================// | |
| var projection = d3.geoMercator() | |
| .scale(width/2/Math.PI) | |
| .translate([width/2, height/2]); | |
| var path = d3.geoPath() | |
| .projection(projection); | |
| var r_count = d3.scaleSqrt() | |
| .range(circleRRange); | |
| var r_countxpop = d3.scaleSqrt() | |
| .range(circleRRange); | |
| var x_continent = d3.scaleOrdinal() | |
| .domain(continents) | |
| .range(continentSpacing) | |
| var x_poverty = d3.scaleLinear() | |
| .range([margin.left, width-margin.right]) | |
| var x_ranges = d3.scaleOrdinal() | |
| .range(rangeSpacing) | |
| .domain(['Low', 'Average', 'High', 'Not Available']) | |
| var y_count = d3.scaleLog() | |
| .base(logBase) | |
| .range([height-margin.bottom, margin.top]) | |
| var y_countxpopulation = d3.scaleLog() | |
| .base(logBase) | |
| .range([height-margin.bottom, margin.top]) | |
| var clr = d3.scaleOrdinal() | |
| .range(colors) | |
| .domain(continents); | |
| var clrBinary = d3.scaleOrdinal() | |
| .range(colorsBinary) | |
| .domain(continents); | |
| //=============================================// | |
| //div and handle_mouse_ functions are for tooltips | |
| //=============================================// | |
| var div = d3.select('body').append('div') | |
| .attr('class', 'tooltip') | |
| .style('opacity', 0); | |
| function handle_mouse_over(d, i){ | |
| div.transition() | |
| .duration(500) | |
| .style('opacity', .8) | |
| svg.selectAll('#' + d.Country_code) | |
| .attr('fill-opacity', 1) | |
| .raise() | |
| if(d3.event.pageX < (440 + width/2) ){ | |
| div.style('left', (d3.event.pageX) + 'px') | |
| } else { | |
| div.style('left', (d3.event.pageX - 250) + 'px') | |
| } | |
| if(this.getBBox().y < (height/2)){ | |
| div.style('top', (d3.event.pageY) + 'px'); | |
| } else { | |
| div.style('top', (d3.event.pageY - 90) + 'px'); | |
| } | |
| div.html('<b>Country:</b> ' + d.country + | |
| '<br><b>Computers given:</b> ' + d.count + | |
| '<br><b>Population:</b> ' + d.Population + | |
| '<br><b>Computers Given/Population Ratio:</b> ' + d.countxpopulation + | |
| '<br><b>% Below Poverty Line:</b> ' + d.pop_below_poverty + '%' | |
| ); | |
| } | |
| function handle_mouse_out(d, i){ | |
| svg.selectAll('#' + d.Country_code) | |
| .attr('fill-opacity', .6) | |
| .lower() | |
| svg.selectAll('path') | |
| .lower() | |
| div.transition() | |
| .duration(500) | |
| .style('opacity', 0); | |
| } | |
| var leftCountAxis = d3.axisLeft(y_count); | |
| var leftCountxpopulationAxis = d3.axisLeft(y_countxpopulation); | |
| var bottomContinentAxis = d3.axisBottom(x_continent); | |
| var bottomRangesAxis = d3.axisBottom(x_ranges); | |
| var bottomPovertyAxis = d3.axisBottom(x_poverty); | |
| var map; | |
| var data; | |
| var scrollFunctions; | |
| var gs; | |
| //=============================================// | |
| //load all the data before using d3.functions() | |
| //=============================================// | |
| d3.queue() | |
| .defer(d3.json, 'https://raw.githubusercontent.com/beemyfriend/beemyfriend.github.io/master/Projects/worldmap.countries.geo.json') | |
| .defer(d3.csv, 'https://raw.githubusercontent.com/beemyfriend/beemyfriend.github.io/master/Projects/laptops.csv') | |
| .await(ready) | |
| function ready(error, geojson, csv){ | |
| function findContinent(country){ | |
| var involved = csv.filter(function(x){return x.country == country}); | |
| if(involved.length != 0){ | |
| return involved[0].Continent | |
| } else { | |
| return 'None' | |
| } | |
| } | |
| geojson.features | |
| .map(function(x){return x.properties.continent = findContinent(x.properties.name);}); | |
| //=============================================// | |
| //debugging purposes | |
| //=============================================// | |
| map = geojson; | |
| data = csv; | |
| //=============================================// | |
| //add dynamic domains to scales | |
| //=============================================// | |
| x_poverty.domain(d3.extent(csv.map(function(d){return +d.pop_below_poverty}))); | |
| y_count.domain(d3.extent(csv.map(function(d){return +d.count}))); | |
| y_countxpopulation.domain(d3.extent(csv.map(function(d){return +d.countxpopulation}))) | |
| r_count.domain([0, d3.max(csv.map(function(d){return +d.count}))]); | |
| r_countxpop.domain([0, d3.max(csv.map(function(d){return +d.countxpopulation}))]) | |
| //=============================================// | |
| //functions used throughout the scroll story. Contains transitions, | |
| //colors and positions of the svg elements | |
| //=============================================// | |
| function continentxgeolocated(){ | |
| svg.selectAll('g') | |
| .remove(); | |
| svg.selectAll('path') | |
| .transition().duration(animationDuration) | |
| .attr('fill', function(d){return clr(d.properties.continent)}) | |
| .attr('stroke', 'black'); | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('r', 0); | |
| } | |
| function countxgeolocated(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('path') | |
| .transition().duration(animationDuration) | |
| .attr('fill', function(d){return clrBinary(d.properties.continent)}) | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('r', function(d){return r_count(+d.count)}) | |
| } | |
| function countxpopulationxgeolocated(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('cx', function(d){return projection([d.longitude, d.latitude])[0]; }) | |
| .attr('cy', function(d){return projection([d.longitude, d.latitude])[1]; }) | |
| .attr('r', function(d){return r_countxpop(+d.countxpopulation)}) | |
| svg.selectAll('path') | |
| .transition().duration(animationDuration) | |
| .attr('fill', function(d){return clrBinary(d.properties.continent)}) | |
| .attr('stroke', 'black'); | |
| } | |
| function countxcontinent(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('path') | |
| .transition().duration(animationDuration) | |
| .attr('fill', 'white') | |
| .attr('stroke', 'white'); | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('cx', function(d){return x_continent(d.Continent)}) | |
| .attr('cy', function(d){return y_count(+d.count)}) | |
| .attr('r', function(d){return r_countxpop(+d.countxpopulation)}); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom/2) + ')') | |
| .call(bottomContinentAxis); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + (margin.left )+ ',' + 0 + ')') | |
| .call(leftCountAxis) | |
| svg.append('g') | |
| .attr('transform', 'translate(' + margin.left + ',50)') | |
| .append('text') | |
| .attr('font-size', 20) | |
| .text('Computers Given Sorted by Continent') | |
| } | |
| function contxpopulationxcontinent(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('cx', function(d){return x_continent(d.Continent)}) | |
| .attr('cy', function(d){return y_countxpopulation(+d.countxpopulation)}) | |
| .attr('r', function(d){return r_countxpop(+d.countxpopulation)}); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom/2) + ')') | |
| .call(bottomContinentAxis); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + (margin.left ) + ',' + 0 + ')') | |
| .call(leftCountxpopulationAxis) | |
| svg.append('g') | |
| .attr('transform', 'translate(' +( margin.left )+ ',50)') | |
| .append('text') | |
| .attr('font-size', 20) | |
| .text('Computers Given (%population) Sorted by Continent') | |
| } | |
| function countxpopulationxpoverty(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('cx', function(d){return x_poverty(d.pop_below_poverty == 'NA' ? 0 : +d.pop_below_poverty)}) | |
| .attr('cy', function(d){return y_countxpopulation(+d.countxpopulation)}) | |
| .attr('r', function(d){return r_countxpop(+d.countxpopulation)}); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom/2) + ')') | |
| .call(bottomPovertyAxis); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + (margin.left ) + ',' + 0 + ')') | |
| .call(leftCountxpopulationAxis) | |
| svg.append('g') | |
| .attr('transform', 'translate(' + margin.left + ',50)') | |
| .append('text') | |
| .attr('font-size', 20) | |
| .text('Computers Given (%population) Sorted by Poverty Rate') | |
| } | |
| function countxpopulationxliteracy(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('cx', function(d){return x_ranges(d.literacyrange)}) | |
| .attr('cy', function(d){return y_countxpopulation(+d.countxpopulation)}) | |
| .attr('r', function(d){return r_countxpop(+d.countxpopulation)}); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom/2) + ')') | |
| .call(bottomRangesAxis); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + (margin.left ) + ',' + 0 + ')') | |
| .call(leftCountxpopulationAxis) | |
| svg.append('g') | |
| .attr('transform', 'translate(' + margin.left + ',50)') | |
| .append('text') | |
| .attr('font-size', 20) | |
| .text('Computers Given (%population) Sorted by Literacy Rate') | |
| } | |
| function countxpopulationxunemployment(){ | |
| svg.selectAll('g') | |
| .remove() | |
| svg.selectAll('circle') | |
| .transition().duration(animationDuration) | |
| .attr('cx', function(d){return x_ranges(d.unemploymentrange)}) | |
| .attr('cy', function(d){return y_countxpopulation(+d.countxpopulation)}) | |
| .attr('r', function(d){return r_countxpop(+d.countxpopulation)}); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom/2) + ')') | |
| .call(bottomRangesAxis); | |
| svg.append('g') | |
| .attr('transform', 'translate(' + (margin.left ) +',' + 0 + ')') | |
| .call(leftCountxpopulationAxis) | |
| svg.append('g') | |
| .attr('transform', 'translate(' + margin.left + ',50)') | |
| .append('text') | |
| .attr('font-size', 20) | |
| .text('Computers Given (%population) Sorted by Unemployment Rate') | |
| } | |
| //=============================================// | |
| //d3.transitions() don't work if the svg elements don't already | |
| //exist. The below svg calls create a transparent map and circles. | |
| //The page can be loaded from anywhere and the d3.transition() | |
| //animation will work. | |
| //=============================================// | |
| svg.selectAll('path') | |
| .data(geojson.features) | |
| .enter().append('path') | |
| .attr('d', path) | |
| .attr('fill', 'white') | |
| .attr('fill-opacity', 1) | |
| .attr('stroke', 'white') | |
| .attr('stroke-width', 1); | |
| svg.selectAll('circle') | |
| .data(csv).enter() | |
| .append('circle') | |
| .attr('cx', function(d){return projection([d.longitude, d.latitude])[0]; }) | |
| .attr('cy', function(d){return projection([d.longitude, d.latitude])[1]; }) | |
| .attr('fill', function(d){return clr(d.Continent)}) | |
| .attr('fill-opacity', .65) | |
| .attr('r', 0) | |
| .attr('stroke', 'black') | |
| .attr('id', function(d){return d.Country_code}) | |
| .on('mouseover', handle_mouse_over) | |
| .on('mouseout', handle_mouse_out); | |
| //=============================================// | |
| // An array of functions in the order of the scroll-story | |
| //=============================================// | |
| scrollFunctions = [continentxgeolocated, | |
| countxgeolocated, | |
| countxpopulationxgeolocated, | |
| countxcontinent, | |
| contxpopulationxcontinent, | |
| countxpopulationxpoverty, | |
| countxpopulationxliteracy, | |
| countxpopulationxunemployment | |
| ] | |
| //=============================================// | |
| //scroll-story logic | |
| //=============================================// | |
| gs = d3.graphScroll() | |
| .container(d3.select('#container')) | |
| .graph(d3.selectAll('#graph')) | |
| .sections(d3.selectAll('#sections > div')) | |
| .on('active', function(i){ | |
| var to_display = scrollFunctions; | |
| to_display[i]() | |
| }) | |
| } | |
| </script> | |
| </body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment