Published
Edited
Aug 5, 2020
2 stars
Also listed in…
Season 1
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
signal
Insert cell
signalMap
Insert cell
Insert cell
shapesWithData
Insert cell
map = {
// let projection = d3
// .geoAlbersUsa()
// .fitSize([mapWidth, mapHeight], shapesWithData);

let projection = d3
.geoAlbersUsa()
.translate([mapWidth / 2, mapHeight / 2])
.scale([mapWidth]);

// const path = d3.geoPath(projection);

const ctx = DOM.context2d(mapWidth, mapHeight);
const path = d3.geoPath(projection).context(ctx);

ctx.fillStyle = "white";
ctx.fillRect(0, 0, mapWidth, mapHeight);

ctx.strokeStyle = "black";
shapesWithData.forEach(d => {
ctx.strokeStyle = "lightgray";
ctx.lineWidth = d.metric ? 1 : 0;
ctx.globalAlpha = d.metric ? 1 : 0;

ctx.beginPath();
path(d);
ctx.stroke();

ctx.fillStyle = colorScale(d.metric || 0);
ctx.beginPath();
let point = projection(d.centroid.geometry.coordinates);
if (!point) return;

ctx.arc(point[0], point[1], 5, 0, 2 * Math.PI);
ctx.fill();
// // .style("fill", (d, i) => {
// // if (!d.metric) return '#CCC';
// // else return colorScale(d.metric || 0);
// // })
});

return ctx.canvas;

// // County outlines

// .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
// 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
Insert cell
Insert cell
Insert cell
usShapes = d3.json("https://cdn.jsdelivr.net/npm/us-atlas@3/counties-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