Published
Edited
Jan 14, 2022
3 stars
Also listed in…
selection
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.style('background-color', '#FFF8E7')
.style('background-color', 'white')
.attr("font-family", "sans-serif");

const title = svg.append("g");

let titleText = "";
if (property == "total_deaths_per_million")
titleText = "cumulative COVID-19 deaths ranking";
else if (property == "total_vaccinations_per_hundred")
titleText = "cumulative COVID-19 vaccinations ranking";
else if (property == "total_tests_per_thousand")
titleText = "cumulative COVID-19 tests ranking";

title
.append("text")
.attr("x", x(dates.length / 2 - 1))
.attr("y", y(0) - 6)
.attr("font-size", 6)
.attr("text-anchor", "middle")
.attr("fill", "grey")
.style("font-variant", "small-caps")
.text(titleText);

title
.append("text")
.attr("x", x(0))
.attr("y", y(euCountries.length) + 2)
.attr("font-size", 5)
.attr("text-anchor", "start")
.attr("fill", inactiveColor)
.text(dateFormat(dates[0]));

title
.append("text")
.attr("x", x(dates.length - 1))
.attr("y", y(euCountries.length) + 2)
.attr("font-size", 5)
.attr("text-anchor", "end")
.attr("fill", inactiveColor)
.text(dateFormat(dates[dates.length - 1]));

const platno = svg.append("g");

euCountries.forEach(country => {
let iso3 = country["iso-3"];

platno
.append("text")
.attr("fill", (d, i) => {
let retval = inactiveColor;
if (iso3 == "HRV") retval = "orange";
return retval;
})
.attr("text-anchor", "end")
.attr('class', `label-${iso3}`)
.attr("font-size", 5)
.attr("opacity", (d, i) => {
let retval = 0.6;
if (iso3 == "HRV") retval = 1;
return retval;
})
.attr("y", y(wrangled[property][iso3][0]) + 1)
.attr("x", x(0) - 5)
.text(country.country)
.on('mouseover', d => {
let target = d3.select(d.target);
let country = target
.attr('class')
.substring(target.attr('class').indexOf('-') + 1);

d3.select(`.path-${country}`)
.attr('stroke', 'black')
.attr('opacity', 0.4);
d3.select(d.target).attr('fill', 'black');
})
.on('mouseout', d => {
let target = d3.select(d.target);
let country = target
.attr('class')
.substring(target.attr('class').indexOf('-') + 1);

let toColor = country == 'HRV' ? 'orange' : inactiveColor;
let toOpacity = country == 'HRV' ? 1 : inactiveOpacity;
d3.select(`.path-${country}`)
.attr('stroke', toColor)
.attr('opacity', toOpacity);

d3.select(d.target).attr('fill', inactiveColor);
});

platno
.append("path")
.attr("stroke", (d, i) => {
let retval = inactiveColor;
if (iso3 == "HRV") retval = "orange";
return retval;
})
.attr('class', `path-${iso3}`)
.attr("stroke-width", (d, i) => {
let retval = 1;
if (iso3 == "HRV") retval = 2;
return retval;
})
.attr("opacity", (d, i) => {
let retval = inactiveOpacity;
if (iso3 == "HRV") retval = 1;
return retval;
})
.attr("fill", "none")
.attr("d", line(wrangled[property][iso3]));
});

return svg.node();
}
Insert cell
inactiveOpacity = 0.2
Insert cell
inactiveColor = 'grey'
Insert cell
line = d3
.line()
.x((d, i) => x(i))
.y(d => y(d))
Insert cell
y = d3
.scaleLinear()
.domain([0, euCountries.length])
.range([20, height - 10])
Insert cell
x = d3
.scaleLinear()
.domain([0, dates.length])
.range([50, width])
Insert cell
height = 200
Insert cell
width = 300
Insert cell
wrangled = {
let retval = new Map();

properties.forEach(property => {
retval[property] = new Map();

euCountries
.map(d => d['iso-3'])
.forEach(country => {
retval[property][country] = new Array();
dates.forEach(date => {
let position = findWithAttr(
rankings[property][dateFormat(date)],
'country',
country
);
// .indexOf(country);
retval[property][country].push(position);
});
});
});

return retval;
}
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
rankings[properties[0]]
Insert cell
rankings = {
let retval = new Map();

properties.forEach((property) => {
retval[property] = new Map();
dates.forEach((date) => {
retval[property][dateFormat(date)] = new Array();

euCountries.forEach((country) => {
let item = grouped
.get(country["iso-3"])
.filter((d) => d.date <= date)
.slice(-1)[0];

let value = item[property];

if (country["iso-3"] === "HRV")
value = (item[property] * 4081657) / 3888529;

retval[property][dateFormat(date)].push({
country: country["iso-3"],
value: value,
sampleDate: item["date"]
});
});

if (property == "total_deaths_per_million") {
retval[property][dateFormat(date)].sort((a, b) => a.value - b.value);
} else if (property == "total_vaccinations_per_hundred") {
retval[property][dateFormat(date)].sort((a, b) => b.value - a.value);
} else if (property == "total_tests_per_thousand") {
retval[property][dateFormat(date)].sort((a, b) => b.value - a.value);
}
});
});

return retval;
}
Insert cell
dateFormat = d3.timeFormat('%Y-%m-%d')
Insert cell
//properties = ['total_deaths_per_million', 'total_vaccinations_per_hundred', 'total_tests_per_thousand']
properties = new Map([
["Total deaths", "total_deaths_per_million"],
["Total vaccinations", "total_vaccinations_per_hundred"],
["Total tests", "total_tests_per_thousand"]
])
Insert cell
euCountries = [
...d3.csvParse(await FileAttachment("countryCodes@1.csv").text(), d3.autoType)
//{ country: 'EU', 'iso-3': 'OWID_EUN' }
]
Insert cell
//dates = d3.timeDay.range(startDate, endDate, 30)
dates = splitDateIntoEqualIntervals(startDate, endDate, 11)
Insert cell
splitDateIntoEqualIntervals = (startDate, endDate, numberOfIntervals) => {
let diff = endDate.getTime() - startDate.getTime();
let intervalLength = diff / numberOfIntervals;
let intervals = [];
intervals.push(new Date(startDate.getTime()));
for (let i = 1; i <= numberOfIntervals; i++)
intervals.push(new Date(startDate.getTime() + i * intervalLength));
return intervals;
}
Insert cell
startDate = new Date(2020, 3, 15)
Insert cell
endDate = new Date(2022, 0, 1)
Insert cell
grouped.get("HRV")[427]
Insert cell
grouped = d3.group(data, d => d.iso_code)
Insert cell
breakpoints = 10
Insert cell
data = d3.csvParse(
await FileAttachment("owid-covid-data@2.csv").text(),
d3.autoType
)
Insert cell
import { Select } from "@observablehq/inputs"
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