Public
Edited
Mar 6, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
input = function (numberOfWeeks) {
return [
1,
numberOfWeeks + 1,
difference_in_weeks("2021-11-24", new Date(Date.now()))
];
}
Insert cell
difference_in_weeks = function (dateString1, dateString2) {
return spannedWeeks(weeknumber(dateString1), weeknumber(dateString2));
}
Insert cell
weeknumber = function (dateString) {
const date = new Date(dateString);

// Get the day of the week (0 = Sunday, 1 = Monday, etc.)
const dayOfWeek = date.getUTCDay();

// Calculate specific days of the current week.
// Thursday is used to calculate the week number.
// Saturday and Sunday are used to calculate bifurcation

const saturday = new Date(date);
saturday.setUTCDate(date.getUTCDate() - date.getDay());

const sunday = new Date(saturday);
sunday.setUTCDate(saturday.getUTCDate() + 6);

const thursday = new Date(saturday);
thursday.setUTCDate(saturday.getUTCDate() + 4);

// Calculate the year of the current week
const year = thursday.getUTCFullYear();

const weekNumber =
Math.floor(
(thursday.getTime() - new Date(year, 0, 1).getTime()) /
(7 * 24 * 60 * 60 * 1000)
) + 1;

const isBifurcated = saturday.getFullYear() !== sunday.getFullYear();

// Calculate the week number
return {
weeks: weekNumber,
year: year,
bifurcated: isBifurcated
};
}
Insert cell
function spannedWeeks(date1, date2) {
const yearDiff = date2.year - date1.year;
const spannedWeeks = yearDiff * 52 + (date2.weeks - date1.weeks) + 1;

return spannedWeeks;
}
Insert cell
(function testDateDiffer() {
const startDateString = "2021-11-24";
const startDate = new Date(startDateString);
const endDate = Date.parse("2024-12-25");
const weekStartDates = [];

// Calculate the start date of each Sunday between the start date and end date
for (let d = startDate; d <= endDate; d.setDate(d.getDate() + 1)) {
if (d.getDay() === 0) {
weekStartDates.push(new Date(d));
}
}

let Logger = [];
// Test that the number of weeks spanned between successive Sundays increments by 1
let previousWeek = null;
for (let i = 0; i < weekStartDates.length; i++) {
const week = weeknumber(weekStartDates[i].toISOString());
if (previousWeek !== null) {
const weeksSpanned = spannedWeeks(weeknumber(startDateString), week);
if (weeksSpanned !== i + 2) {
Logger.push(
`Error: Weeks spanned between ${previousWeek.year}-W${
previousWeek.weeks
} and ${week.year}-W${week.weeks} should be ${
i + 2
}, but is ${weeksSpanned}`
);
}
}
previousWeek = week;
}
return Logger;
})()
Insert cell
spannedWeeks(weeknumber("2021-11-24"), weeknumber(new Date(Date.now())))
Insert cell
data_old = FileAttachment("lineages@7.json").json()
Insert cell
data = fetch(
"https://raw.githubusercontent.com/ciscorucinski/SARS-CoV-2_Variant_Designation_Tree/master/lineages.json"
).then((response) => response.json())
Insert cell
lineages = data.root
Insert cell
d3.hierarchy(lineages)
Insert cell
Tree(find("BA.2.75"), {
label: (d) => d.data.lineage.pango,
width: 1100,
heightCoefficent: 0.8,
weeks: 2
})
Insert cell
class Name {
static PANGO = new Name("pango");
static PARTIAL_PANGO = new Name("partial");
static UNALIASED = new Name("unaliased");

constructor(name) {
this.name = name;
}
}
Insert cell
Tree(find("XBB.1.9"), {
label: (d) => d.data.lineage.pango,
width: 600,
heightCoefficent: 2,
weeks: 2
})
Insert cell
// newTree = {
// var tree = d3.hierarchy(lineages).copy();
// tree.children[0] = null;
// tree.data.children[0] = null;
// return tree;
// }
Insert cell
lineages
Insert cell
{
var copiedTree = { ...lineages };
var filtered = copiedTree.children.filter(function (value, index, array) {
return value.id[0] === "X";
});
copiedTree.children = filtered;
return d3.hierarchy(copiedTree);
}
Insert cell
find = function (searchTerm, searchType = Name.PANGO, tree = lineages) {
if (searchTerm === "recombinants") {
var copiedTree = { ...lineages };
var filtered = copiedTree.children.filter(function (value, index, array) {
return value.id[0] === "X";
});
copiedTree.children = filtered;
return d3.hierarchy(copiedTree);
}
return d3
.hierarchy(tree)
.copy()
.find((d) => {
switch (searchType) {
case Name.PANGO:
return d.data.lineage.pango === searchTerm;
case Name.PARTIAL_PANGO:
return d.data.lineage.partial === searchTerm;
case Name.UNALIASED:
return d.data.lineage.unaliased === searchTerm;
}
});
}
Insert cell
find("BA.2.75.5.1", Name.PARTIAL_PANGO)
Insert cell
Tree(find("B.1.1.529"), {
label: (d) => d.data.lineage.pango,
width: 1100,
heightCoefficent: 0.9,
weeks: 2
})
Insert cell
Tree(find("BA.2.75"), {
label: (d) => d.data.lineage.pango,
width: 1000,
heightCoefficent: 0.85,
weeks: 0
})
Insert cell
Tree(find("BE.1"), {
label: (d) => d.data.lineage.pango,
width: 1000,
heightCoefficent: 0.9,
weeks: 3
})
Insert cell
Tree(find("recombinants"), {
label: (d) => d.data.lineage.pango,
width: 1000,
heightCoefficent: 1,
weeks: 2
})
Insert cell
find("recombinants")
Insert cell
Tree(find("XBB.1.9"), {
label: (d) => d.data.lineage.pango,
width: 600,
heightCoefficent: 2,
weeks: 2
})

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