Published
Edited
Apr 12, 2020
20 stars
Andy's Walgreens COVID-19 Tracker TrackerBelgium Vaccination Tracker - Progress of the vaccination campaignVaccination against covid-19 in France500,000 COVID-19 DeathsCovid-19 vaccinations: BubblesTime Spiral with a COVID DemoCOVID MasksGrid Cartogram component with live COVID demos (plus a MapEditor)The US COVID SyringeCOVID-19 DKCOVID-19 World Community Mobility Report by GoogleCOVID 19Chicago COVID ZIP SparklinesThe COVID Syringeభారతదేశంలో కోవిడ్-19SVG DataGrid with many features and a live COVID Dashboard demoThe spread of Covid-19 in New MexicoHeatmap of COVID-19 Confirmed Cases by Age over Time in JapanThe CoViD-19 ReportCovid19 WorldwideMassachusetts Coronavirus Cases by TownChoropleth map about Covid19 in FranceWell ordered coronavirus heatmaps for US and the WorldCOVID-19 Racial/Ethnic Mortality AnalysisProPublica's COVID Arrow MapClustering students to slow virus spread inside schoolsCOVID-19 in the USAWho Is Wearing Masks in the U.S.Covid-19 Viz RoundupCoronavirus StatsThe Covid-19 Crisis' Impact on the Number of US Flight PassengersCOVID-19 Daily New CasesCOVID-19 CasesCOVID–19 Bubble Chart with D3 RenderCoronavirus Deaths by Race / EthnicityHow many SARS-CoV-2 tests are we running in the U.S.?COVID-19 Onset vs. ConfirmationPeaks in confirmed daily deaths due to COVID-19 so farCOVID-19 in the U.S.Recreating John Burn-Murdoch’s Coronavirus trackerTracking COVID-19 Cases in VietnamCOVID-19 in NYC by Zip Code & IncomeVisualizing the Network Meta-Analysis of Covid-19 Studiesxkcd COVID-19 spread sketchCOVID-19's deaths in EuropeCovid-19 (corona virus) deaths per 1,000,000 peopleCOVID-19 Bubble map or spike map? (Twitter debate)
A Timeline of Shelter-in-Place
Where’s that $2 trillion going?Estimating SARS-COV-2 infectionsCODAVIM - CountySARS-CoV-2 Epi CurveCOVID-19 Curves (U.S.)COVID-19 Cases by CountyCOVID-19 world growth rateA graphical experiment of exponential spreadCOVID-19 by US countyCOVID-19 Confirmed vs. New cases"Live" Logistic Coronavirus Death CounterInfografiche: COVID-19 in ItaliaCoronavirus (COVID-19) GlobeBar Chart Race, COVID-19 outbreak Worldwide to 24th March 2020US Coronavirus testing by statesUnited States Coronavirus Daily Cases Map (COVID-19)COVID-19 Numbers by State, Side by SideRecreating NYT U.S. Cases MapCOVID-19 in Washington stateCOVID-19 outbreak in maps and chartsCOVID-19 Spreading trendsRestaurants during COVID-19 social distancingCOVID-19 Countries Trajectories in 3DStates that aren't reporting aspects of their COVID-19 testing processNextstrain Prototyping - Issue 817Reviewing COVID-19 SARS-CoV-2 preprints from medRxiv and bioRxivCoronavirus worldwide evolutionCovid-19 New Cases PunchcardCovid-19 cases per district in Germany.COVID-19 Cases, Deaths, and Recoveries (Select Country)Quarantine NowEmissions in WuhanCOVID-19(nCOV-2019) Outbreak in S.KoreaMovement of population between provinces in 2019-nCoVComparing COVID-19 GrowthCovid-19 derived chartCoronavirus Trends (COVID-19)Netherlands Coronavirus Daily Cases Map (COVID-19)Map and timeline of Corona outbreakSARS-CoV-2 Phylogenetic TreeCoronavirus data (covid-19)Visualizing the Logic of Exponential Viral SpreadItaly Coronavirus Daily Cases Map (COVID-19)COVID-19 Fatality Rate
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-family", "sans-serif")
.attr("font-size", 10);

svg.append("g")
.attr("stroke", "currentColor")
.attr("stroke-width", 2)
.selectAll("line")
.data(data.filter(d => d.start !== null))
.join("line")
.attr("x1", d => x(d.start))
.attr("x2", x(today))
.attr("y1", d => y(d.name))
.attr("y2", d => y(d.name));

svg.append("g")
.call(xAxis);

svg.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(data)
.join("text")
.attr("x", d => x(d.start || today) - 6)
.attr("y", d => y(d.name))
.attr("dy", "0.35em")
.text(d => d.name)
.filter(d => d.start)
.append("title")
.text(d => `${d.name}
${d3.utcFormat("%B %-d, %-I:%M %p")(d.start)}`);

svg.append("g")
.selectAll("text")
.data(data)
.join("text")
.attr("x", width - margin.right + 6)
.attr("y", d => y(d.name))
.attr("dy", "0.35em")
.text(d => {
if (d.start === null) return d.partial ? "Partial" : "None";
const day = Math.round((today - d.start) / (1000 * 60 * 60 * 24));
return `${day} day${day === 1 ? "" : "s"}`;
});

