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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more