Published
Edited
Jan 19, 2021
4 stars
Insert cell
Insert cell
chart = {
const svg = d3.create('svg')
.attr('viewBox', [0, 0, width, height]);
svg.append('g').call(xAxis);
svg.selectAll('.line-decade')
.data(x.ticks())
.join('line')
.attr('class', 'line-decade')
.attr('x1', d => x(d))
.attr('x2', d => x(d))
.attr('y1', 10)
.attr('y2', height - margin.top)
.attr('stroke-width', 1)
.attr('stroke', 'lightgray');
svg.selectAll('.label-region')
.data(region)
.join('text')
.attr('class', 'label-region')
.attr('x', 0)
.attr('y', d => y(d))
.attr('text-align', 'right')
.attr('alignment-baseline', 'right')
.text(d => d);
const simulation = d3.forceSimulation(data)
.force('x', d3.forceX((d) => x(d.always)).strength(5))
.force('y', d3.forceY((d) => y(d.region)))
.force('collide', d3.forceCollide(radius + padding))
.stop();
svg.selectAll('circle')
.data(data)
.join('circle')
.attr('cx', (d) => x(d.always))
.attr('cy', (d) => y(d.region))
.attr('r', (d) => size(d.population))
.attr('fill', (d) => color(d.region))
.attr('opacity', .7);
// select all rect
svg.selectAll("circle")
.on("mouseover", function(d) {
// change the selection style
d3.select(this)
.attr('stroke-width', '2')
.attr("stroke", "black");
// make the tooltip visible and update its text
tooltip
.style("visibility", "visible")
.html(`<b>County:</b> ${d.county}, ${d.state}<br><b>'Always' wears mask:</b> ${d.always}%<br><b>Population:</b> ${d3.format(".2s")(d.population)}`)
})
.on("mousemove", function() {
tooltip
.style("top", d3.event.pageY - 10 + "px")
.style("left", d3.event.pageX + 10 + "px");
})
.on("mouseout", function() {
// change the selection style
d3.select(this).attr('stroke-width', '0');

tooltip.style("visibility", "hidden");
});
for(let i = 0; i < 100; i++) {
simulation.tick();

svg.selectAll('circle')
.data(data)
.attr('cx', (d) => d.x)
.attr('cy', (d) => d.y);

yield svg.node();
}
}
Insert cell
Insert cell
color = d3.scaleOrdinal()
.domain(region)
.range(d3.schemeTableau10)
Insert cell
y = d3.scaleBand()
.domain(region)
.range([height + margin.bottom, margin.top])
Insert cell
xAxis = g => g
.attr('transform', `translate(0,${height - margin.top})`)
.call(d3.axisBottom(x))
Insert cell
x = d3.scaleLinear()
.domain([0,100])
.nice()
.range([margin.left, width - margin.right])
Insert cell
size = d3.scaleLinear()
.domain(popExtent)
.nice()
.range([3, 20])
Insert cell
popExtent = {
const bounds = data.map((d) => d.population).sort(d3.ascending);
return [bounds[0], bounds[bounds.length - 1]];
}
Insert cell
dataExtent = {
const bounds = data.map((d) => d.always).sort(d3.ascending);
return [bounds[0], bounds[bounds.length - 1]];
}
Insert cell
region = ['Northeast', 'South', 'West', 'Midwest']
Insert cell
data = rawData
Insert cell
rawData = {
return d3.csvParse(
await FileAttachment('prepared_mask_data.csv').text(),
d => ({
always: d.ALWAYS,
never: d.NEVER,
county: d['county.name'],
state: d['state.name'],
region: d.regions,
population: +d.pop_2015
})
);
}
Insert cell
tooltip = d3
.select("body")
.append("div")
.attr("class", "svg-tooltip")
.style("position", "absolute")
.style("visibility", "hidden");
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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