svg.append("g")
.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", d => d.start ? x(d.start) : x(today))
.attr("cy", d => y(d.name))
.attr("r", 2)
.attr("fill", d => d.start ? "currentColor" : "none")
.attr("stroke", d => d.start ? "none" : "currentColor");

return svg.node();
}
Insert cell
today = new Date(Date.UTC(2020, 3, 12))
Insert cell
data = [
{name: "Alabama", date: "April 4 at 5 p.m."},
{name: "Alaska", date: "March 28 at 5 p.m."},
{name: "Arizona", date: "March 31 at 5 p.m."},
{name: "Arkansas", date: null},
{name: "California", date: "March 19"},
{name: "Colorado", date: "March 26 at 6 a.m."},
{name: "Connecticut", date: "March 23 at 8 p.m."},
{name: "Delaware", date: "March 24 at 8 a.m."},
{name: "District of Columbia", date: "April 1 at 12:01 a.m."},
{name: "Florida", date: "April 3 at 12:01 a.m."},
{name: "Georgia", date: "April 3"},
{name: "Hawaii", date: "March 25 at 12:01 a.m."},
{name: "Idaho", date: "March 25 at 1:30 p.m."},
{name: "Illinois", date: "March 21 at 5 p.m."},
{name: "Indiana", date: "March 24 at 11:59 p.m."},
{name: "Iowa", date: null},
{name: "Kansas", date: "March 30 at 12:01 a.m."},
{name: "Kentucky", date: "March 26 at 8 p.m."},
{name: "Louisiana", date: "March 23 at 5 p.m."},
{name: "Maine", date: "April 2 at 12:01 a.m."},
{name: "Maryland", date: "March 30 at 8 p.m."},
{name: "Massachusetts", date: "March 24 at 12 p.m."},
{name: "Michigan", date: "March 24 at 12:01 a.m."},
{name: "Minnesota", date: "March 27 at 11:59 p.m."},
{name: "Mississippi", date: "April 3 at 5 p.m."},
{name: "Missouri", date: "April 6 at 12:01 a.m."},
{name: "Montana", date: "March 28 at 12:01 a.m."},
{name: "Nebraska", date: null},
{name: "Nevada", date: "April 1"},
{name: "New Hampshire", date: "March 27 at 11:59 p.m."},
{name: "New Jersey", date: "March 21 at 9 p.m."},
{name: "New Mexico", date: "March 24 at 8 a.m."},
{name: "New York", date: "March 22 at 8 p.m."},
{name: "North Carolina", date: "March 30 at 5 p.m."},
{name: "North Dakota", date: null},
{name: "Ohio", date: "March 23 at 11:59 p.m."},
{name: "Oklahoma", date: null, partial: true},
{name: "Oregon", date: "March 23"},
{name: "Pennsylvania", date: "April 1 at 8 p.m."},
{name: "Rhode Island", date: "March 28"},
{name: "South Carolina", date: "April 7 at 5 p.m."},
{name: "South Dakota", date: null},
{name: "Tennessee", date: "March 31 at 11:59 p.m."},
{name: "Texas", date: "April 2 at 12:01 a.m."},
{name: "Utah", date: null, partial: true},
{name: "Vermont", date: "March 25 at 5 p.m."},
{name: "Virginia", date: "March 30"},
{name: "Washington", date: "March 23"},
{name: "West Virginia", date: "March 24 at 8 p.m."},
{name: "Wisconsin", date: "March 25 at 8 a.m."},
{name: "Wyoming", date: null, partial: true}
]
.map(({date, ...rest}) => ({...rest, start: parseDate(date)}))
.sort((a, b) => d3.ascending(a.start === null, b.start === null) || d3.descending(!!a.partial, !!b.partial) || d3.ascending(a.start, b.start))
Insert cell
parseDate = {
const format1 = d3.utcParse("%B %d");
const format2a = d3.utcParse("%B %d at %I p.m.");
const format2b = d3.utcParse("%B %d at %I:%M p.m.");
const format3a = d3.utcParse("%B %d at %I a.m.");
const format3b = d3.utcParse("%B %d at %I:%M a.m.");
return x => {
let date = null;
if (date = format1(x));
else if (date = format2a(x) || format2b(x)) date.setUTCHours(date.getUTCHours() + 12);
else if (date = format3a(x) || format3b(x));
if (date !== null) date.setUTCFullYear(2020);
return date;
};
}
Insert cell
x = d3.scaleUtc()
.domain([d3.min(data, d => d.start), today])
.rangeRound([margin.left, width - margin.right])
Insert cell
y = d3.scalePoint()
.domain(data.map(d => d.name))
.rangeRound([margin.top, height - margin.bottom])
.padding(1)
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${margin.top})`)
.call(d3.axisTop(x).ticks(width / 80))
.call(g => g.select(".domain").remove())
.call(g => g.append("g")
.attr("stroke", "white")
.attr("stroke-width", 2)
.selectAll("line")
.data(x.ticks(d3.utcDay))
.join("line")
.attr("x1", d => 0.5 + x(d))
.attr("x2", d => 0.5 + x(d))
.attr("y2", height - margin.bottom - margin.top))
Insert cell
margin = ({top: 24, right: 41, bottom: 0, left: 60})
Insert cell
height = data.length * 14
Insert cell
d3 = require("d3@5")
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