Public
Edited
Feb 21, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
owid_co2_data@7.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
cleanedData = {
let data = owid_co2_data7.map(a => {return {...a}}) // works for single layer objects
// Makes array of all country codes
let codeOnly = data.map( e => e.iso_code )
let codeList = codeOnly.filter( (value, index, array) => {
return array.indexOf(value) === index;
})
// processes each country
let isBlank = (value) => ( !value || value.length === 0 )
let cleanedData = []
let singleCountryData, lookingForNext
let keys = Object.keys(data[0])
let last = null, next = null
for(let i=0; i<codeList.length; i++){
singleCountryData = data.filter( (value, index, array) => {
return value.iso_code === codeList[i];
})
for(let k=4; k<keys.length; k++){ // controls which properties are cleaned
// replaces all blank values with null
for(let j=0; j<singleCountryData.length; j++){
if( isBlank(singleCountryData[j][keys[k]]) ){ singleCountryData[j][keys[k]] = null}
}

// linear interpolation between values
last = null; next = 0 // indexes for linear interpolation
for(let j=0; j<singleCountryData.length; j++){
if( (singleCountryData[j][keys[k]]) == null ){ //if blank
if( last === null || next === null ){} // if either before or after data
else if(next < j) { // in the middle of the data and we need to find the next index
next = singleCountryData.findIndex( (element,index) => element[keys[k]] != null && j<index )
if( next == -1){ // if we are past the data
next = null
} else { // linear interpolation from existing last and next indexes, scaleLinear(domain, range)
singleCountryData[j][keys[k]] = d3.scaleLinear([last,next] , [+singleCountryData[last][keys[k]],+singleCountryData[next][keys[k]]])(j)
}
} else { // linear interpolation from existing last and next indexes
singleCountryData[j][keys[k]] = d3.scaleLinear([last,next] , [+singleCountryData[last][keys[k]],+singleCountryData[next][keys[k]]])(j)
}
} else { // if value, sets the last index
last = j
singleCountryData[j][keys[k]] = +singleCountryData[j][keys[k]]
}
}
}
// calculates co2, co2/capita, co2/gdp
for( let j=0; j<singleCountryData.length; j++){
if(singleCountryData[j].co2 != null){ singleCountryData[j].co2 = singleCountryData[j].co2 * 1e6 * 1000} // converts between millions of tonnes -> tonnes
if(singleCountryData[j].population != null && singleCountryData[j].gdp != null){
singleCountryData[j].gdp_per_capita = singleCountryData[j].gdp / singleCountryData[j].population
}
if(singleCountryData[j].population != null && singleCountryData[j].co2 != null){
singleCountryData[j].co2_per_capita = singleCountryData[j].co2 / singleCountryData[j].population
}
if(singleCountryData[j].co2 != null && singleCountryData[j].gdp != null){
singleCountryData[j].co2_per_gdp = singleCountryData[j].co2 / singleCountryData[j].gdp
}
}
}
return data
}
Insert cell
Insert cell
Insert cell
groupedData = {
let data = []
const startDate = d3.min( cleanedData.map( e => e.year) )
const endDate = d3.max( cleanedData.map( e => e.year) )
let population, gdp, co2
let obj
let c = ['L','LM','UM','H']

for(let i=0; i<c.length; i++){
for(let j=startDate; j<=endDate; j++){
data.push({n:0, class:c[i], year:j, population:0,co2:0, gdp:null, co2_per_gdp:null, co2_per_capita:null, co2_per_gdp:null, gdp_per_capita:null})
}
}
for(let i=0; i<cleanedData.length; i++){
if( startDate <= cleanedData[i].year ){
obj = data.find( e => e.year == cleanedData[i].year && e.class==cleanedData[i].class)
obj.n += 1
if( cleanedData[i].population != null){ obj.population += cleanedData[i].population }
if( cleanedData[i].co2 != null ){ obj.co2 += cleanedData[i].co2 }
if( cleanedData[i].gdp != null ){ obj.gdp += cleanedData[i].gdp }
}
}
for(let i=0; i<data.length; i++){
if( data[i].co2 == 0){ data[i].co2 = null }
}
for(let i=data.length-1; 0<=i; i--){ // delete all null data points
if( data[i].co2==null && data[i].gdp==null){ data.splice(i,1) }
}
for(let i=0; i<data.length; i++){
if( data[i].co2 != null && data[i].gdp != null){ data[i].co2_per_gdp = data[i].co2 / data[i].gdp }
if( data[i].co2 != null && data[i].population != null){ data[i].co2_per_capita = data[i].co2 / data[i].population }
if( data[i].population != null && data[i].gdp != null){ data[i].gdp_per_capita = data[i].gdp / data[i].population }
}
return data
}
Insert cell
Insert cell
Insert cell
kernels = [
({name:'Uniform', function: (x,s) => (-s<=x && x<=s) ? .5/s : 0}),
({name:'Triangular', function: (x,s) => (-s<=x && x<=s) ? (1-Math.abs(x/s))/s : 0}),
({name:'Epanechnikov', function: (x,s) => (-s<=x && x<=s) ? 3/4/s*(1-(x/s)**2) : 0}),
({name:'Quartic', function: (x,s) => (-s<=x && x<=s) ? 15/16/s*(1-(x/s)**2)**2 : 0}),
({name:'Triweight', function: (x,s) => (-s<=x && x<=s) ? 35/32/s*(1-(x/s)**2)**3 : 0}),
({name:'Tricube', function: (x,s) => (-s<=x && x<=s) ? 70/81/s*(1-Math.abs(x/s)**3)**3 : 0}),
({name:'Cosine', function: (x,s) => (-s<=x && x<=s) ? Math.PI/4/s*Math.cos(Math.PI/2*x/s) : 0}),
({name:'Gaussian', function: (x,s) => 1/Math.sqrt(2*Math.PI)/s*Math.exp(-.5*(x/s)**2) }),
]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
smoothedData = {
let data = []
let c = ['L','LM','UM','H']
let weight, weightSum, distance, filteredData, year
let keys = Object.keys(groupedData[0])
for( let i=0; i<groupedData.length; i++){ // for each data point
weightSum = 0
year = groupedData[i].year
data.push({n:groupedData[i].n, class:groupedData[i].class, year:groupedData[i].year })
weightSum = new Object

// set values to 0 so they can be added to
for(let k=3; k<keys.length; k++){
if( groupedData[i][keys[k]] == null ){ data[i][keys[k]] = null }else{ data[i][keys[k]] = 0 }
weightSum[keys[k]] = 0
}

// add values and weights if not null
filteredData = groupedData.filter( e => e.class == groupedData[i].class)
for( let j=0; j<filteredData.length; j++){ // sum each datapoint in class
distance = filteredData[j].year - year
weight = kernels.find(e => e.name == select).function(distance ,Math.max(.01,support))
for(let k=3; k<keys.length; k++){
if( data[i][keys[k]] != null && filteredData[j][keys[k]] != null ){
weightSum[keys[k]] += weight
data[i][keys[k]] += weight * +filteredData[j][keys[k]]
}
}
}

// divide sum by weightSum to creatte an average
for(let k=3; k<keys.length; k++){
if(data[i][keys[k]] != null) { data[i][keys[k]] = data[i][keys[k]] / weightSum[keys[k]] }
}
}
return data
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more