|
|
|
// SARS-CoV-2-Viz
|
|
|
|
// Animated COVID case count visualization
|
|
|
|
// Copyright 2022 Edward L. Platt <ed@elplatt.com>
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
let ui = UI();
|
|
|
|
let tracker = ProgressTracker(
|
|
|
|
(id) => { ui.addDisplay(id); },
|
|
|
|
(id, progress) => ui.display(progress, id)
|
|
|
|
);
|
|
|
|
document.getElementById("header").appendChild(ui.node);
|
|
|
|
|
|
|
|
let onDataProgress = tracker.getTracker();
|
|
|
|
let dataPromise = getData(
|
|
|
|
(progress) => {
|
|
|
|
onDataProgress(`Fetching data: Received ${progress} bytes`)
|
|
|
|
})
|
|
|
|
.then((dataCSV) => {
|
|
|
|
let result = parseData(
|
|
|
|
dataCSV,
|
|
|
|
(progress) => onDataProgress(`Parsing data: ${progress}`));
|
|
|
|
return result;
|
|
|
|
})
|
|
|
|
.then((data) => {
|
|
|
|
return data;
|
|
|
|
});
|
|
|
|
|
|
|
|
let onFeatureProgress = tracker.getTracker();
|
|
|
|
let featurePromise = getFeatures(
|
|
|
|
async function (progress) {
|
|
|
|
await onFeatureProgress(`Fetching features: Received ${progress} bytes`);
|
|
|
|
})
|
|
|
|
.then(async (features) => {
|
|
|
|
return await parseFeatures(
|
|
|
|
features,
|
|
|
|
async (progress) => await onFeatureProgress(`Parsing features: ${progress}`));
|
|
|
|
});
|
|
|
|
|
|
|
|
let onMetadataProgress = tracker.getTracker();
|
|
|
|
let metadataPromise = getMetadata(
|
|
|
|
async (progress) => {
|
|
|
|
await onMetadataProgress(`Fetching metadata: ${progress}`);
|
|
|
|
})
|
|
|
|
.then(async (metadataCSV) => {
|
|
|
|
return await parseMetadata(
|
|
|
|
metadataCSV,
|
|
|
|
async (progress) => await onMetadataProgress(`Parsing metadata: ${progress}`));
|
|
|
|
});
|
|
|
|
|
|
|
|
Promise.all([
|
|
|
|
dataPromise, featurePromise, metadataPromise
|
|
|
|
]).then((values) => {
|
|
|
|
const [rawDataForDay, us, metadata] = values;
|
|
|
|
const population = populationMap(metadata);
|
|
|
|
const dataForDay = normalizeData(rawDataForDay, population);
|
|
|
|
|
|
|
|
if (false) {
|
|
|
|
console.log("Data for Day")
|
|
|
|
console.log(dataForDay);
|
|
|
|
console.log("US");
|
|
|
|
console.log(us);
|
|
|
|
console.log("Population");
|
|
|
|
console.log(population);
|
|
|
|
}
|
|
|
|
|
|
|
|
let msPerFrame = 250;
|
|
|
|
let dates = dataForDay.map((data) => data["10001"].date);
|
|
|
|
let day = dataForDay.length - 1;
|
|
|
|
let data = dataForDay[day];
|
|
|
|
let normalizeBy = 'toDate';
|
|
|
|
ui.onNormalize((value) => {
|
|
|
|
normalizeBy = value;
|
|
|
|
chart.update(dataForDay[day]);
|
|
|
|
});
|
|
|
|
let domain = (d) => {
|
|
|
|
if (normalizeBy == 'all') {
|
|
|
|
return [0, Math.max(1, d["10001"].maxPer100KCap)];
|
|
|
|
} else {
|
|
|
|
return [0, Math.max(1, d["10001"].maxSoFarPer100KCap)];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let chart = createChoropleth(us, msPerFrame, domain);
|
|
|
|
|
|
|
|
ui.clearDisplays();
|
|
|
|
ui.display("Initializing visualization");
|
|
|
|
ui.display(dataForDay[day]["10001"].date);
|
|
|
|
ui.setFrames(dates, day);
|
|
|
|
ui.setMsPerFrame(msPerFrame);
|
|
|
|
ui.showControls();
|
|
|
|
|
|
|
|
document.getElementById("content").appendChild(chart.node);
|
|
|
|
chart.update(data);
|
|
|
|
ui.onTick((day) => {
|
|
|
|
chart.update(dataForDay[day]);
|
|
|
|
ui.display(dates[day]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
main();
|
|
|
|
|