├── data ├── example.json ├── graph_1.csv ├── graph_2.csv ├── years_education.csv └── cleaning │ └── cleaning_education.ipynb ├── .DS_Store ├── src ├── .DS_Store ├── utils.js ├── stylesheets │ └── main.css ├── app_map.js └── app.js ├── README.md ├── webpack.config.js ├── package.json └── index.html /data/example.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "example": "test" 4 | } 5 | ] -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccsuehara/world-adult-education-dynamic-viz/master/.DS_Store -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccsuehara/world-adult-education-dynamic-viz/master/src/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Understanding the skills we need in life (the dynamic viz of the adult version) 2 | 3 | .Promise() -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | // example of how to export functions 2 | // this particular util only doubles a value so it shouldn't be too useful 3 | export function myExampleUtil(x) { 4 | return x * 2; 5 | } 6 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: { 5 | app: './src/app.js', 6 | }, 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.css$/, 11 | use: ['style-loader', 'css-loader'], 12 | }, 13 | { 14 | test: /\.js$/, 15 | loader: 'babel-loader', 16 | exclude: [/node_modules/], 17 | query: { 18 | presets: ['es2017'], 19 | }, 20 | }, 21 | ], 22 | }, 23 | output: { 24 | filename: 'bundle.js', 25 | path: path.join(__dirname, './'), 26 | }, 27 | plugins: [], 28 | mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', // eslint-disable-line 29 | }; 30 | -------------------------------------------------------------------------------- /data/graph_1.csv: -------------------------------------------------------------------------------- 1 | year,No Level,Primary,Secondary,Tertiary 2 | 1950,601404.6029000004,411145.0305000002,111224.91219999999,26509.9941 3 | 1955,597711.4919999995,472183.21579999995,141252.6825999999,33037.329399999995 4 | 1960,615450.5538000001,522665.8717999999,170746.65539999984,39684.6914 5 | 1965,613334.8772000001,571763.1008000004,227471.11539999998,50455.55419999997 6 | 1970,620870.5078,616474.426,283488.3938,64562.28749999999 7 | 1975,633171.9094999996,651144.9759000002,367912.1017,94640.09340000001 8 | 1980,653703.5587000002,694411.3613999999,484297.32199999987,128100.56079999995 9 | 1985,681588.7088000003,724522.5595999997,604541.3413999996,180632.5423999999 10 | 1990,720936.4739999999,746442.0453000001,745869.3807,248407.96140000003 11 | 1995,700186.6664000003,792829.8296999998,953404.0825999994,312037.6546 12 | 2000,669901.2640000003,830149.0882000002,1151187.5763999997,406548.33299999987 13 | 2005,630303.2713000001,856540.8007999997,1381347.1460999993,472068.23339999997 14 | 2010,603669.9564000003,854202.0380999997,1628867.1789000002,558951.3775999999 15 | -------------------------------------------------------------------------------- /data/graph_2.csv: -------------------------------------------------------------------------------- 1 | year,No Level,Primary,Secondary,Tertiary 2 | 1950,52.283116232862646,35.74289806652784,9.669339051449649,2.3046466491598614 3 | 1955,48.040414135296615,37.95121482249859,11.353031455225238,2.6553395869795517 4 | 1960,45.638023835424654,38.7576830793184,12.661520703573103,2.942772381683852 5 | 1965,41.92238853980603,39.080893253435036,15.548002952182111,3.4487152545768196 6 | 1970,39.16186609112314,38.884579982966294,17.88123993153083,4.072313994379736 7 | 1975,36.24609975458316,37.274972873961765,21.061229247625928,5.41769812382915 8 | 1980,33.34349858532108,35.419884041196944,24.702584001676755,6.534033371805223 9 | 1985,31.104519104494504,33.063819141593505,27.588437807514648,8.243223946397347 10 | 1990,29.286647467854703,30.32276188579347,30.299498495935456,10.091092150416376 11 | 1995,25.383261488152126,28.741773942015474,34.56293342021796,11.312031149614436 12 | 2000,21.90804741366951,27.148695728838195,37.647745065007776,13.295511792484529 13 | 2005,18.869889612858728,25.642942208866828,41.354486563561046,14.132681614713407 14 | 2010,16.558452999649564,23.430459227146834,44.67924954445757,15.331838228746033 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scaffold", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "", 7 | "license": "ISC", 8 | "engines": { 9 | "node": ">=9.0.0" 10 | }, 11 | "devDependencies": { 12 | "babel-core": "^6.21.0", 13 | "babel-eslint": "^7.1.1", 14 | "babel-loader": "^7.1.4", 15 | "babel-preset-es2015": "^6.24.1", 16 | "babel-preset-es2017": "^6.22.0", 17 | "babel-preset-stage-2": "^6.22.0", 18 | "css-loader": "0.26.1", 19 | "eslint": "^6.5.1", 20 | "eslint-config-prettier": "^6.3.0", 21 | "eslint-config-uber-es2015": "^3.1.2", 22 | "eslint-plugin-babel": "^5.3.0", 23 | "eslint-plugin-prettier": "^3.1.1", 24 | "prettier": "^1.18.2", 25 | "style-loader": "0.13.1", 26 | "webpack": "4", 27 | "webpack-cli": "^3.0.8", 28 | "webpack-command": "^0.2.1", 29 | "webpack-dev-server": "^3.1.4" 30 | }, 31 | "dependencies": { 32 | "d3-scale": "^3.2.1", 33 | "domready": "^1.0.8" 34 | }, 35 | "scripts": { 36 | "start": "webpack-dev-server", 37 | "build": "NODE_ENV=production webpack", 38 | "lint": "eslint ." 39 | }, 40 | "babel": { 41 | "presets": [ 42 | "es2015", 43 | "stage-2" 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/stylesheets/main.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,300,700); 2 | *{ 3 | font-family: 'Open Sans'; 4 | line-height: 170%; 5 | color: #444; 6 | } 7 | /*body, p, h1, h2{ 8 | margin: 0; 9 | padding: 0; 10 | }*/ 11 | 12 | h2{ 13 | margin-top: 20px; 14 | font-size: 20px; 15 | } 16 | 17 | h1{ 18 | font-size: 50px; 19 | } 20 | 21 | h3{ 22 | font-size: 30px; 23 | } 24 | 25 | mark { 26 | background-color: white; 27 | padding: 0px 1px; 28 | /*opacity: 0.5;*/ 29 | } 30 | 31 | .wrapper{ 32 | padding: 100px; 33 | margin: 0 0 50px 0; 34 | text-align: center; 35 | height: 45vh; 36 | background: url('https://static.themoscowtimes.com/image/article_1360/c5/9d6336449aa84ea6a4bc76a44bdf8705.jpg') no-repeat center center fixed; 37 | background-size: cover; 38 | transition: all 0.4s ease; 39 | } 40 | 41 | .wrapperText { 42 | font: black ; 43 | } 44 | 45 | p, h2, h4,#area_chart, #area_chart2, #mapGadgets, #AllButtons { 46 | margin: 0 10% 30px 20%; 47 | width: 50%; 48 | max-width: 600px; 49 | padding-left: 100px; 50 | transition: all 0.4s ease; 51 | } 52 | 53 | #map { 54 | margin: 10 10% 30px 25%; 55 | width: 50%; 56 | max-width: 600px; 57 | padding-left: 150px; 58 | transition: all 0.4s ease; 59 | } 60 | 61 | 62 | .introduction{ 63 | margin-bottom: 20px; 64 | } 65 | 66 | 67 | a { 68 | cursor: pointer; 69 | } 70 | 71 | 72 | .buble_legend{ 73 | opacity: 1; 74 | transition: opacity 0.3s; 75 | } 76 | 77 | .buble_legend text, 78 | .axis text { 79 | font-size: 13px; 80 | fill: #333; 81 | } 82 | 83 | .axis path, 84 | .axis line { 85 | fill: none; 86 | stroke-width:1px; 87 | stroke: #e7e7e7; 88 | } 89 | 90 | circle { 91 | stroke: #fff; 92 | } 93 | 94 | .bubble { 95 | opacity: 1; 96 | transition: opacity 0.3s; 97 | } 98 | 99 | .bubble text { 100 | opacity: 0; 101 | pointer-events: none; 102 | font-size: 12px; 103 | } 104 | 105 | .bubble:hover text { 106 | opacity: 1; 107 | } 108 | 109 | .bubble:hover circle { 110 | fill-opacity: 1; 111 | } 112 | 113 | .tooltip { 114 | position: absolute; 115 | font-size: 12px ; 116 | width: auto; 117 | height: auto; 118 | pointer-events: none; 119 | background-color: white; 120 | } 121 | 122 | .plot { 123 | display: inline-block; 124 | } 125 | 126 | #foot { 127 | 128 | background-color: #404040; 129 | border-top: 0.5px solid #e4e4e4; 130 | width:100%; 131 | bottom:100; 132 | float:left; 133 | padding-left:0px; 134 | } 135 | 136 | #foot p { 137 | font-size: 12px ; 138 | color: #FCFCFC; 139 | } 140 | 141 | #foot a { 142 | font-size: 12px ; 143 | color: #FCFCFC; 144 | } 145 | 146 | 147 | -------------------------------------------------------------------------------- /src/app_map.js: -------------------------------------------------------------------------------- 1 | //Disclaimer: this code relied in these examples: 2 | //https://www.d3-graph-gallery.com/graph/choropleth_basic.html 3 | //http://duspviz.mit.edu/d3-workshop/mapping-data-with-d3/ 4 | //http://bl.ocks.org/palewire/d2906de347a160f38bc0b7ca57721328 5 | //https://blockbuilder.org/micahstubbs/d393bcfde0228430c00b 6 | 7 | var width = 1000, 8 | height = 450; 9 | 10 | var projection = d3.geoNaturalEarth() 11 | .scale(width / 2 / Math.PI) 12 | .translate([width / 2, height / 2]) 13 | 14 | var path = d3.geoPath() 15 | .projection(projection); 16 | 17 | var svg = d3.select("#map").append("svg") 18 | .attr("width", width) 19 | .attr("height", height); 20 | 21 | var colorScheme = d3.schemeReds[6]; 22 | colorScheme.unshift("black") 23 | var colorNoEducation = d3.scaleThreshold() 24 | .domain([0, 5, 10, 20, 40, 60]) 25 | .range(colorScheme); 26 | var colorNoSecondary = d3.scaleThreshold() 27 | .domain([0, 40, 50, 60, 70, 80]) 28 | .range(colorScheme); 29 | var colorGenderGap = d3.scaleThreshold() 30 | .domain([-30, 3, 6, 9, 15, 20]) 31 | .range(colorScheme) 32 | 33 | // Legend 34 | var g = svg.append("g") 35 | .attr("class", "legendThreshold") 36 | .attr("transform", "translate(20,20)"); 37 | g.append("text") 38 | .attr("class", "caption") 39 | .attr("x", -1) 40 | .attr("y", -7) 41 | .text("Adult population with no education attainment at all") 42 | .style("font", "16px avenir"); 43 | var labels = ['No data', '0-5%', '5-10%', '10-20%', '20-40%', '40-60%', '>60%']; 44 | var legend = d3.legendColor() 45 | .labels(function (d) { 46 | return labels[d.i]; 47 | }) 48 | .shapePadding(4) 49 | .scale(colorNoEducation); 50 | svg.select(".legendThreshold") 51 | .call(legend) 52 | .style("font", "16px avenir"); 53 | 54 | d3.selectAll(".label") 55 | .style("font", "16px avenir"); 56 | 57 | var noEducationLabels = { 58 | 0: "No data", 59 | 1: "0-5%", 60 | 2: "5-10%", 61 | 3: "10-20%", 62 | 4: "20-40%", 63 | 5: "40-60%", 64 | 6: ">60%" 65 | } 66 | 67 | var secondaryLabels = { 68 | 0: "No data", 69 | 1: "0-40%", 70 | 2: "40-50%", 71 | 3: "50-60%", 72 | 4: "60-70%", 73 | 5: "70-80%", 74 | 6: ">80%" 75 | } 76 | 77 | var genderGapLabels = { 78 | 0: "No data", 79 | 1: "< 3 pp", 80 | 2: "3-6 pp", 81 | 3: "6-9 pp", 82 | 4: "9-15 pp", 83 | 5: "15-20 pp", 84 | 6: ">20 pp" 85 | } 86 | 87 | var yearNow = 1950; 88 | 89 | var indicator = "no_education"; 90 | 91 | var indicators_dict = { 92 | "no_education": "Adult population with no educational attainment at all", 93 | "secondary_incomplete": "Adult population with incomplete secondary education", 94 | "gap_female-male_no-education": "Gap female-male - Adult population with no educational attainment (difference in percentage points)", 95 | "gap_female-male_secondary-incomplete": "Gap female-male - Adult population with no secondary education (difference in percentage points)" 96 | } 97 | 98 | var educationByIdYearIndicator = {}; 99 | 100 | d3.queue() 101 | .defer(d3.json, "data/raw/world-110m.geojson") 102 | .defer(d3.csv, "data/clean/data_by_year-country_indicators.csv") 103 | .await(ready); 104 | 105 | // update when timeslide changes 106 | d3.select("#timeslide").on("input", function() { 107 | update(+this.value); 108 | }); 109 | 110 | //update when dropdown menu changes 111 | d3.select("#indicatorList").on("change", function() { 112 | updateFromDropdown(this.value); 113 | }) 114 | 115 | // update the fill of each SVG of class "country" with value 116 | function update(value) { 117 | document.getElementById("range").innerHTML=value; 118 | yearNow = value; 119 | d3.selectAll(".country") 120 | .attr("year", value) 121 | .attr("fill", countryYearMatch) 122 | .attr("percentage", percentage); 123 | } 124 | 125 | function updateFromDropdown(value) { 126 | indicator = value; 127 | d3.selectAll(".country") 128 | .attr("indicator", value) 129 | .attr("fill", countryYearMatch) 130 | .attr("percentage", percentage); 131 | d3.selectAll(".caption") 132 | .text(indicators_dict[value]); 133 | d3.selectAll(".label") 134 | .text(function(d, i) { 135 | if (indicator == "no_education") { 136 | return noEducationLabels[i]; 137 | } else if (indicator == "secondary_incomplete") { 138 | return secondaryLabels[i]; 139 | } else if (indicator == "gap_female-male_no-education") { 140 | return genderGapLabels[i]; 141 | } else { 142 | return genderGapLabels[i] 143 | } 144 | }); 145 | } 146 | 147 | function percentage(data, value) { 148 | idYear = data.id.concat(yearNow).concat(indicator); 149 | return educationByIdYearIndicator[idYear]; 150 | } 151 | 152 | function countryYearMatch(data, value) { 153 | idYear = data.id.concat(yearNow).concat(indicator); 154 | perc = educationByIdYearIndicator[idYear]; 155 | if (indicator == "no_education") { 156 | return colorNoEducation(perc); 157 | } else if (indicator == "secondary_incomplete") { 158 | return colorNoSecondary(perc); 159 | } else if (indicator == "gap_female-male_no-education") { 160 | return colorGenderGap(perc); 161 | } else { 162 | return colorGenderGap(perc); 163 | } 164 | } 165 | 166 | function ready(error, world_map, education) { 167 | if (error) throw error; 168 | 169 | education.forEach(function(d) { 170 | idYearIndicator = d.id.concat(d.year).concat(d.indicator); 171 | educationByIdYearIndicator[idYearIndicator] = +d.percentage; 172 | }); 173 | 174 | svg.append("g") 175 | .attr("transform", "translate(0,20)") 176 | .selectAll("path") 177 | .data(world_map.features) 178 | .enter().append("path") 179 | .attr("d", path) 180 | .attr("fill", function(d) { 181 | idYearIndicator = d.id.concat(yearNow).concat(indicator); 182 | if (idYearIndicator in educationByIdYearIndicator) { 183 | return colorNoEducation(educationByIdYearIndicator[idYearIndicator]); 184 | } else { 185 | return "black"; 186 | } 187 | }) 188 | .attr("stroke", "black") 189 | .attr("class", "country") 190 | .attr("year", yearNow) 191 | .attr("country_code", function(d) { 192 | return d.id; 193 | }) 194 | .attr("indicator", indicator) 195 | .attr("percentage", function(d) { 196 | idYearIndicator = d.id.concat(yearNow).concat(indicator); 197 | return educationByIdYearIndicator[idYearIndicator]; 198 | }); 199 | } 200 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Understanding the skills 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |
21 |
22 |

