Public
Edited
Nov 12, 2021
Insert cell
Insert cell
Insert cell
Insert cell
annotations = [
[
"2020-09-20",
"Cohort of undergraduates are allowed to move back onto campus for limited in-person classes",
{ dy: 100 }
],
["2020-10-05", "Quiet period ends", { dy: 60 }],
[
"2020-11-18",
"In-person classes shifted online in response to rising cases",
{ flip: true }
],
[
"2020-11-25",
"Thanksgiving break begins, portion of the undergraduate population leaves campus for the rest of the semester"
],
[
"2021-01-27",
"Campus moves to Modified Level 2 activity status",
{ dy: 20 }
],
[
"2021-07-07",
"After 90% vaccination level reached, Brown removes vaccinated students from testing program and drops indoor masking requirement for masking students",
{ flip: true }
],
[
"2021-08-03",
"University reinstates indoor mask mandate for all community members and increases required testing frequency for vaccinated people"
],
[
"2021-09-13",
"New temporary restrictions introduced, including suspension of indoor dining",
{ flip: true, dy: 120 }
],
["2021-09-24", "In-person dining resumes", { dy: 270 }],
[
"2021-09-29",
"Remaining temporary restrictions are reversed",
{ dy: 180, width: 80 }
],
[
"2021-10-06",
"Fully vaccinated students are only required to get tested once weekly",
{ dy: 100 }
],
[
"2021-10-29",
"Fully vaccinated undergraduate students are no longer required to get tested",
{ flip: true }
]
].map((d) => ({
date: new Date(d[0]),
content: d[1],
...d[2]
}))
Insert cell
xAxis = (x, ticks = 80, height = heroMetrics.height) => (g) =>
g
.attr("transform", `translate(0,${height - heroMetrics.bottom})`)
.call(d3.axisBottom(x).ticks(ticks).tickFormat(d3.timeFormat("%-m/%-d")))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
fall2020Timeline = makeSemesterTimeline(semesters[0])
Insert cell
spring2021Timeline = makeSemesterTimeline(semesters[1])
Insert cell
summer2021Timeline = makeSemesterTimeline(semesters[2])
Insert cell
fall2021Timeline = makeSemesterTimeline(semesters[3])
Insert cell
Insert cell
printTimeline = {
const data = smooth(rates, "rate");
const x = d3
.scaleTime()
.domain(d3.extent(rates, (d) => d.date))
.range([0, heroMetrics.width - heroMetrics.right]);

const chart = d3.select(DOM.svg(heroMetrics.width, heroMetrics.height));
chart
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("font-family", "sans-serif")
.attr("font-size", 11);

const content = chart
.append("g")
.attr("transform", `translate(${heroMetrics.left}, 0)`);

content.append("g").call(addSemesters(x, 18));

content
.append("g")
.call((g) =>
g
.attr(
"transform",
`translate(0,${heroMetrics.height - heroMetrics.bottom})`
)
.call(d3.axisBottom(x).ticks(20).tickFormat(d3.timeFormat("%B %Y")))
);
content.append(rateLine(x, data));

chart
.append("g")
.call(yAxis)
.call((g) =>
g
.select(".tick:last-of-type text")
.clone()
.attr("x", -23)
.attr("y", -12)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(`↑ test positivity rate (7-day average, %)`)
);

return chart.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
semesterPicker = html`<center><p style="font-size:30px">I was on campus for: <br> ${viewof hereFall2020} <br> ${
hereFall2020 ? html`${viewof thanksgiving2020}` : html``
} <br> ${viewof hereSpring2021} <br> ${viewof hereSummer2021} <br> ${viewof hereFall2021}`
Insert cell
Ω = html`<center><p style="font-size:40px">You took <strong>${totalTests.toLocaleString()}</strong> tests!`
Insert cell
totalTests = {
let totalTests = 0;
if (hereFall2020) totalTests += testRequirements[0].numTests;
if (thanksgiving2020) totalTests += testRequirements[5].numTests;
if (hereSpring2021) totalTests += testRequirements[1].numTests;
if (hereSummer2021) totalTests += testRequirements[2].numTests;
if (hereFall2021)
testRequirements.slice(3).forEach((r) => (totalTests += r.numTests));

return totalTests;
}
Insert cell
check = (title, checked = true) => {
const checkbox = html`<input type="checkbox">`;
checkbox.checked = checked;
const view = html`<label style="margin-right: 0.75em">${checkbox} ${title}`;
view.value = checked;
checkbox.oninput = () => (view.value = checkbox.checked);
return view;
}
Insert cell
viewof thanksgiving2020 = check("Thanksgiving 2020 until finals")
Insert cell
viewof hereFall2020 = check("Fall 2020 until Thanksgiving")
Insert cell
viewof hereSpring2021 = check("Spring 2021")
Insert cell
viewof hereSummer2021 = check("Summer 2021", false)
Insert cell
viewof hereFall2021 = check("Fall 2021")
Insert cell
Insert cell
Insert cell
html`<div style="display:flex">${Plot.plot({
marks: [
Plot.barY(
d3
.groups(data, (d) =>
dateFns.differenceInCalendarDays(d.date, dateFns.startOfWeek(d.date))
)
.map(([day, items]) => ({
day,
total: d3.sum(items, (d) => d.negative + d.positive)
})),
{ x: "day", y: "total" }
)
],
x: { tickFormat: Plot.formatWeekday() },
y: { tickFormat: "s" },
width: 350
})}${Plot.plot({
marks: [
Plot.barY(
d3
.groups(data, (d) =>
dateFns.differenceInCalendarDays(d.date, dateFns.startOfWeek(d.date))
)
.map(([day, items]) => ({
day,
positive:
d3.sum(items, (d) => d.positive) /
d3.sum(items, (d) => d.negative + d.positive)
})),
{ x: "day", y: "positive", fill: "red", axis: "right" }
)
],
x: { tickFormat: Plot.formatWeekday() },
y: { tickFormat: "%" },
width: 350
})}`
Insert cell
// Plot.plot({
// marks: [
// // Plot.line(weeks, { x: "date", y: "negative / 10", stroke: "green" }),
// Plot.line(weekify(data, ["positive"]), {
// x: "date",
// y: "positive",
// stroke: "red"
// }),
// Plot.line(weekify(vax, ["doses"]), { x: "date", y: (d) => d.doses / 4e5 }),
// Plot.line(
// weekify(
// covid.filter((d) => d.state === "RI"),
// ["new_case"]
// ),
// { x: "date", y: (d) => d.new_case / 1e2, stroke: "blue" }
// )
// ]
// })
Insert cell
// Plot.plot({
// marks: [
// // Plot.line(weeks, { x: "date", y: "negative / 10", stroke: "green" }),
// Plot.line(weekify(data, ["positive"]), {
// x: "date",
// y: "positive",
// stroke: "red"
// }),
// Plot.line(weekify(vax, ["doses"]), { x: "date", y: (d) => d.doses / 4e5 }),
// Plot.line(
// weekify(
// covid.filter((d) => d.state === "RI"),
// ["new_case"]
// ),
// { x: "date", y: (d) => d.new_case / 1e2, stroke: "blue" }
// )
// ],
// width: width
// })
Insert cell
Insert cell
// vaxRaw = d3
// .csvParse(
// (
// await FileAttachment(
// "trends_in_number_of_covid19_vaccinations_in_the_us.csv"
// ).text()
// )
// .split("\r\n")
// .slice(2)
// .join("\r\n"),
// d3.autoType
// )

Insert cell
// d3.groups(vax, (d) => d.Location)
Insert cell
// vax = vaxRaw
// .filter((d) => d["Date Type"] == "Admin")
// .map((d) => ({
// type: d["Date Type"],
// date: d.Date,
// doses: d["Total Doses Administered Daily"]
// }))
Insert cell
// weekify = (arr, keysToSum) =>
// d3
// .groups(arr, (d) => `${dateFns.getYear(d.date)}-${dateFns.getWeek(d.date)}`)
// .map(([week, entries]) => ({
// date: entries[0].date,
// ...Object.fromEntries(
// keysToSum.map((k) => [k, d3.sum(entries, (d) => d[k])])
// )
// }))
Insert cell
data = FileAttachment("Brown_Asymptomatic Test Results_Daily.xlsx")
.xlsx()
.then((file) => file.sheet(0, { headers: true }))
.then((data) =>
data.map((d) => ({
date: d.Date,
negative: d.Negative,
positive: d.Positive
}))
)
Insert cell
// dateFns = import("https://unpkg.com/date-fns@2.16.1/esm/index.js?esm")
Insert cell
// only fetch the required functions (there are a lot of other ones)
dateFns = Promise.all(
[
"isBefore",
"isSameDay",
"differenceInCalendarDays",
"startOfWeek",
"differenceInWeeks"
].map((name) =>
import(
`https://unpkg.com/date-fns@2.16.1/esm/${name}/index.js`
).then((m) => [name, m.default])
)
).then(Object.fromEntries)
Insert cell
// rawCovid = await d3.json(
// "https://data.cdc.gov/resource/9mfq-cb36.json?$$app_token=P7qXIq6TVhbiyl54sAjeIcy4C&$limit=50000"
// )
Insert cell
// d3
// .groups(rawCovid, (d) => Object.keys(d).length)
// .map((d) => [d[0], Object.keys(d[1][0])])
Insert cell
// covid = d3.sort(
// rawCovid.map((d) => ({
// date: new Date(d.submission_date),
// state: d.state,
// tot_cases: +d.tot_cases,
// // conf_cases: +d.conf_cases,
// // prob_cases: +d.prob_cases,
// new_case: +d.new_case,
// // pnew_case: +d.pnew_case,
// tot_death: +d.tot_death,
// new_death: +d.new_death,
// // pnew_death: +d.pnew_death,
// created_at: new Date(d.created_at)
// // consent_cases: d.consent_cases,
// // consent_deaths: d.consent_deaths
// })),
// (d) => d.date
// )
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