Published
Edited
Oct 4, 2021
Importers
1 star
Insert cell
Insert cell
date = "20200301"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
signal
Insert cell
signalMap
Insert cell
Insert cell
Insert cell
// colorScale = d3.scaleSequential(
// // d3.extent(shapesWithData, d => d.metric),
// signalMap[signal].extent,
// // [0, 3000],
// d3.interpolateReds
// )

// colorScale = d3.scaleQuantize(signalMap[signal].extent, d3.schemeReds[8])
colorScale = d3.scaleQuantize(extent, signalMap[signal].colorScheme)
Insert cell
legend({
color: colorScale,
title: signalMap[signal].label,
width: width
})
Insert cell
Insert cell
extent = d3.extent(shapesWithData, d => d.metric)
Insert cell
Insert cell
Insert cell
Insert cell
data = fetchData(signalMap[signal], date, fips)
Insert cell
metrics = new Map(data.epidata.map(d => [d.geo_value, d.value]))
Insert cell
reduceMetrics = data.epidata.reduce((m, d) => {
m[d.geo_value] = d.value;
return m;
}, {})
Insert cell
Insert cell
metricExtent = d3.extent(shapesWithData, s => {
return s.metric;
})
Insert cell
rScale = d3
.scaleSqrt()
.domain(metricExtent)
.range([0.1, 12])
Insert cell
popExtent = d3.extent(shapesWithData, s => {
return s.population;
})
Insert cell
rPopScale = d3
.scaleSqrt()
.domain(popExtent)
.range([0.1, 12])
Insert cell
rPopScale(762)
Insert cell
mapImage = {
// let projection = d3.geoAlbersUsa()
// .fitSize([mapWidth, mapHeight], shapesWithData);
let localNodes = shapesWithData
.map(d => {
return {
id: d.id,
metric: d.metric,
name: d.properties.name,
r: rScale(d.metric), // || 2,
population: d.population,
p: rPopScale(d.population),
cx: d.centroid.geometry.coordinates[0],
cy: d.centroid.geometry.coordinates[1],
x: d.centroid.geometry.coordinates[0],
y: d.centroid.geometry.coordinates[1]
};
})
.filter(d => !isNaN(d.r));
console.log(localNodes);

let simulation = d3
.forceSimulation(localNodes)
.force(
"collide",
d3
.forceCollide()
// .radius(d => d.p) // for spacing by population
.radius(d => d.r + 1) // for spacing by metric
.strength(1)
)

.force(
"x",
d3.forceX(d => {
return d.cx;
})
)
.force(
"y",
d3.forceY(d => {
return d.cy;
})
);

simulation.tick(100);

let projection = d3
.geoAlbersUsa()
.translate([width / 2, mapHeight / 2])
.scale([100]);
//
const path = d3.geoPath();
// const path = d3.geoPath(projection);

const svg = d3
.select(DOM.svg(mapWidth, mapHeight))
.attr('viewBox', `-25, -25, ${mapWidth + 50}, ${mapHeight + 60}`)
// .attr('width', mapWidth)
// .attr('height', mapHeight)
.attr('preserveAspectRatio', 'xMidYMid slice')
.style("width", "100%")
.style("height", "auto")
.style('font-size', 12);
// .style('border', '1px solid yellow');

let node = svg.node();

svg
.append("rect")
.attr("width", mapWidth)
.attr("height", mapHeight)
.attr("fill", "white");
// .attr("fill", "green");

// County outlines
svg
.append("g")
.selectAll("path")
.data(shapesWithData)
.join("path")
.attr("stroke-width", d => (d.metric ? 0.5 : 0))
.style("stroke", (d, i) => {
return "lightgray";
})
//.style("opacity", (d, i) => (d.metric ? 1 : 0.2))
// .style("fill", (d, i) => {
// if (!d.metric) return '#CCC';
// else return colorScale(d.metric || 0);
// })
.style("fill", "none")
.attr("d", path)
.on("click", function(d) {
console.log(d);
node.value = { fips: d.id, name: d.properties.name };
node.dispatchEvent(new CustomEvent("input", { bubbles: true }));
});

// State outlines
svg
.append("g")
.attr("stroke-width", 1)
.selectAll("path")
.data(stateShapes)
.join("path")
.style("stroke", (d, i) => {
return "lightgray";
})
.style('fill', 'none')
.attr("d", path);

// let lines = svg
// .append("g")
// .selectAll("line.centroid")
// .data(localNodes)
// .join("line")
// .classed("centroid", true)
// .attr("x1", d => d.cx)
// .attr("x2", d => d.x)
// .attr("y1", d => d.cy)
// .attr("y2", d => d.y)
// // .style("stroke", "black");
// .style("stroke", (d, i) => {
// if (!d.metric) return '#CCC';
// else return colorScale(d.metric || 0);
// });

let centroids = svg
.append("g")
.selectAll("circle.centroid")
.data(localNodes)
.join("circle")
.classed("centroid", true)
.sort((a, b) => {
return b.r - a.r;
})
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", d => d.r)
.style("stroke", "lightgray")
.style("stroke-width", 0.5)
.style("fill-opacity", 0.96)
.style("fill", (d, i) => {
if (!d.metric) return '#CCC';
else return colorScale(d.metric || 0);
})
.on("click", d => {
console.log("circle", d);
});

// svg
// .append("text")
// .text(`${prettyDate(date)}`)
// .attr("dx", mapWidth / 2)
// .attr("dy", "24px")
// .style("font-size", "12px")
// .style("text-anchor", 'middle')
// .style('text-transform', 'uppercase')
// .style("font-family", "helvetica neue");

// svg
// .append("text")
// .text(`${signal}`)
// .attr("dx", mapWidth / 2)
// .attr("dy", "36px")
// .style("fill", colorScale(colorScale.domain()[1]))
// .style("font-size", "9px")
// .style("text-anchor", 'middle')
// .style('text-transform', 'uppercase')
// .style("font-family", "helvetica neue");

// simulation.on("tick", () => {
// centroids.attr("cx", d => d.x).attr("cy", d => d.y);
// // lines
// // .attr("x1", d => d.cx)
// // .attr("x2", d => d.x)
// // .attr("y1", d => d.cy)
// // .attr("y2", d => d.y);
// });

// svg
// .append("g")
// .attr("transform", `translate(${0},${mapHeight - 25})`)
// .append(() =>
// legend({
// color: colorScale,
// title: signalMap[signal].label,
// width: mapWidth
// })
// );

return node;
}
Insert cell
Insert cell
Insert cell
Insert cell
usShapes = d3.json(
"https://cdn.jsdelivr.net/npm/us-atlas@3/counties-albers-10m.json"
)
Insert cell
countyShapes = topojson
.feature(usShapes, usShapes.objects.counties)
.features.sort((a, b) => +a.id - +b.id)
Insert cell
stateShapes = topojson
.feature(usShapes, usShapes.objects.states)
.features.sort((a, b) => +a.id - +b.id)
Insert cell
shapesWithData = countyShapes.map(s => ({
...s,
population: pops.get(s.id),
metric: metrics.get(s.id),
centroid: turf.centroid(s)
}))
Insert cell
Insert cell
Insert cell
sensors = [
{
key: 'doctor-visits-smoothed_adj_cli',
name: 'Doctor Visits',
id: 'doctor-visits',
tooltipText:
'Percentage of daily doctor visits that are due to COVID-like symptoms',
mapTitleText:
'Percentage of daily doctor visits that are due to COVID-like symptoms',
chartTitleText:
'Percentage of daily doctor visits that are due to COVID-like symptoms',
yAxis: 'Percentage',
format: 'percent',
signal: 'smoothed_adj_cli',
levels: ['county', 'msa', 'state'],
type: 'early',
extent: [0, 11],
colorScheme: d3.schemePuRd[8]
},
{
key: 'hospital-admissions-smoothed_adj_covid19',
name: 'Hospital Admissions',
id: 'hospital-admissions',
tooltipText:
'Percentage of daily hospital admissions with COVID-19 associated diagnoses',
mapTitleText:
'Percentage of daily hospital admissions with COVID-19 associated diagnoses',
chartTitleText:
'Percentage of daily hospital admissions with COVID-19 associated diagnoses',
yAxis: 'Percentage',
format: 'percent',
signal: 'smoothed_adj_covid19',
levels: ['county', 'msa', 'state'],
type: 'late',
extent: [0, 22],
colorScheme: d3.schemeRdPu[8]
},
{
key: 'fb-survey-smoothed_cli',
name: 'Symptoms (FB)',
id: 'fb-survey',
tooltipText:
'Percentage of people with COVID-like symptoms, based on Facebook surveys',
mapTitleText:
'Percentage of people with COVID-like symptoms, based on Facebook surveys',
chartTitleText:
'Percentage of people with COVID-like symptoms, based on Facebook surveys',
yAxis: 'Percentage',
format: 'percent',
signal: 'smoothed_cli',
levels: ['county', 'msa', 'state'],
type: 'early',
extent: [0, 1.8],
colorScheme: d3.schemeBlues[8]
},
{
key: 'fb-survey-smoothed_hh_cmnty_cli',
name: 'Symptoms in Community (FB)',
id: 'fb-survey',
tooltipText:
'Percentage of people who know someone in their local community with COVID-like symptoms, based on Facebook surveys',
mapTitleText:
'Percentage of people who know someone in their local community with COVID-like symptoms, based on Facebook surveys',
chartTitleText:
'Percentage of people who know someone in their local community with COVID-like symptoms, based on Facebook surveys',
yAxis: 'Percentage',
format: 'percent',
signal: 'smoothed_hh_cmnty_cli',
levels: ['county', 'msa', 'state'],
type: 'early',
extent: [0, 38.8],
colorScheme: d3.schemePuBu[8]
},
{
key: 'safegraph-full_time_work_prop',
name: 'Away from Home 6hr+ (SG)',
id: 'safegraph',
tooltipText:
'Proportion of people spending 6 hours or more away from home, based on SafeGraph mobility data',
mapTitleText:
'Proportion of people spending 6 hours or more away from home, based on SafeGraph mobility data',
chartTitleText:
'Proportion of people spending 6 hours or more away from home, based on SafeGraph mobility data',
yAxis: 'Proportion',
format: 'raw',
signal: 'full_time_work_prop',
levels: ['county', 'state'],
type: 'public',
extent: [0, 0.14],
colorScheme: d3.schemeGnBu[8]
},
{
key: 'indicator-combination-nmf_day_doc_fbc_fbs_ght',
name: 'Combined',
id: 'indicator-combination',
tooltipText:
'Combination of COVID-19 indicators available at this geographic level',
mapTitleText: 'Combination of COVID-19 indicators',
chartTitleText: 'Combination of COVID-19 indicators',
yAxis: 'Combined value (arbitrary scale)',
format: 'raw',
signal: 'nmf_day_doc_fbc_fbs_ght',
levels: ['county', 'msa', 'state'],
type: 'early',
extent: [0.24, 2],
colorScheme: d3.schemeYlGnBu[8]
},
{
key: 'indicator-combination-confirmed_7dav_incidence_prop',
name: 'Cases per 100,000 People',
id: 'indicator-combination',
tooltipText:
'Daily new confirmed COVID-19 cases per 100,000 people (7-day average), based on data reported by USAFacts and Johns Hopkins University',
mapTitleText:
'Daily new confirmed COVID-19 cases per 100,000 people (7-day average)',
chartTitleText:
'Daily new confirmed COVID-19 cases per 100,000 people (7-day average)',
yAxis: 'Cases per 100,000 people',
format: 'raw',
signal: 'confirmed_7dav_incidence_prop',
levels: ['msa', 'county', 'state'],
type: 'late',
extent: [0, 50],
colorScheme: d3.schemeOranges[8]
},
{
key: 'indicator-combination-deaths_7dav_incidence_prop',
name: 'Deaths per 100,000 People',
id: 'indicator-combination',
tooltipText:
'Daily new COVID-19 deaths per 100,000 people (7-day average), based on data reported by USAFacts and Johns Hopkins University',
mapTitleText:
'Daily new COVID-19 deaths per 100,000 people (7-day average)',
chartTitleText:
'Daily new COVID-19 deaths per 100,000 people (7-day average)',
yAxis: 'Deaths per 100,000 people',
format: 'raw',
signal: 'deaths_7dav_incidence_prop',
levels: ['msa', 'county', 'state'],
type: 'late',
extent: [0, 1.8],
colorScheme: d3.schemeReds[8]
}
]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
moment = require('moment')
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