Published
Edited
Dec 14, 2020
Importers
Insert cell
md`# Covid Zoomable Chart`
Insert cell
data = d3.csv(
await FileAttachment(
"United_States_COVID-19_Cases_and_Deaths_by_State_over_Time.csv"
).url()
)
Insert cell
no_negatives = data.filter(function(d) {
return d.new_case >= 0;
})
Insert cell
filteredData = no_negatives.map(d => ({
x: formatTime(d.submission_date),
y: +d.new_case,
state: d.state
}))
Insert cell
totalData = data.map(d => ({
x: formatTime(d.submission_date),
y: +d.tot_cases,
z: +d.tot_death,
state: d.state
}))
Insert cell
formatTime = d3.timeParse("%m/%d/%Y")
Insert cell
// xScale = d3
// .scaleTime()
// .domain(d3.extent(totalData, d => d.x))
// .range([margin.left, width - margin.right])
Insert cell
// yScale = d3
// .scaleLinear()
// .domain([0, max])
// .range([height - margin.bottom, margin.top])
Insert cell
yAxi = (g, y) =>
g//.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(12 * k))
.call(g => g.select(".domain").attr("display", "none"))
Insert cell
xAxi = (g, x) =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(12))
.call(g => g.select(".domain").attr("display", "none"))
Insert cell
k = height / width
Insert cell
max = d3.max(filtered, d => d.y)
Insert cell
filtered = totalData.filter(function(d) {
return d.state == selected_state;
})
Insert cell
max_deaths = d3.max(filtered, d => d.z)
Insert cell
viewof selected_state = select({
title: "State for Comparison",
options: _.uniqBy(filteredData, d => d.state)
.map(d => d.state)
.sort(),
value: "WA"
})
Insert cell
Insert cell
curve_diff = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height + 50)
.attr("text-anchor", "middle");

//svg.append("g").call(xAxi);

//svg.append("g").call(yAxi);

svg.node().update2 = sel => {
svg.selectAll("*").remove();

const curveData = totalData.filter(function(d) {
return d.state == sel;
});

const gLine = svg.append('g');
const gLine2 = svg.append('g');

const yLimits = d3.extent(curveData, d => +d.y);
const yScale = d3
.scaleLinear()
.domain(yLimits)
.range([height - margin.bottom, margin.top])
.nice();

const timeLimits = d3.extent(curveData, d => d.x);
const xScale = d3
.scaleTime()
.domain(timeLimits)
.range([margin.left, width - margin.right])
.nice();

const covidCasesLineGen = d3
.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y));

const covidDeathLineGen = d3
.line()
.x(d => xScale(d.x))
.y(d => yScale(d.z));

gLine
.append("path")
.attr("stroke", "#944dff")
.datum(curveData)
.attr("fill", "none")
.attr("d", d => covidCasesLineGen(d));

gLine2
.append("path")
.attr("stroke", "red")
.datum(curveData)
.attr("d", d => covidDeathLineGen(d))
.attr("fill", "none");

const gx = svg
.append('g')
.attr('class', 'x-axis')
.attr('transform', 'translate(0,' + (height - margin.bottom) + ')');

const gy = svg
.append('g')
.attr('class', 'y-axis')
.attr('transform', 'translate(' + margin.left + ',0)');

function zoomed({ transform }) {
const zx = transform.rescaleX(xScale).interpolate(d3.interpolateRound); // calculate the new xScale
const zy = transform.rescaleY(yScale).interpolate(d3.interpolateRound); // calculate the new yScale
gLine.attr("transform", transform).attr("stroke-width", 1 / transform.k); // transform the line
gLine2.attr("transform", transform).attr("stroke-width", 2 / transform.k);
gx.call(xAxi, zx); // redraw x-axis with new "x" scale, "zx" is passed as the second arg to "xAxis"
gy.call(yAxi, zy); // redraw y-axis with new "y" scale, "zy" is passed as the second arg to "yAxis"
}

const zoom = d3
.zoom()
.scaleExtent([0.5, 32])
.on("zoom", zoomed);

svg.call(zoom).call(zoom.transform, d3.zoomIdentity);
};

// svg
// .append("g")
// .attr("transform", `translate(${width - 400}, 0)`)
// .append(() => death_legend);

return svg.node();
}
Insert cell
stats = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", 70)
.attr("text-anchor", "middle");

svg
.append("text")
.attr("x", width / 2)
.attr("y", 20)
.text("Covid-19 Cases vs Deaths for " + selected_state);

svg
.append("text")
.attr("font-size", 12)
.attr("x", width / 2)
.attr("y", 35)
.text("Most Recent Total Cases: " + max);

svg
.append("text")
.attr("font-size", 12)
.attr("x", width / 2)
.attr("y", 50)
.text("Most Recent Total Deaths: " + max_deaths);

svg
.append("text")
.attr("font-size", 12)
.attr("x", width / 2)
.attr("y", 65)
.text(
"Death Percent of Total: " + ((max_deaths / max) * 100).toFixed(2) + "%"
);

return svg.node();
}
Insert cell
curve_diff.update2(selected_state)
Insert cell
d3 = require("d3")
Insert cell
margin = ({
top: 20,
right: 30,
bottom: 30,
left: 80
})
Insert cell
height = 500
Insert cell
import { legend } from "@d3/color-legend"
Insert cell
import { select } from "@jashkenas/inputs"
Insert cell
_ = require("lodash")
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