Built with blockbuilder.org
forked from ElaineYu's block: Metis Health & Wealth of Nations Country Comparison
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
.lineA {
fill: none;
stroke: blue;
stroke-width: 2px;
}
.lineB {
fill: none;
stroke: hotpink;
stroke-width: 2px;
}
</style>
</head>
<body>
<select id="dropdown-category"></select>
<select id="dropdown-countriesA"></select>
<select id="dropdown-countriesB"></select>
<script>
// HOMEWORK ASSIGNMENT:
// 1. pick: pop, $, or death
// 2. pick a country
// 3. create line chart
// 4. create dropdown of countries
// 5. create ability to pick different series
// 6. create ability to compare two countries
// General Instructions and Breakdown
// 1. Determine the range. The range is your screen space display.
// For x-scale, .range([0 , width])
// For y-scale, .range([height, 0])
// 2. Determine the domain. The domain is your data (e.g. income per capita).
// Requires the extent of your data (min and max values). For example
// X-axis
// var xExtent = d3.extent(data, d => d.income);
// .domain([300, xExtent[1]]) // income per capita data
// Y-axis
// var yExtent = d3.extent(data, d => d.lifeExpectancy);
// .domain([0, yExtent[1]]) // life expectancy data
// 3. Determine the scale, which requires domain and range
// Scales can also be used with virtually any type of data, such as named categorical data or discrete data that requires sensible breaks.
// For continuous quantitative data, you typically want a linear scale.
// 4. Determine the axes, which requires scale
// 5. Draw svg. Append the svg to the body
// 6. Append axes
// GLOBALS
// Margin conventions: https://bl.ocks.org/mbostock/3019563
// Define the margin object with properties for the four sides
var margin = {top: 20, right: 40, bottom: 200, 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 dropDownSelectForCategory = 'population';
var dropDownSelectForCountryA = 'Afghanistan';
var dropDownSelectForCountryB = 'Zimbabwe';
// Draw svg/ add svg to canvas
var svg = d3.select("body")
.append("svg") // Append the svg to the body
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
svg.append("text")
.attr("class", "axisText")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Year");
var xAxis = svg.append('g')
.attr("transform", "translate(0," + height + ")") // Move x-axis down translate(tx, ty) / (0, 500 - margin.top - margin.bottom)
// Call axes.x later on update on drawChart
// .call(axes.x)
var yAxis = svg.append('g')
// .call(axes.y)
var appendLine = svg.append("path")
.attr("class", "lineA")
var appendLineB = svg.append("path")
.attr("class", "lineB")
// 1. Determine the range. The range is your screen space display.
var loadRange = function() {
return {
x: [0, width],
y: [height, 0]
}
}
// 2. Determine the domain. The domain is your data (e.g. income per capita).
var loadDomain = function(xValues, yValues) {
return {
x: d3.extent(xValues), // year
y: d3.extent(yValues) // Example: population
}
}
// 3. Determine the scale, which requires domain and range.
var loadScale = function(domain, range) {
return {
x: d3.scaleLinear().domain(domain.x).range(range.x),
y: d3.scaleLinear().domain(domain.y).range(range.y)
}
}
// 4. Determine the axes, which requires scale
var loadAxis = function(scale){
return {
x: d3.axisBottom().scale(scale.x).tickFormat(d3.format("d")),
y: d3.axisLeft().scale(scale.y)
}
}
function getXAxisValueExtent(nationsData) {
var nationYears = nationsData.map(function(nation) {
// Determine Min and Max for each
var incomeMinMax = d3.extent(nation.income, function(i) {return i[0]})
var lifeMinMax = d3.extent(nation.lifeExpectancy, function(i) {return i[0]})
var popMinMax = d3.extent(nation.population, function(i) {return i[0]})
// Merge the arrays
var allMinMax = d3.merge([incomeMinMax, lifeMinMax, popMinMax])
// Find the extent of all the arrays
return d3.extent(allMinMax)
})
var xValuesYearMinMax = d3.extent(d3.merge(nationYears));
return xValuesYearMinMax
// [1800, 2009]
}
var findByYear = function(data, year) {
var resultArry = data.find(function(i) {
return i[0] === year
})
if(resultArry) {
return resultArry[1]
}
}
// 8. Build an object for category
var buildObjectForCountry = function(nation, year, categoryStr) {
if (categoryStr === "population") {
var n = {
country: nation[0].name,
year: year,
category: "population",
value: findByYear(nation[0].population, year)
}
return n
} else if (categoryStr === "lifeExpectancy") {
var n = {
country: nation[0].name,
year: year,
category: "lifeExpectancy",
value: findByYear(nation[0].lifeExpectancy, year)
}
return n
} else if (categoryStr === "income"){
var n = {
country: nation[0].name,
year: year,
category: "income",
value: findByYear(nation[0].income, year)
}
return n
}
}
// 7. Get original data for specified country
function getDataForCountry(nationsData, countryName) {
return nationsData.filter(function(nation) {
if (nation.name === countryName ) {
return nation
}
});
}
function getLineDataForCountryAndCategory(xValuesYearMinMax, nationsData, countryName, categoryStr) {
var data = [];
var originalDataForOneCountry = getDataForCountry(nationsData, countryName);
for(var year=xValuesYearMinMax[0]; year<=xValuesYearMinMax[1]; ++year) {
var newNation = buildObjectForCountry(originalDataForOneCountry, year, categoryStr)
if (newNation.value) {
data.push([newNation.year, newNation.value]);
}
}
return data;
}
function drawLines(svg, scale, lineDataA, lineDataB) {
var line = d3.line()
.x(function(d) { return scale.x(d[0])})
.y(function(d) { return scale.y(d[1])})
appendLine.datum(lineDataA)
.attr("d", line)
appendLineB.datum(lineDataB)
.attr("d", line);
}
function getArrayofCategoryValuesForDomainExtent(xValuesYearMinMax, originalDataForOneCountry, categoryStr) {
var arrayOfYAxisValuesForCountry = [];
for(var year=xValuesYearMinMax[0]; year<=xValuesYearMinMax[1]; ++year) {
var newNation = buildObjectForCountry(originalDataForOneCountry, year, categoryStr)
if (newNation.value) {
arrayOfYAxisValuesForCountry.push(newNation.value);
}
}
return arrayOfYAxisValuesForCountry;
}
function drawChart(xValuesYearMinMax, nationsData, countryNameA, countryNameB, categoryStr) {
var originalDataForOneCountryA = getDataForCountry(nationsData, countryNameA);
var originalDataForOneCountryB = getDataForCountry(nationsData, countryNameB);
var arrayOfYAxisValuesForCountryA = getArrayofCategoryValuesForDomainExtent(xValuesYearMinMax, originalDataForOneCountryA, categoryStr);
var arrayOfYAxisValuesForCountryB = getArrayofCategoryValuesForDomainExtent(xValuesYearMinMax, originalDataForOneCountryB, categoryStr);
// Merge arrays to find the min-max of y values for both countries for a single category
var mergedArrays = d3.merge([arrayOfYAxisValuesForCountryA, arrayOfYAxisValuesForCountryB]);
var domain = loadDomain(xValuesYearMinMax, mergedArrays);
var range = loadRange();
var scale = loadScale(domain, range);
var axes = loadAxis(scale);
xAxis.call(axes.x);
yAxis.call(axes.y)
var lineDataA = getLineDataForCountryAndCategory(xValuesYearMinMax, nationsData, countryNameA, categoryStr);
var lineDataB = getLineDataForCountryAndCategory(xValuesYearMinMax, nationsData, countryNameB, categoryStr);
drawLines(svg, scale, lineDataA, lineDataB)
}
function populateCategoryDropdown() {
var dropdownOptions = [{text: "Population", value: "population"}, {text: "Income", value: "income"}, {text: "Life Expectancy", value: "lifeExpectancy"}]
d3.select("#dropdown-category")
.selectAll("option")
.data(dropdownOptions)
.property("selected", function(d){ return d === 'population'; })
.enter()
.append("option")
.attr("value", function(option) { return option.value; })
.text(function(option) { return option.text; })
}
function populateCountryDropdownA(nationsData) {
var dropdownOfCountries = []
nationsData.forEach(function(nation) {
dropdownOfCountries.push({ text: nation.name, value: nation.name})
// Alphabetize via sort
dropdownOfCountries.sort(function(a, b){
if(a.value < b.value) return -1;
if(a.value > b.value) return 1;
return 0;
})
});
d3.select("#dropdown-countriesA")
.selectAll("option")
.data(dropdownOfCountries)
.property("selected", function(d){ return d === 'Afghanistan'; })
.enter()
.append("option")
.attr("value", function(option) { return option.value; })
.text(function(option) { return option.text; })
}
function populateCountryDropdownB(nationsData) {
var dropdownOfCountriesB = []
nationsData.forEach(function(nation) {
dropdownOfCountriesB.push({ text: nation.name, value: nation.name})
// Reverse alphabetize via sort
dropdownOfCountriesB.sort(function(a, b){
if(a.value > b.value) return -1;
if(a.value < b.value) return 1;
return 0;
})
});
d3.select("#dropdown-countriesB")
.selectAll("option")
.data(dropdownOfCountriesB)
.property("selected", function(d){ return d === 'Zimbabwe'; })
.enter()
.append("option")
.attr("value", function(option) { return option.value; })
.text(function(option) { return option.text; })
}
function updateChartByDropdownCategoryAndCountry(xValuesYearMinMax, nationsData) {
populateCategoryDropdown()
var dropdownCategory = d3.select("#dropdown-category");
var dropdownCountryA = d3.select("#dropdown-countriesA");
var dropdownCountryB = d3.select("#dropdown-countriesB");
// Initialize drawChart
drawChart(xValuesYearMinMax, nationsData, dropDownSelectForCountryA, dropDownSelectForCountryB, dropDownSelectForCategory)
dropdownCategory.on("change", function() {
dropDownSelectForCategory = this.value;
svg.append("text")
.attr("class", "axisText")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text(this.value);
drawChart(xValuesYearMinMax, nationsData, dropDownSelectForCountryA, dropDownSelectForCountryB, dropDownSelectForCategory)
})
dropdownCountryA.on("change", function() {
dropDownSelectForCountryA = this.value;
drawChart(xValuesYearMinMax, nationsData, dropDownSelectForCountryA, dropDownSelectForCountryB, dropDownSelectForCategory)
})
dropdownCountryB.on("change", function() {
dropDownSelectForCountryB = this.value;
drawChart(xValuesYearMinMax, nationsData, dropDownSelectForCountryA, dropDownSelectForCountryB, dropDownSelectForCategory)
})
}
d3.json('nations.json', function(error, nations) {
// console.log('Original data', nations)
var xValuesYearMinMax = getXAxisValueExtent(nations);
populateCountryDropdownA(nations);
populateCountryDropdownB(nations);
updateChartByDropdownCategoryAndCountry(xValuesYearMinMax, nations)
})
</script>
</body>
https://d3js.org/d3.v4.min.js