Published
Edited
Mar 14, 2022
Insert cell
Insert cell
euScatter = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg
.append("rect")
.attr("x", vaxScale(0))
.attr("y", gdpY.range()[1])
.attr("width", width - margin.left - margin.right)
.attr("height", height - margin.top - margin.bottom)
.attr("fill", "#f9f9f9");

svg
.append("text")
.attr("x", width / 2)
.attr("y", 20)
.attr("opacity", 0.8)
.attr("font-size", 22)
.attr("text-anchor", "middle")
.text(title);

svg
.append("foreignObject")
.attr("font-size", 14)
.attr("opacity", 0.9)
.attr("width", width - margin.right - margin.left)
.attr("height", 100)
.attr("x", vaxScale(0))
.attr("y", 30)
.text(explanation);

svg
.append("path")
.attr("fill", "#ccc")
.attr("fill-opacity", 0.15)
.attr("stroke", "none")
.attr("d", area(intervalData));

svg
.append("path")
.datum(correlationLineData)
.attr("stroke", "#333")
.attr("opacity", 0.4)
.attr("stroke-dasharray", "8,8")
.attr("stroke-width", 1.5)
.attr("d", corrLine);

svg
.append("rect")
.attr("x", 0)
.attr("y", height - margin.bottom)
.attr("width", width)
.attr("height", 200)
.attr("fill", "white");

svg.append("g").call(xGrid);
svg.append("g").call(yGrid);
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);

svg.append("path").datum();

svg
.selectAll(".flags")
.data(combinedData)
.enter()
.append("text")
.attr("font-size", (d) => populationScale(d.population))
.attr("opacity", 0.8)
.attr("x", (d) => vaxScale(d.vaxRate))
.attr("y", (d) => gdpY(d.gdp))
.text((d) => emojiMap.get(d.code));

return svg.node();
}
Insert cell
title = "Why are vaccination rates correlated with economic prosperity?"
Insert cell
explanation = "The chart shows EU countries scattered according to vaccination rates and median equalised net income. Flag size correlates to respective population sizes. The dotted line represents regression, with a grey area indicating the 95% confidence interval. One can notice a significant correlation between the observed variables and the clustering of countries along the 'iron curtain' lines."
Insert cell
Insert cell
correlationLineData = [
[vaxScale.domain()[0], predict(vaxScale.domain()[0])],
[vaxScale.domain()[1], predict(vaxScale.domain()[1])]
]
Insert cell
yAxis = (g) =>
g
.attr("transform", `translate(${margin.left},0)`)
.style("stroke-width", 1)
.call(d3.axisLeft(gdpY))
.call((g) => g.select(".domain").remove())
.call((g) => g.select(".tick:last-of-type text").append("tspan").text(" €"))
.call((g) =>
g
.append("text")
.attr("x", 5)
.attr("y", margin.top + 15)
.attr("fill", "#000")
.attr("opacity", 0.5)
.attr("font-size", 12)
// .attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Median equivalised net income")
)
Insert cell
xAxis = (g) =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(vaxScale).ticks(width / 100))
.call((g) => g.select(".domain").remove())
.call((g) => g.select(".tick:last-of-type text").append("tspan").text("%"))
.call((g) =>
g
.append("text")
.attr("x", width - margin.right - 5)
.attr("y", -10)
.attr("fill", "#000")
.attr("opacity", 0.5)
.attr("font-size", 12)
// .attr("font-weight", "bold")
.attr("text-anchor", "end")
.text("Percentage of population vaccinated with at least one dose")
)
Insert cell
yGrid = (g) =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(gdpY).tickSize(-width + margin.left + margin.right))
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll("text").remove())
.call((g) => g.selectAll("line").attr("stroke", "white"))
Insert cell
xGrid = (g) =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(
d3.axisBottom(vaxScale).tickSize(-height + margin.top + margin.bottom)
)
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll("text").remove())
.call((g) => g.selectAll("line").attr("stroke", "white"))
Insert cell
Insert cell
Insert cell
Insert cell
predict = linearRegression(confidenceData)
Insert cell
interval = confidenceInterval(confidenceData, predict)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
emojiMap = new Map(countryEmoji.map((key) => [key.alpha3, key.flag]))
Insert cell
Insert cell
gdpDataMap = new Map(gdpData.map((key) => [key.code, key.gdp]))
Insert cell
countryNameMap = new Map(gdpData.map((key) => [key.code, key.country]))
Insert cell
countryEmojiMap = countryEmoji.map
Insert cell
format = d3.format(".1%")
Insert cell
gdpY = d3
.scaleLinear()
.domain([0, 40000])
.range([height - margin.bottom, margin.top])
Insert cell
austriaRed = "#ED2939"
Insert cell
inactiveOpacity = 0.2
Insert cell
inactiveColor = 'grey'
Insert cell
height = 800
Insert cell
wrangled = {
let retval = [];

euCountries
.map((d) => d["iso-3"])
.forEach((country) => {
const countryData = grouped.get(country);

const lastNonNull = countryData
.filter((x) => x["people_vaccinated"] != null)
.slice(-1)
.pop();

var countryName = country;
// if (countryName == "OWID_EUN") countryName = euAutName;

retval.push({
name: countryName,
value: lastNonNull["people_vaccinated"] / lastNonNull["population"],
population: lastNonNull["population"]
});
});

return retval.sort((a, b) => a.value - b.value);
}
Insert cell
findWithAttr = (array, attr, value) => {
for (var i = 0; i < array.length; i += 1) {
if (array[i][attr] === value) {
return i;
}
}
return -1;
}
Insert cell
vaxScale = d3
.scaleLinear()
.domain([0, 100])
.range([margin.left, width - margin.right])
Insert cell
euCountries = [
...d3.csvParse(
await FileAttachment("countryCodes@1.csv").text(),
d3.autoType
),
{ country: "EU", "iso-3": "OWID_EUN" }
]
Insert cell
gdpData = d3.csvParse(
await FileAttachment("gdp-per-capita-worldbank@2.csv").text(),
d3.autoType
)
Insert cell
grouped = d3.group(data, d => d.iso_code)
Insert cell
data = d3.csvParse(
await FileAttachment("owid-covid-data (1)@1.csv").text(),
d3.autoType
)
Insert cell
margin = ({ top: 100, right: 100, bottom: 30, left: 80 })
Insert cell
import { countryEmoji } from "@mattdzugan/making-maps-out-of-emojis";
Insert cell
d3 = require("d3@6", "d3-regression")
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