23 | Before skills, comes education 24 |

25 |

26 | A brief journey into the evolution of adult education around the world 27 |

28 |

29 | by Carla Solis Uehara and Luis Eduardo San Martin 30 |

31 |
32 |
33 | 34 |
35 |

The spotlight of education has usually been put on children's education. Nevertheless, the ones that are currently part of the workforce and delivering the productive needs of the economy are the current adult population. How well suited and prepared is this workforce?

36 | 37 |

Education is the pilar for building the skills we will need in life. Although we really don't know yet what the future demands for skills will be, the basic set of skills will always come first. The world is currently in an education crisis, where going to school is not the same as learning. This is true for children who are curently in the school, but moreso, for adults who are part of the workforce and have, supposedly, consolidated their skills by then. This project aims to overview the education trends that have been achieved by the countries around the world, from 1950 to 2010. We will look at the evolution and the major gaps that are still missing. For this purpose, adult population is hereafter defined as population aged 25 or more. All the data we used come from the Barro-Lee Educational Attainment Dataset. 38 |

39 | 40 |

Education levels in adult population

41 |

In 1950, more than 50% of the world's adult population did not even start primary education, and less than 15% of them had an education level greater than primary. 60 years after, the panorama has changed: More than 60% of the world's adult population has at least started secondary. But is this enough? Tertiary education (also known as higher education) has increased only to mean a little more than 10% of the total population. More important, as we will look afterwards, is that the distribution of attainment is different depending on the place.

