Public
Edited
Dec 15, 2023
Insert cell
Insert cell
md
`Note the scale is based on the distribution of cases on the last date where data is available.`
Insert cell
viewof bins = slider({
min: 3,
max: 9,
step: 1,
value: 9,
title: "Quantiles",
description: "Number of cuts to use when binning the data."
})
Insert cell
stateData = (async function() {
const response = await FileAttachment("state_to_FIPS_crosswalk@1.csv").text();
const rows = d3.csvParse(response);
const uniqueNames = [...new Set(rows.map(d => d.STATE_NAME))];
return uniqueNames;
})();
Insert cell
viewof stateSelect = Inputs.select(["Iowa"].concat(stateData), {label: "Select a State"})
Insert cell
// fipsSelect contains all fips codes for selected state
fipsSelect = (async function() {
const response = await FileAttachment("state_to_FIPS_crosswalk@1.csv").text();
const rows = d3.csvParse(response);
// Create dictionary of COUNTY_FIPS and STATE_NAME
const countyFIPSDict = {};
rows.forEach(row => {
countyFIPSDict[row.COUNTY_FIPS] = row.STATE_NAME;
});
// Filter COUNTY_FIPS using the stateSelect and the STATE_NAME column
const stateFilter = await stateSelect
const fipsSelect = Object.keys(countyFIPSDict).filter(fips => countyFIPSDict[fips] === stateSelect);

return fipsSelect;
})();
Insert cell
// stateIDSelect contains all state codes for selected state
stateIDSelect = (async function() {
const response = await FileAttachment("state_to_FIPS_crosswalk@1.csv").text();
const rows = d3.csvParse(response);
// Create dictionary of STATE_NAME and STATE_CODE
const stateCodeDict = {};
rows.forEach(row => {
stateCodeDict[row.STATE_NAME] = row.STATE_CODE;
});
// Get the STATE_CODE based on the stateSelect
const stateFilter = await stateSelect
const stateCode = stateCodeDict[stateFilter];

return stateCode;
})();

Insert cell
viewof var1_select = Inputs.select(["covid_confirmed"].concat(data_variables), {label: "Select variable"})
Insert cell
viewof date = Scrubber(dates.map(x => d3.timeParse("%Y-%m-%d")(x)), {
autoplay: false,
loop: false,
delay: 300,
format: date => date.toLocaleString("en", {year: "numeric", month: "long", day: "numeric"})
})
Insert cell
map = {
// Create SVG
var svg = d3.select(DOM.svg(width, height));

// Create map
var countyMap = svg.append("g")
.selectAll("path")
.data(counties.features)
.enter()
.append("path")
.attr("d", path)
.attr("fill", "#cccc")
.attr("stroke", "white")
.attr("stroke-width", 0.1)
.on("mouseover", handleMouseOver)
.on("mouseout", handleMouseOut);

// Draw the state boundaries (could do this in a cleaner way with topoJSON)
svg.append("g")
.selectAll("path")
.data(states.features)
.enter()
.append("path")
.attr("d", path)
.attr("stroke", "white")
.attr("stroke-width", 1)
.attr("fill", "none");

// Add legend
var legendGroup = svg.append("g")
.attr("transform", "translate("+50+","+50+")")
.attr("width", 400)
.attr("height", 60);

var legendElement = legendGroup.append(() => legend({
color,
title: var1_select,
ticks: bins,
tickFormat: ",.2f",
width: 400,
height: 60
}));

// Update the fill based on date scrubber
function update(date) {
countyMap.attr("fill", function(d) {
var map_var = data.get(d.properties["COUNTY_FIPS"] + " " + dateToString(date));

if (map_var) {
var fcolor = color(map_var);
} else {
var fcolor = "#cccc";
}

return fcolor;
});
}

// Function to handle legend hover
function handleLegendHover(d, i) {
// Get the corresponding bin range from the color scale
var range = color.range();
var binIndex = i;
var binColor = range[binIndex];

// Highlight the corresponding selection on the map
countyMap.attr("fill", function(d) {
var map_var = data.get(d.properties["COUNTY_FIPS"] + " " + dateToString(date));

if (map_var) {
var fcolor = (color(map_var) === binColor) ? binColor : "#cccc";
} else {
var fcolor = "#cccc";
}

return fcolor;
});
}

// Function to handle legend mouseout
function handleLegendMouseOut() {
// Restore the original fill colors on the map
countyMap.attr("fill", function(d) {
var map_var = data.get(d.properties["COUNTY_FIPS"] + " " + dateToString(date));

if (map_var) {
var fcolor = color(map_var);
} else {
var fcolor = "#cccc";
}

return fcolor;
});
}

// Function to handle mouseover event
function handleMouseOver(d) {
// Example: Change fill color on hover
d3.select(this)
.attr("fill", "red");
// Show the tooltip
var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("opacity", 0)
.html("County: " + d.properties["NAME"] + "<br/>Data: " + d.var1_select)
.style("left", d3.event.pageX + "px")
.style("top", d3.event.pageY + "px");
tooltip.transition()
.duration(300)
.style("opacity", 0.9);
}

// Function to handle mouseout event
function handleMouseOut(d) {
// Example: Revert fill color after hover
d3.select(this)
.attr("fill", function(d) {
var map_var = data.get(d.properties["COUNTY_FIPS"] + " " + dateToString(date));

if (map_var) {
var fcolor = color(map_var);
} else {
var fcolor = "#cccc";
}

return fcolor;
});
// Remove the tooltip
d3.select(".tooltip").remove();
}

// Function to handle legend click
function handleLegendClick(d, i) {
var binInfoBox = legendGroup.select(".bin-info-box");
if (binInfoBox.empty()) {
binInfoBox = legendGroup
.append("text")
.attr("class", "bin-info-box")
.attr("x", 500)
.attr("y", 30)
.style("font-size", "12px")
.style("fill", "black")
.text("You are viewing the bin information of this legend");
} else {
binInfoBox.remove();
}
}

// Attach event listeners to the legend elements
legendElement.selectAll("rect")
.on("mouseover", handleLegendHover)
.on("mouseout", handleLegendMouseOut)
.on("click", handleLegendClick);

return Object.assign(svg.node(), { update });
}

