Published
Edited
Apr 25, 2020
Insert cell
Insert cell
wnc_surround = {
let map = d3
.create("svg")
.attr("width", map_width)
.attr("height", map_height)
.style('border', 'solid 2px black');

let county_group = map
.append("g")
.selectAll('path')
.data(counties.features)
.enter()
.append('path')
.attr('d', geoGenerator)
.style('stroke', 'black')
.style('stroke-width', '1px')
.style('stroke-opacity', 0.2)
.style('fill', function(d) {
let cases = d.properties.cases;
if (cases == 0) {
return 'white';
} else {
let s = 0.6;
if (d.properties.STATEFP == '37') {
return d3.interpolateBlues((d.properties.cases / max_cases) ** s);
} else {
return d3.interpolateReds((d.properties.cases / max_cases) ** s);
}
}
})
.on('mouseenter', function() {
d3.select(this)
.style('stroke-width', '4px')
.style('stroke-opacity', 0.8);
})
.on('mouseleave', function() {
d3.select(this)
.style('stroke-width', '1px')
.style('stroke-opacity', 0.2);
})
.attr('title', function(d) {
return `${
d.properties.NAME
} County, ${get_state(d.properties.STATEFP)}<br /> ${d.properties.cases} cases and ${d.properties.deaths} deaths<br />as of April 24`;
});
county_group.nodes().forEach(tippy);

map
.append("g")
.selectAll('path')
.data(states.features)
.enter()
.append('path')
.attr('d', geoGenerator)
.style('stroke', 'black')
.style('stroke-width', '3px')
.style('opacity', 0.7)
.style('fill', 'none');

let road_group = map.append("g");
road_group
.selectAll('path')
.data(roads.features)
.enter()
.append('path')
.attr('d', geoGenerator)
.style('fill', 'none')
.style('stroke-width', '4')
.style('stroke', '#ffffff')
.style('opacity', '0.9')
.attr('pointer-events', 'none');
let road_group2 = map.append("g");
road_group2
.selectAll('path')
.data(roads.features)
.enter()
.append('path')
.attr('d', geoGenerator)
.style('fill', 'none')
.style('stroke-width', '1.5')
.style('stroke', '#333')
.style('opacity', '0.7')
.attr('pointer-events', 'none');

map
.append('g')
.selectAll('circle')
.data(cities.features)
.enter()
.append('circle')
.attr('cx', function(d) {
let x =
projection.scale() * d.geometry.coordinates[0] +
projection.translate()[0];
return x;
})
.attr('cy', function(d) {
let y =
-projection.scale() * d.geometry.coordinates[1] +
projection.translate()[1];
return y;
})
.attr('r', 5)
.attr('fill', 'black');

map
.append('g')
.selectAll('text')
.data(cities.features)
.enter()
.append('text')
.attr('x', function(d) {
let x =
projection.scale() * d.geometry.coordinates[0] +
projection.translate()[0];
return x;
})
.attr('y', function(d) {
let y =
-projection.scale() * d.geometry.coordinates[1] +
projection.translate()[1];
return y;
})
.attr('dx', 8)
.attr('dy', function(d) {
if (d.properties.NAME == 'Atlanta') {
return 0;
} else if (d.properties.NAME == 'Knoxville') {
return 8;
} else {
return -5;
}
})
.text(d => d.properties.NAME)
.style('fill', function(d) {
if (d.properties.NAME == 'Atlanta') {
return 'white';
} else {
return 'black';
}
})
.style('font-size', '12px')
.attr('pointer-events', 'none');

return map.node();
}
Insert cell
geoGenerator = d3.geoPath().projection(projection)
Insert cell
projection = d3
.geoIdentity()
.reflectY(true)
.fitSize([map_width, map_height], bounds)
Insert cell
max_cases = d3.max(counties.features.map(f => f.properties.cases))
Insert cell
cities = {
let cities = topojson.feature(map_file, map_file.objects["cities"]);
cities.features = cities.features.filter(
d =>
[
"Asheville",
"Athens",
"Atlanta",
"Charlotte",
"Columbia",
"Knoxville"
].indexOf(d.properties.NAME) > -1
);
return cities;
}
Insert cell
roads = topojson.feature(map_file, map_file.objects["roads"])
Insert cell
function get_state(fip) {
if (fip == '13') {
return 'GA';
} else if (fip == '37') {
return 'NC';
} else if (fip == '45') {
return 'SC';
} else if (fip == '47') {
return 'TN';
}
}
Insert cell
counties = topojson.feature(map_file, map_file.objects["counties"])
Insert cell
states = topojson.feature(map_file, map_file.objects["states"])
Insert cell
bounds = {
let xmin = -482000;
let xmax = -57000;
let ymin = 3538010;
let ymax = 3859300;
return {
type: "Feature",
geometry: {
type: "LineString",
coordinates: [[xmin, ymin], [xmax, ymax]]
},
aspect: (ymax - ymin) / (xmax - xmin)
};
}
Insert cell
// This map file is the only data file.
// NY Times COVID data is embedded as properties
// in the counties layer, which is fine since we're
// intersted in a snapshot in time.
map_file = FileAttachment('wnc_surround_aea@4.json').json()
Insert cell
d3 = require('d3@5')
Insert cell
topojson = require("topojson-client@3")
Insert cell
tippy = require("https://unpkg.com/tippy.js@2.5.4/dist/tippy.all.min.js")
Insert cell
map_width = 0.8 * width
Insert cell
map_height = bounds.aspect * map_width
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