Published
Edited
Mar 25, 2021
2 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof CountyMap = {
let value = null;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, 975, 610])
// svg.append("g")
// .attr("transform", "translate(610,20)")
// .append(() => legend({color:colorScale, title: `% Difference in ${dataInfo.variable}`, width: 260 }));
// draw counties
svg.append("g")
.selectAll("path")
.data(topojson.feature(geography, geography.objects.counties).features)
.enter().append("path")
.attr("d", path)
// !!!! HERE !!!! This is the conditional check for the population and death count threshholds
.attr("fill",
data =>
((_.find(populationData, feature => +feature.GEOID == +data.id)[populationVariable] > topQuantilePop)
&&
(_.find(normalizedDeathData, feature => +feature.fips == +data.id)[currentDate] > topQuantileDeath))
?
'rgb(0,0,0)'
:
'rgb(240,240,240)'
)
.attr('id', data => data.properties.name)
.attr('class', 'county');

// state outline
svg.append("g")
.selectAll("path")
.data(topojson.feature(geography, geography.objects.states).features)
.enter().append("path")
.attr("d", path)
.attr("fill", 'none')
.attr("stroke", d => 'white')
.attr('id', d=> d.properties.name)
.attr('class', 'state');
// state background
svg.append("path")
.datum(topojson.mesh(geography, geography.objects.states, (a, b) => a !== b))
.attr("fill", "none")
.attr("stroke", d => 'white')
.attr("stroke-linejoin", "round")
.attr("pointer-events", "none")
.attr("d", path);
// // thanks! https://observablehq.com/@duynguyen1678/choropleth-with-tooltip
const tooltip = svg.append("g")

svg
.selectAll(".county")
.on("touchmove mousemove", function(event, d) {
tooltip.call(
callout,
`${d.properties.name}
`
);
tooltip.attr("transform", `translate(${d3.pointer(event, this)})`);
d3.select(this)
.raise();
})
.on("touchend mouseleave", function() {
tooltip.call(callout, null);
d3.select(this)
.attr("stroke", null)
.lower();
});

const outline = svg.append("path")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-linejoin", "round")
.attr("pointer-events", "none");

return Object.assign(svg.node(), {value: null});
}
Insert cell
Insert cell
cdcDeathData = d3.csv(`https://gist.githubusercontent.com/nofurtherinformation/977077f4e1874333f570515007537ebb/raw/fde4cc565c4e6ce8e4200ef63fc23438792ac9e9/cdc_deaths.csv`)
Insert cell
rawPopulationData = d3.csv('https://gist.githubusercontent.com/nofurtherinformation/28547271cf378dc19984c9aeb4673b7f/raw/6614436c28e4c0b11d915b1216e1b1cb09ec190f/DS01_2018_C.csv')
Insert cell
populationData = {
const cdcGeoids = cdcDeathData.map(row => +row.fips)
return rawPopulationData.filter(row => cdcGeoids.includes(+row['GEOID']))
}
Insert cell
geography = fetch('https://cdn.jsdelivr.net/npm/us-atlas@3/counties-albers-10m.json').then(r => r.json())
Insert cell
Insert cell
// get the columns from the first data to select
populationColumns = Object.keys(populationData[0]).slice(3,)
Insert cell
// map out the population data values based on the populationVariable
populationVariableData = _.map(populationData, o => +o[populationVariable]).sort((a, b) => a - b)
Insert cell
Insert cell
topQuantilePop = {
const response = await gdaProxy.QuantileBreaks(+quantileNumbers, populationVariableData)
return response.bins.breaks[+quantileNumbers-1]
}
Insert cell
Insert cell
dates = Object.keys(cdcDeathData[1001])
Insert cell
// list of date indices
dateIndices = Array.from({length: Object.keys(cdcDeathData[1001]).length-1}, (_, i) => i+1)
Insert cell
currentDate = dates[dateSelector]
Insert cell
Insert cell
normalizedDeathData = {
// declare return data object
let returnData = [];
// loop through CDC rows of counties
for (let i=0; i<cdcDeathData.length; i++){
// add a temporary object for this county
const currentGEOID = cdcDeathData[i].fips
let tempObj = {
'fips':currentGEOID
}
// find the county population data
const countyData = _.find(populationData, feature => +feature.GEOID == +currentGEOID)
// if missing population data, skip
if (countyData === undefined) {
continue
}
const countyPopulation = countyData?.totPopE
// list of date columns
const tempKeys = Object.keys(cdcDeathData[i]).slice(1,)
// loop through date columns to calculate 7-day average of deaths per 100k
for (let n=0; n<tempKeys.length; n++){
tempObj[tempKeys[n]] = (cdcDeathData[i][tempKeys[n]]/countyPopulation)*100_000
}
returnData.push(tempObj)
}
return returnData
}
Insert cell
// // map out the population data values based on the populationVariable
deathDataCurrentDate = _.map(normalizedDeathData, feature => +feature[currentDate]).sort((a, b) => a - b)
Insert cell
topQuantileDeath = {
const response = await gdaProxy.QuantileBreaks(+quantileNumbers, deathDataCurrentDate)
return response.bins.breaks[+quantileNumbers-1]
}
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

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