Insert cell
Insert cell
dates = (async function() {
const response = await FileAttachment("covid_demographics_data.csv").text();
const rows = d3.csvParse(response);
const uniqueDates = [...new Set(rows.map(d => d.date))];
return uniqueDates;
})();
Insert cell
rawCounties = FileAttachment("us_counties.json").json()
Insert cell
filteredCounties = (async function() {
// Filter COUNTY_FIPS using the stateSelect and the STATE_NAME column
let stateFilter = await stateIDSelect
let countiesSelect = rawCounties.features.filter(county => county.properties.STATE === stateFilter);
return countiesSelect;
})();
Insert cell
counties = JSON.parse(JSON.stringify(rawCounties))
Insert cell
counties.features = filteredCounties
Insert cell
rawStates = FileAttachment("us_states.json").json();
Insert cell
stateFeatures = (async function() {
// Filter COUNTY_FIPS using the stateSelect and the STATE_NAME column
let stateFilter = await stateSelect
let statesSelect = rawStates.features.filter(state => state.properties.NAME === stateFilter);
return statesSelect;
})();
Insert cell
states = JSON.parse(JSON.stringify(rawStates))
Insert cell
states.features = stateFeatures
Insert cell
data = (async function() {
const dataMap = d3.map();
const response = await FileAttachment("covid_demographics_data.csv").text();
const rows = d3.csvParse(response);
const data_vars = Object.keys(rows[0]);
// Retrieve the selected value from var1_select
const selectedValue = await var1_select;
rows.forEach(d => {
if (fipsSelect.includes(d.countyFIPS)) {
// Use the selected value to access the correct column from the CSV
const columnValue = +d[selectedValue];
dataMap.set(+d.countyFIPS + " " + d.date, columnValue);
}
});
return dataMap;
})();

Insert cell
data_variables = (async function() {
const response = await FileAttachment("covid_demographics_data.csv").text();
const data_rows = d3.csvParse(response);
const data_vars = Object.keys(data_rows[0]);
const filteredDataVars = data_vars.filter(variable => (
variable !== "Unnamed: 0" &&
variable !== "countyFIPS" &&
variable !== "date" &&
variable !== "month" &&
variable !== ""
))
return filteredDataVars;
})();
Insert cell
clean = (async function() {
const response = await FileAttachment("covid_demographics_data.csv").text();
// Retrieve the selected value from var1_select
const selectedValue = await var1_select;
const data = d3.csvParse(response, d => {
// Use the selected value to access the correct column from the CSV
const columnValue = +d[selectedValue];
return [+d.countyFIPS, d.date, columnValue];
});
return data;
})()
Insert cell
Insert cell
Insert cell
Insert cell
iowaProjection = d3.geoAlbers()
.center([0, 41.5])
.rotate([93, 0])
.parallels([29.5, 45.5])
.scale(6000)
.translate([width / 2, height / 2]);
Insert cell
usStatesData = await d3.json('https://d3js.org/us-10m.v1.json');
Insert cell
path = d3.geoPath().projection(iowaProjection);
Insert cell
projection = d3.geoAlbersUsa()
.translate( [width/2, height/2] );
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function dateToString(date) {
var year = date.getFullYear();
var month = ("0" + (date.getMonth() + 1)).slice(-2);
var day = ("0" + date.getDate()).slice(-2);
return `${year}-${month}-${day}`;
}
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