Published
Edited
Nov 24, 2020
1 star
Insert cell
Insert cell
aiddata = (await d3.csv(googleSheetCsvUrl, row => ({
yearDate: d3.timeParse('%Y')(row.year),
yearInt: +row.year,
aiddata_id: row.aiddata_id,
aiddata_2_id: row.aiddata_2_id,
donor: row.donor,
recipient: row.recipient,
commitment_amount: +row.commitment_amount_usd_constant,
coalesced_purpose_code: row.coalesced_purpose_code,
coalesced_purpose_name: row.coalesced_purpose_name,
})))
Insert cell
Insert cell
geoJSON = FileAttachment("countries-50m.json").json()
Insert cell
Insert cell
donors = {
let temp = d3.rollup(aiddata, v => d3.sum(v, d => d.commitment_amount), d => d.donor)
let temp2 = Array.from(temp, ([donor, amount]) => ({donor, amount}))
return temp2.sort((a,b) => d3.descending(a.amount, b.amount))
}
Insert cell
recipients = {
let temp = d3.rollup(aiddata, v => d3.sum(v, d => d.commitment_amount), d => d.recipient)
let temp2 = Array.from(temp, ([recipient, amount]) => ({recipient, amount}))
return temp2.sort((a,b) => d3.descending(a.amount, b.amount))
}
Insert cell
netAid = {
let temp = []
for (const country of donors){
let recipient = recipients.find(d => d.recipient == country.donor)
let received = 0
if(recipient){
received = recipient.amount
}
let net = country.amount - received
temp.push({'country' : country.donor, 'donated' : country.amount, 'received' : received, 'net' : net})
}
for (const country of recipients){
if (! donors.find(d => d.donor == country.recipient)){
temp.push({'country' : country.recipient, 'donated' : 0, 'received' : country.amount, 'net' : 0 - country.amount})
}
}
return temp.sort((a,b) => d3.ascending(a.net, b.net))
}
Insert cell
Insert cell
margin = ({top: 50, bottom: 50, left: 150, right: 50})
Insert cell
height = 1000
Insert cell
width = 1000
Insert cell
visHeight = height - margin.top - margin.bottom
Insert cell
visWidth = width - margin.left - margin.right
Insert cell
midPadding = 10
Insert cell
maxDonation = d3.max([d3.max(donors, d => d.amount), d3.max(recipients, d => d.amount)])
Insert cell
countryScale = d3.scaleBand()
.domain(netAid.map(d => d.country))
.range([visHeight, 0])
Insert cell
dollarScale = d3.scalePow()
.domain([0, maxDonation])
.range([0, visWidth /2 - midPadding * 2])
.exponent(1/2)
Insert cell
axis1Scale = d3.scalePow()
.domain([0, maxDonation/1000000000])
.range([0, visWidth /2 - midPadding * 2])
.exponent(1/2)
Insert cell
axis2Scale = d3.scalePow()
.domain([maxDonation/1000000000, 0])
.range([0, visWidth /2 - midPadding * 2])
.exponent(1/2)
Insert cell
yAxis = d3.axisLeft(countryScale)
Insert cell
xAxis1 = d3.axisBottom(axis1Scale)
Insert cell
xAxis2 = d3.axisBottom(axis2Scale)
Insert cell
Insert cell
{
const svg = d3.create('svg')
.attr('width', width)
.attr('height', height);

const g = svg.append("g")
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// draw the donor bars
g.selectAll('rect')
.data(netAid)
.join('rect')
.attr('x', visWidth /2 + midPadding)
.attr('y', d => countryScale(d.country))
.attr('width', d => dollarScale(d.donated))
.attr('height', countryScale.bandwidth())
.attr('fill', '#355265');
//draw the recipient bars
g.selectAll('rect2')
.data(netAid)
.join('rect')
.attr('x', d => visWidth /2 - midPadding - dollarScale(d.received))
.attr('y', d => countryScale(d.country))
.attr('width', d => dollarScale(d.received))
.attr('height', countryScale.bandwidth())
.attr('fill', '#76B064');
// add a group for the y-axis
g.append('g')
.call(yAxis);
// add a group for the x-axis
g.append('g')
// we have to move this group down to the bottom of the vis
.attr('transform', `translate(${visWidth / 2 + midPadding}, ${visHeight})`)
.call(xAxis1)
// add a label for the x-axis
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', visWidth / 4)
.attr('y', 40)
.text("Billion US dollars given");
g.append('g')
// we have to move this group down to the bottom of the vis
.attr('transform', `translate(${midPadding}, ${visHeight})`)
.call(xAxis2)
// add a label for the x-axis
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', visWidth / 4)
.attr('y', 40)
.text("Billion US dollars received");
g.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', visWidth / 2)
.attr('y', -30)
.attr('text-anchor', 'middle')
.text("International Aid Between Countries from 1947 to 2013")
return svg.node();
}
Insert cell
Insert cell
mapMargin = ({top: 10, bottom: 10, left: 10, right: 10})
Insert cell
mHeight = 300
Insert cell
mWidth = 800
Insert cell
mapHeight = mHeight - mapMargin.top - mapMargin.bottom
Insert cell
mapWidth = mWidth - mapMargin.left - mapMargin.right
Insert cell
projection = d3.geoEquirectangular()
.fitSize([mapWidth, mapHeight], geoJSON)
Insert cell
path = d3.geoPath().projection(projection)
Insert cell
maxNet = d3.max(netAid, d => d.net)
Insert cell
minNet = d3.min(netAid, d => d.net)
Insert cell
colorScale = d3.scaleSequential()
.domain([minNet, -minNet])
.interpolator(d3.interpolatePuOr)
.unknown(lightgray)
Insert cell
colorLegend = d3.scaleSequential()
.domain([minNet/1000000000, -minNet/1000000000])
.interpolator(d3.interpolatePuOr)
.unknown(lightgray)
Insert cell
countryToAid = {
let temp = {}
for (const country of netAid) {
temp[country.country] = country
}
temp['United States of America'] = temp['United States']
temp['Czechia'] = temp['Czech Republic']
temp['Slovakia'] = temp['Slovak Republic']
temp['South Korea'] = temp['Korea']
return temp
}
Insert cell
myLegendArgs = ({color : colorLegend, title : 'Net Aid in Billion USD'})
Insert cell
Insert cell
Insert cell
{
const svg = d3.create('svg')
.attr('width', mWidth)
.attr('height', mHeight);

const g = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// draw map

g.selectAll("path")
.data(geoJSON.features)
.join("path")
.attr("d", path)
.attr("fill", d => colorScale((countryToAid[d.properties.SOVEREIGNT] || {net: undefined}).net))
.attr("stroke", "white");

return svg.node();
}
Insert cell
Insert cell
import {legend, swatches} from "@d3/color-legend"
Insert cell
Insert cell
d3 = require('d3@6')
Insert cell
googleSheetCsvUrl = 'https://docs.google.com/spreadsheets/d/1YiuHdfZv_JZ-igOemKJMRaU8dkucfmHxOP6Od3FraW8/gviz/tq?tqx=out:csv'
Insert cell
import {lightgray} from "@nyuvis/fundamental-graphs"
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