Published
Edited
Jul 29, 2021
1 fork
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function init(all) {

d3.select('.yAxis')
.call(d3.axisLeft(y))
.attr('opacity', 1)

d3.select('.xAxis')
.call(d3.axisBottom(x))
.attr('opacity', 1)
if(d3.select('.axis-title').empty()) {
d3.select('.xAxis')
.append('text')
.attr('class', 'axis-title')
.attr('x', margin.left + (width - margin.left - margin.right) / 2)
.attr('y', margin.bottom * .7) // Relative to the x axis.
}
d3.select('.axis-title').text('Date');
d3.select('.day-title')
.transition().duration(1000)
.attr('opacity', 0);

svg.selectAll(".line")
.transition()
.duration(2000)
.attr("stroke-width", 5)
.attr("stroke-linejoin", 'butt')
.attr("stroke-linecap", "butt")
.attr("d", line)
.on("end", function() {
if(all) {
update1(all)
}
});

// TEXT AND BUTTONS
d3.selectAll('button')
.classed('active', false)
d3.select("#default")
.classed('active', true)
d3.select('.top-text')
.html('<span>This is a line chart showing <strong>deaths from COVID-19 over time</strong>. <br>The US recently passed 500,000 deaths.</span>')
}
Insert cell
function update1(all) {
d3.select('.yAxis')
.call(d3.axisLeft(y1))
.attr('opacity', 1)
d3.select('.xAxis')
.call(d3.axisBottom(x))
d3.select('.axis-title').text('Date');
d3.select('.day-title')
.transition().duration(1000)
.attr('opacity', 0);
svg.selectAll(".line")
.transition()
.duration(2000)
.attr("stroke-width", 20)
.attr("stroke-linejoin", 'butt')
.attr("stroke-linecap", "butt")
.attr("d", line1)
.on("end", function() {
if(all) {
update2(all)
}
});
// BUTTONS AND TEXT
d3.selectAll('button')
.classed('active', false)
d3.select("#update1")
.classed('active', true)

d3.select('.top-text')
.html("<span>We can instead visualize the <strong>number of days</strong> passed before reaching the next 100,000 deaths. Here, each bar's length corresponds to the number of days it took to reach the next 100,000 deaths (e.g. <span class='label' style='background:steelblue; color:white;'>0 to 100k</span>).</span>")
}
Insert cell
function update2(all) {
svg.selectAll(".line")
.transition()
.duration(2000)
.attr('stroke-width', 20)
.attr("stroke-linejoin", 'butt')
.attr("stroke-linecap", "butt")
.attr("d", line2)
.on("end", function() {
if(all) {
update3(all)
}
});
// d3.select('.yAxis')
// .transition().duration(2000)
// .attr('opacity', 0)

// d3.select('.xAxis')
// .transition().duration(2000)
// .attr('opacity', 0)
d3.select('.xAxis')
.call(d3.axisBottom(x2).ticks(width / 80).tickSizeOuter(0))
d3.select('.axis-title')
.text('Days');
d3.select('.day-title')
.transition().duration(1000)
.attr('opacity', 0);
// BUTTONS AND TEXT
d3.selectAll('button')
.classed('active', false)
d3.select("#update2")
.classed('active', true)

d3.select('.top-text')
.html("<span>When we align each of the bars, we notice deaths have been accelerating, as the bars' lengths have gotten progressively shorter for each 100,000 death threshold.</span>")
}
Insert cell
function update3(all) {

if(d3.select('.day-title').empty()) {
svg.append('text')
.text('34 days')
.attr('class', 'day-title')
.attr('x', x2(382))
.attr('y', height / 2)
.attr('fill', 'white')
}
d3.select('.day-title')
.transition().duration(1000)
.attr('opacity', 1)
svg.selectAll('.line')
.on("mouseover", function(d, i){
return tooltip.style("visibility", "visible")
.text(`${i[0].name}: ${i.length} days`);
})
.on("mousemove", function(event){
return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");
})
.on("mouseout", function(){
return tooltip.style("visibility", "hidden");
});
svg.selectAll(".line")
.transition().duration(2000)
.attr("d", line2)
.attr("stroke-width", height * .75)
d3.select('.yAxis')
.transition().duration(2000)
.attr('opacity', 0)
d3.select('.xAxis')
.call(d3.axisBottom(x2).ticks(width / 80).tickSizeOuter(0))

if(d3.select('.axis-title').empty()){
d3.select('.xAxis')
.append('text')
.attr('class', 'axis-title')
.text('Days')
.attr('opacity', 1)
.attr('x', margin.left + (width - margin.left - margin.right) / 2)
.attr('y', margin.bottom * .7) // Relative to the x axis.
}
// BUTTONS AND TEXT
d3.selectAll('button')
.classed('active', false)
d3.select("#update3")
.classed('active', true)
d3.select('.top-text')
.html("<span>The United States' <span class='label' style='background:#9467BD; color:white;'>most recent 100,000 deaths</span> occurred more rapidly (34 days) than any series of 100,000 deaths prior.</span>")
}
Insert cell
tooltip = d3.select("body").append("div")
.attr("class", "svg-tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
Insert cell
y1 = d3.scalePoint()
.padding(.25)
.domain(data.filter(d => d.name != 'Sixth 100k').map(d => d.name))
.range([height - margin.bottom, margin.top])
Insert cell
x2 = d3.scaleLinear()
.domain([0, data.length])
.range([margin.left, width - margin.right])
Insert cell
line1 = d3.line()
.defined(d => !isNaN(d.deaths))
.x(d => x(d.date))
.y(d => y1(d.name))
Insert cell
line2 = d3.line()
.defined(d => !isNaN(d.deaths))
.x(d => x(d.date))
.y(height / 2)
Insert cell
d3.select("#default")
.on("click", function() {
init(false)
});
Insert cell
d3.select("#init")
.on("click", function() {
init(true);
});
Insert cell
d3.select("#update1")
.on("click", function() {
update1();
});
Insert cell
d3.select("#update2")
.on("click", function() {
update2();
});
Insert cell
d3.select("#update3")
.on("click", function() {
update3();
});
Insert cell
Insert cell
Insert cell
data = raw.filter(d => d.deaths < 500001)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
specific = html`<style>
.axis-title {
fill: #000;
font-size: 12px;
text-anchor: middle;
}

.labels {
fill: #000;
font-size: 12px;
}

.active {
background: #cecece;
color: black;
transition: 500ms all ease;
box-shadow: none;
}
.label {
padding: 5px;
border-radius: 3px;
}

.yAxis path {
stroke: none;
}

.tick line {
stroke: none;
}

.day-title {
font-size: 12px;
font-weight: 300;
text-anchor: middle;
pointer-events: none;
}

@media screen and (max-width: 768px) {
.day-title {
display: none;
}
}
.svg-tooltip {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background: rgba(69,77,93,.9);
border-radius: .1rem;
color: #fff;
display: block;
font-size: 11px;
max-width: 320px;
padding: .2rem .4rem;
position: absolute;
text-overflow: ellipsis;
white-space: pre;
z-index: 300;
visibility: hidden;
}
</style>`
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