Skip to content

Commit

Permalink
add new files from other repo
Browse files Browse the repository at this point in the history
  • Loading branch information
cjwit committed Jun 26, 2020
1 parent 4c350b2 commit 36c588b
Show file tree
Hide file tree
Showing 13 changed files with 9,237 additions and 197 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ I wouldn't depend on this for much, it's mostly a chance for me (Christopher Wit

## Next

* Add hover for data
* Automate Y scale change from log to linear
* Fix issue in python code that creates the wrong length title line
* Check for hover issues
* Add doubling time lines
279 changes: 279 additions & 0 deletions averages.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>COVID-19 statistics by US state - Witulski</title>
<style> /* set the CSS */

body {
font-family: Arial;
padding: 50px 5%;
}

svg {
display: block;
margin: 0 auto;
}

path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}

.axis path,
.axis line {
fill: none;
stroke: lightgrey;
stroke-width: 1;
shape-rendering: crispEdges;
}

.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
opacity: 0.4;
}

.title {
font-size: 16px;
font-weight: bold;
}

.tooltip {
line-height: 1;
padding: 12px;
background: grey;
color: white;
position: absolute;
text-align: left;
font: 14px sans-serif;
font-weight: bold;
}

</style>
<body>

<center>
<h1>COVID-19 seven day averages of new cases by US states</h1>
<p><a href="index.html">See cases</a> | <a href="deaths.html">See deaths</a> | <a href="scaled_averages.html">See seven day averages scaled by population</a></p>
<p>Click state names to show their graphs | Developed by <a href="http://cjwit.github.io">Christopher Witulski</a> | Last updated on <span id="date">June 26, 2020</span></p>
</center>

<!-- load the d3.js library -->
<script src="src/d3.min.js"></script>

<script>

// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 100, bottom: 320, left: 100},
width = 800 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;

// Set the ranges
// Change Y to scale.linear() for linear scale
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);

var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width, 0, 0)
.tickFormat(function(d) {return y.tickFormat(5,d3.format(",d"))(d)})
.ticks(5);

// Define the line
var dataline = d3.svg.line()
.x(function(d,i) { return x(i); })
.y(function(d) { return y(d); });

// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");

var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);

// Get the data
d3.csv("formattedCovidAverages.csv")
.row(function(d) {
var cases = Object.keys(d).map(function(key) {
if (!isNaN(d[key])) {
return d[key];
}
})
return {state: d.state, cases: cases };
})
.get(function(error, data) {

// Scale the range of the data
// FIXME: get max value, not registering if statement
x.domain([0, data[0].cases.length]);
y.domain([0, d3.max(data, function(d) {
// var maxCases = 0;
// for (var i = 0; i < d.cases.length - 1; i++) {
// if (d.cases[i] > maxCases) {
// maxCases = d.cases[i];
// // console.log(d.state, d.cases[i], maxCases);
// }
// }
// console.log(maxCases);
return 10000;
})]);

// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {
return d.state;
})
.entries(data);

// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);

// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)

svg.append('text')
.attr('x', 10)
.attr('y', -10)
.attr('class', 'title')
.text('Seven day rolling average')

var color = d3.scale.category10(); // set the color scale

// Loop through each symbol / key
dataNest.forEach(function(d, i) {

// sending just the list of numbers to the line()
svg.append("path")
.attr("class", "line")
.style("stroke", function() {
return d.color = color(d.key);
})
.attr("id", 'tag'+d.key.replace(/\s+/g, ''))
.style('opacity', 0.4)
.attr("d", dataline(d.values[0].cases))
.on("mouseover", function() {

// color label on mouseover
d3.select('#label'+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style("opacity", 1)

// color line on mouseover
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style("opacity", 1)
.style('stroke-width', 8);

// build tooltip
// console.log('in path', d.key, d.values[0].cases)
tooltip.transition()
.duration(100)
.style("opacity", .9);

tooltip.html(function() {
var casesArray = d.values[0].cases;
var maxcases = 0;
for (i = 0; i < casesArray.length; i++) {
if (Number(casesArray[i]) > maxcases) {
maxcases = Number(casesArray[i])
}
}
// FIXME: why is the last case undefined?
return d.key + ", max: " + Math.round(maxcases) + ", current: " + Math.round(Number(casesArray[casesArray.length - 2]));
})
.style('left', (d3.event.pageX - 50) + 'px')
.style('top', (d3.event.pageY - 80) + "px");
})
.on("mouseout", function() {
tooltip.transition()
.duration(100)
.style("opacity", 0);

if (!d.active) {
d3.select('#label'+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style("opacity", .4)
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style('opacity', 0.4)
.style('stroke-width', 2);
}
});

// Make space for the legend
// calculate individually based on i to place instead of working through this
legendWidthSpacing = width/4
d.active = false

// Build legend
svg.append("text")
.attr("x", (legendWidthSpacing/2 + Math.floor(i/14) * legendWidthSpacing))
.attr("y", height + 40 + (i%14 * 20))
.attr("class", "legend")
.attr("id", 'label'+d.key.replace(/\s+/g, ''))
.style("fill", function() {return d.color = color(d.key); })
.on("mouseover", function() {
if (!d.active) {
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style('opacity', 1)
.style('stroke-width', 4);
}
})
.on("mouseout", function() {
if (!d.active) {
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style('opacity', 0.1)
.style('stroke-width', 2);
}
})
.on("click", function () {
var newOpacity = d.active ? 0.4 : 1;
var newStrokeWidth = d.active ? 2 : 4;
d3.select("#label"+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style('opacity', newOpacity);
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(200)
.style('opacity', newOpacity)
.style('stroke-width', newStrokeWidth);
d.active = !d.active
})
.text(d.key);
});

});

</script>

<p>
This chart tracks the seven day average of cases of COVID-19 across the USA. The data comes from the New York Times (see <a href = 'https://www.nytimes.com/article/coronavirus-county-data-us.html?action=click&module=Spotlight&pgtype=Homepage'>here for more information</a> and <a href = 'https://github.com/nytimes/covid-19-data'>here for the GitHub data</a>). The idea for the chart comes from <a href = "https://ourworldindata.org/grapher/covid-confirmed-cases-since-100th-case">this similar one from Our World in Data</a>.
</p>
<p>
I wouldn't depend on this for much, it's mostly a chance for me to see a graph that I wish were easier to find while checking to see if I remember how to use D3.js.
</p>
<script data-goatcounter="https://witulski.goatcounter.com/count"
async src="//gc.zgo.at/count.js"></script>
</body>
Loading

0 comments on commit 36c588b

Please sign in to comment.