42 | 43 |
44 | 45 |
46 | 47 |

There have been many significative changes like the shift in demographic trends: Adult population has almost tripled from 1950 to 2010: This means going from 1.3 billion people to almost 4 bilion. Proportionately, this also means much more educated people than before. Humanity had never seen this size of educated people ever. Does this necessarily mean that there will be enough accumulated human capital to solve the world's problems? Does this mean more agency and rights for more people?

48 | 49 |
50 | 51 |
52 | 53 |

The evolution of countries and regions

54 |

All countries have univocally augmented their mean year of education. The biggest changes happened since the decade of 1980, especially in countries with large populations such as China and Russia. Regarding regions, East Asia and the Pacific, and Central Europe and Central Asia have had the biggest improvements. Countries from Sub-Saharan Africa, on the other hand, have only had modest increases compared to their initial situations, with the notable exception of Botswana.

55 | 56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 |
67 | 68 |
69 |
70 | 71 |

Remaining gaps

72 |

Despite this progress, there is still much to be done to close the remaining gaps in educational attainment. As noted previously, the advancement in education during the period 1960-2010 for countries of Sub-Saharan Africa has been slim. Even in 2010, there is a cluster of countries in the Sahel region with more than 60% of the population with no educational attainments. In terms of secondary education completion, the gap is universal access is largely significant: most countries still have more than 60% of the population with incomplete secondary education.

73 |

Education levels by gender also exhibit a pressing gap that has largely remained constant in Sub-Saharan Africa, North Africa and the Middle East, and South Asia; where most countries have a female-male gap of more than 15 percentage points (pp) in population with no education by gender. Importantly, the gender gap in secondary education completion has increased almost universally from 1960-2010, even in countries considered advanced economies like Canada or France. This stylized fact brings to light a complex issue countries face when seeking to achieve increased educational attainments: universal access to improved education levels usually benefits males first.

74 | 75 |
76 |
77 |
78 | 1950 79 |
80 | 88 |
89 |
90 | 91 |
92 | 93 |
94 | 95 |
96 | 97 | 98 | 99 |