Public
Edited
Nov 20
Insert cell
Insert cell
Insert cell
rawWorld = FileAttachment("countries-50m.json").json()
Insert cell
rawScholarData = FileAttachment("intl-scholars@2.csv").csv()
Insert cell
Insert cell
cleanedScholarData = rawScholarData
.map((d) => {
let newObj = {};

for (let prop in d) {
if (prop.substring(0, 1) == "2") {
newObj[prop] = parseFloat(d[prop]) ? parseFloat(d[prop]) : 0;
} else {
newObj[prop] = d[prop];
}
}
return newObj;
})
.filter((d) => d.entity == "country")
Insert cell
Insert cell
Insert cell
scholarWorldData = rawWorld.features.map((d) => ({
...d,
scholars: cleanedScholarData.find((e) => e.name == d.properties.SOVEREIGNT)
? cleanedScholarData.find((e) => e.name == d.properties.SOVEREIGNT)
: cleanedScholarData.find((e) => e.name == d.properties.NAME)
}))
Insert cell
Insert cell
scholarWorldData.filter((d) => !d.scholars).map((d) => d.properties.NAME)
Insert cell
Insert cell
margin = ({ top: 20, bottom: 100, sides: 20 })
Insert cell
worldProjection = d3
.geoEqualEarth()
.fitSize([width - margin.sides * 2, width / 2], worldOutline)
Insert cell
Insert cell
worldPath = d3.geoPath().projection(worldProjection)
Insert cell
Insert cell
worldOutline = d3.geoGraticule().outline()
Insert cell
graticules = d3.geoGraticule().step([15, 15])
Insert cell
Insert cell
colorScale = d3
.scaleLinear()
.domain(
d3.extent(scholarWorldData, (d) =>
d.scholars ? d.scholars[year] : 0
)
)
.range([0, 1])
Insert cell
Insert cell
//Inputs.select is a dropdown selection UI!
viewof year = Inputs.select(
Object.keys(scholarWorldData[0].scholars)
.filter((d) => d.substring(0, 1) == "2")
.filter((d) => d.split("-")[1] == "Scholars"),
{ value: "2019/20-Scholars" }
)
Insert cell
Insert cell
//find "Nigeria" in the list of countries, and get the user-selected year scholar count.
scholarWorldData.find((d) => d.properties.NAME == "Nigeria").scholars[year]
Insert cell
Insert cell
{
// create SVG artboard
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", width / 2 + margin.bottom);

// create background color rectangle
svg
.append("rect")
.attr("width", width)
.attr("height", width / 2 + 100)
.attr("fill", "#f9f9fe");

// add group for holding everything
const countryGroup = svg
.append("g")
.attr("transform", "translate(" + margin.sides + " " + margin.top + ")");

// fill world outline for ocean coloring
countryGroup
.append("path")
.attr("d", worldPath(worldOutline))
.attr("fill", "#4488cc");

// draw countries with choropleth coloring
countryGroup
.selectAll(".countries")
.data(scholarWorldData)
.join("path")
.attr("d", worldPath)
.attr("class", "countries")
.attr("fill", (d) => {
if (d.scholars) {
return d3.interpolateViridis(colorScale(d.scholars[year]));
} else {
return "gray";
}
})
.attr("stroke", "white")
.attr("stroke-width", 0.5)

// attach event listeners
.on("mouseover", (e, d) => {
d3.select(e.target).transition().attr("stroke-width", 2);
d3.select("#dataHolder").text(
`${d.properties.NAME} had ${
d.scholars[year]
} international scholars in school year ${year.split("-")[0]}`
);
})
.on("mouseout", (e, d) => {
d3.select(e.target).transition().attr("stroke-width", 0.5);
d3.select("#dataHolder").text("Mouseover a country for details");
});

// add the graticule lines
countryGroup
.append("path")
.attr("d", worldPath(graticules()))
.attr("stroke", "#dcdcdc")
.attr("stroke-width", 0.5)
.attr("fill", "none");

// create area for text to be displayed
svg
.append("text")
.attr("x", width / 2)
.attr("y", width / 2 + margin.bottom / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.attr("id", "dataHolder")
.attr("font-family", "Futura")
.text("Mouseover a country for details");

return svg.node();
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more