With the world going through the COVID-19 pandemic, and given that I’m in NYC, which is the epicenter of the outbreak here in the U.S., I thought it would be a fun exercise to track the number of cases and deaths in NYC. There are a lot of great visualizations out there, and I’ve been checking the COVID-19 Dashboard by JHU CSSE , but I wanted an easier, faster way to just see the information for NYC.
I found a data source from New York Times that gets updated daily on GitHub (https://github.com/nytimes/covid-19-data ). From this data, I used D3.js (which I learned in my course CSE 6242 Data Analytics and Visualization at Georgia Tech) to create a simple interactive plot that tracks the number of confirmed COVID-19 cases and deaths in NYC. Check it out here!
Here’s the code, written with D3.js v5:
<! DOCTYPE html >
< html >
< head >
< meta http - equiv = "Content-Type" content = "text/html;charset=utf-8" >
< title > COVID - 19 in NYC < /title>
<script type="text/ javascript " src=" https :/ / d3js . org / d3 . v5 . min . js "></script>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
font: 10px " Helvetica Neue ", Helvetica, Arial, sans-serif;
position: relative;
}
text {
font-family: arial;
font-size: 12px;
}
path.line {
fill: none;
stroke: red;
stroke-width: 2px;
}
.overlay {
fill: none;
pointer-events: all;
}
.axis path,
.axis line {
fill: none;
stroke: slategray;
shape-rendering: crispEdges;
}
.focus circle {
fill: none;
stroke: black;
}
.tooltip {
width: 94px;
padding: 4px 10px;
border: 1px solid #aaa;
border-radius: 4px;
box-shadow: 2px 2px 4px rgba(0,0,0,0.3);
position: absolute;
background-color: white;
font-size: 14px;
pointer-events: none;
-webkit-transition: all 0.25s;
-moz-transition: all 0.25s;
-ms-transition: all 0.25s;
-o-transition: all 0.25s;
transition: all 0.25s;
}
.tooltip div {
margin: 3px 0;
}
.tooltip-date, .tooltip-likes {
font-weight: bold;
}
.grid line {
stroke: lightgrey;
stroke-opacity: 0.6;
shape-rendering: crispEdges
}
.grid path {
stroke-width: 0;
</style>
</head>
<body>
<script type=" text / javascript ">
var parseDate = d3.timeParse(" % Y -% m -% d "),
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(" , "),
dateFormatter = d3.timeFormat(" % m /% d /% y ");
var margin = {left: 50, right: 20, top: 20, bottom: 50 };
var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var max = 0;
var xNudge = 50;
var yNudge = 20;
var tooltip = d3.select(" body ").append(" div ")
.attr(" class ", " tooltip ")
.style(" display ", " none ");
//Function for converting CSV values from strings to Dates and numbers
var rowConverter = function(d) {
return {
date: parseDate(d.date),
county: d.county,
cases: parseFloat(d.cases),
deaths: parseFloat(d.deaths)
};
}
d3.dsv(" , ", " https :/ / raw . githubusercontent . com / nytimes / covid - 19 - data / master / us - counties . csv ", rowConverter).then(function(data) {
dataset = data.filter(function(d) {
return d[" county "] === " New York City "
});
max = d3.max(dataset, function(d) { return d.cases; });
minDate = d3.min(dataset, function(d) {return d.date; });
maxDate = d3.max(dataset, function(d) { return d.date; });
var y = d3.scaleLinear()
.domain([1,max])
.range([height,0]);
var x = d3.scaleTime()
.domain([minDate,maxDate])
.range([0,width]);
var yAxis = d3.axisLeft(y);
var xAxis = d3.axisBottom(x);
var line = d3.line()
.x(function(d){ return x(d.date); })
.y(function(d){ return y(d.cases); })
var line2 = d3.line()
.x(function(d){ return x(d.date); })
.y(function(d){ return y(d.deaths); })
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(8)
}
function make_y_gridlines() {
return d3.axisLeft(y)
.ticks(5)
}
var svg = d3.select(" body ").append(" svg ").attr(" id "," svg ").attr(" height "," 100 % ").attr(" width "," 100 % ");
var chartGroup = svg.append(" g ").attr(" class "," chartGroup ").attr(" transform "," translate ( "+xNudge+" , "+yNudge+" ) ");
chartGroup.append(" path ")
.style(" stroke "," blue ")
.style(" fill "," none ")
.style(" stroke - width "," 2 px ")
.attr(" d ",function(d){ return line(dataset); })
chartGroup.append(" path ")
.style(" stroke "," red ")
.style(" fill "," none ")
.style(" stroke - width "," 2 px ")
.attr(" d ",function(d){ return line2(dataset); })
var focus = chartGroup.append(" g ")
.attr(" class ", " focus ")
.style(" display ", " none ");
focus.append(" circle ")
.attr(" r ", 5);
focus.append(" path ")
.style(" stroke ", " black ")
.style(" stroke - width ", " 1 px ")
.style(" opacity ", " 0 ");
var tooltipDate = tooltip.append(" div ")
.attr(" class ", " tooltip - date ");
var tooltipCases = tooltip.append(" div ");
tooltipCases.append(" span ")
.attr(" class ", " tooltip - title ")
.text(" Cases : ");
var tooltipDeaths = tooltip.append(" div ");
tooltipDeaths.append(" span ")
.attr(" class ", " tooltip - title ")
.text(" Deaths : ");
var tooltipCasesValue = tooltipCases.append(" span ")
.attr(" class ", " tooltip - cases ");
var tooltipDeathsValue = tooltipDeaths.append(" span ")
.attr(" class ", " tooltip - deaths ");
chartGroup.append(" rect ")
.attr(" class ", " overlay ")
.attr(" width ", width)
.attr(" height ", height)
.on(" mouseover ", function() { focus.style(" display ", null); tooltip.style(" display ", null); })
.on(" mouseout ", function() { focus.style(" display ", " none "); tooltip.style(" display ", " none "); })
.on(" mousemove ", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(dataset, x0, 1),
d0 = dataset[i - 1],
d1 = dataset[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr(" transform ", " translate ( " + x(d.date) + " , " + y(d.cases) + " ) ");
tooltip.attr(" style ", " left :" + (x(d.date) + 64) + " px ; top :" + y(d.cases) + " px ; ");
tooltip.select(" . tooltip - date ").text(dateFormatter(d.date));
tooltip.select(" . tooltip - cases ").text(formatValue(d.cases));
tooltip.select(" . tooltip - deaths ").text(formatValue(d.deaths));
}
chartGroup.append(" g ")
.attr(" class "," axis x ")
.attr(" transform "," translate ( 0 , "+height+" ) ")
.call(xAxis);
chartGroup.append(" g ")
.attr(" class "," axis y ")
.call(yAxis);
//Create title
chartGroup.append(" text ")
.attr(" x ", (width / 2))
.attr(" y ", 16)
.attr(" text - anchor ", " middle ")
.style(" font - size ", " 16 px ")
.text(" COVID - 19 Confirmed Cases and Deaths in NYC ");
chartGroup.append(" g ")
.attr(" class "," grid ")
.attr(" transform "," translate ( 0 , " + height + " ) ")
.style(" stroke - dasharray ",(" 3 , 3 "))
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
chartGroup.append(" g ")
.attr(" class "," grid ")
.style(" stroke - dasharray ",(" 3 , 3 "))
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
)
});
</script>
</body>
</html>