|
|
|
// SARS-CoV-2-Viz
|
|
|
|
// Animated COVID case count visualization
|
|
|
|
// Copyright 2022 Edward L. Platt <ed@elplatt.com>
|
|
|
|
|
|
|
|
// Convert csv to tsv
|
|
|
|
// Assumes quoted strings do not contain escaped quotes
|
|
|
|
function csvToTSV(csv, onProgress) {
|
|
|
|
onProgress("0 of ? parts");
|
|
|
|
let quoteParts = csv.split('"');
|
|
|
|
let tsv = "";
|
|
|
|
const rowCount = quoteParts.length;
|
|
|
|
for (const [index, part] of quoteParts.entries()) {
|
|
|
|
if (index % 2 == 0) {
|
|
|
|
// Not quoted
|
|
|
|
tsv += part.replace(/,/g, "\t");
|
|
|
|
} else {
|
|
|
|
// Quoted
|
|
|
|
tsv += part;
|
|
|
|
}
|
|
|
|
onProgress("{$index} of {$rowCount} parts");
|
|
|
|
}
|
|
|
|
return tsv;
|
|
|
|
}
|
|
|
|
|
|
|
|
function tsvRowToJSON(keys, tsvRow) {
|
|
|
|
let row = {};
|
|
|
|
let rowParts = tsvRow.split("\t");
|
|
|
|
for (const [index, key] of keys.entries()) {
|
|
|
|
row[key] = rowParts[index];
|
|
|
|
}
|
|
|
|
return row;
|
|
|
|
}
|
|
|
|
|
|
|
|
function tsvToJSON(tsv, onProgress) {
|
|
|
|
const lines = tsv.split(/\n/);
|
|
|
|
let columnNames = [];
|
|
|
|
let data = [];
|
|
|
|
const count = lines.length;
|
|
|
|
for (const [row, line] of lines.entries()) {
|
|
|
|
if (row == 0) {
|
|
|
|
columnNames = line.split("\t").map((x) => x.trim());
|
|
|
|
} else {
|
|
|
|
let dataRow = {};
|
|
|
|
for (const [col, cell] of line.split("\t").entries()) {
|
|
|
|
dataRow[columnNames[col]] = cell.trim();
|
|
|
|
}
|
|
|
|
// Limit to US Counties
|
|
|
|
if (dataRow["iso3"] == "USA"
|
|
|
|
&& dataRow["Admin2"] != ""
|
|
|
|
&& dataRow["Admin2"] != "Unassigned"
|
|
|
|
&& dataRow["FIPS"] != "") {
|
|
|
|
data.push(dataRow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let progress = count / row;
|
|
|
|
onProgress(progress);
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|