Published
Edited
Dec 28, 2020
1 fork
Importers
16 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
xData = getCovidDataGrouped({
statistic: "positive",
derivative: 1,
smoothing
})
Insert cell
xLabel = `daily new positive tests (${smoothing}-day moving average)`
Insert cell
yData = getCovidDataGrouped({
statistic: "positive",
derivative: 2,
smoothing
})
Insert cell
yLabel = "change in " + xLabel
Insert cell
Insert cell
duration = 10e3
Insert cell
height = 720
Insert cell
margin = ({top: 20, right: 30, bottom: 30, left: 40})
Insert cell
x = d3.scaleLinear()
.domain(d3.extent(data, d => d.x)).nice()
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain(d3.extent(data, d => d.y)).nice()
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80))
.call(g => g.select(".domain").remove())
.call(g =>
g
.selectAll(".tick line")
.clone()
.attr("y2", -height)
.attr("stroke-opacity", 0.1)
)
.call(g =>
g
.append("text")
.attr("x", width - 4)
.attr("y", -4)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.attr("fill", "black")
.text(data.x)
.call(halo)
)
Insert cell
yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(
d3
.axisLeft(y)
.ticks()
.tickFormat(d => (d === 0 ? 0 : d > 0 ? `+${d}` : `–${Math.abs(d)}`))
)
.call(g => g.select(".domain").remove())
.call(g =>
g
.selectAll(".tick line")
.clone()
.attr("x2", width)
.attr("stroke-opacity", 0.1)
)
.call(g =>
g
.select(".tick:last-of-type text")
.clone()
.attr("x", 4)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("fill", "black")
.text(data.y)
.call(halo)
)
Insert cell
function halo(text) {
text.select(function() { return this.parentNode.insertBefore(this.cloneNode(true), this); })
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-width", 4)
.attr("stroke-linejoin", "round");
}
Insert cell
function length(path) {
return d3.create("svg:path").attr("d", path).node().getTotalLength();
}
Insert cell
line = d3.line()
.curve(d3.curveCatmullRom)
.x(d => x(d.x))
.y(d => y(d.y))
Insert cell
data = stateData.get(state)
Insert cell
stateData = new Map(
states
.map(state => [
state,
Object.assign(
dates
.map(date => ({
name: date.slice(5),
x: xData.get(state).get(date),
y: yData.get(state).get(date)
}))
.filter(({ x, y }) => x !== undefined && y !== undefined),
{ x: xLabel, y: yLabel, name: state }
)
])
.concat([["pure logistic example", logistic]])
)
Insert cell
cumulative = getCovidDataGrouped({
statistic: "positive"
})
Insert cell
states = Array.from(cumulative.keys()).sort(
(a, b) => cumulative.get(b).get(latest) - cumulative.get(a).get(latest)
)
Insert cell
dates = Array.from(cumulative.get("WA").keys())
Insert cell
latest = dates[dates.length - 1]
Insert cell
import { getCovidDataGrouped } from "@tophtucker/covid-tracking-project-data"
Insert cell
d3 = require("d3@5")
Insert cell
logistic = Object.assign(
d3
.range(0, 20, .5)
.map(dLogistic(10, 100, 1))
.map((d, i, arr) => ({
name: i,
x: Math.log(d),
y: Math.log(d) - Math.log(arr[i - 1])
}))
.filter(({ x, y }) => valid(x) && valid(y)),
{ x: xLabel, y: yLabel, name: "logistic" }
)
Insert cell
valid = d => d !== undefined && d !== null && !isNaN(d)
Insert cell
import { dLogistic } from "@tophtucker/scrapbook"
Insert cell
import { radio, slider } from "@jashkenas/inputs"
Insert cell
// // for animation
// state = {
// replay;
// for (const state of states) {
// yield state;
// await Promises.delay(5450);
// }
// }
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