Published
Edited
May 12, 2021
Insert cell
Insert cell
Insert cell
// viewof select = Radio(Object.keys(cntydata),{value: 'moving_in', label: "Choose whether People are:"})
Insert cell
viewof button = Button("Click to recolor stuff")
Insert cell
chart = {
const width = 975;
const height = 610;
let state = d3.select(null), target, color;
let colors = d3.scaleQuantize([1, 10000], d3.schemeBlues[9]);

const zoom = d3.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed);

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.on("dblclick", (event) => event.stopPropagagion())
.on("click", reset);

const g = svg.append("g");

const states = g.append("g")
.attr("fill", "#444")
.attr("cursor", "pointer")
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.join("path")
.on("click", clicked)
.attr("d", path);
states.append("title")
.text(d => d.properties.name);

g.append("path")
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-linejoin", "round")
.attr("pointer-events", "none")
.attr("d", path(topojson.mesh(us, us.objects.states, (a, b) => a !== b)));

const counties = g.append("g")
.attr("fill", "#444")
.attr("stroke", "#444")
.attr("pointer-events", "none")

svg.call(zoom).on("wheel.zoom", null)

function reset() {
if (!target) return;
target = null;
state.style("fill", color);
states.transition().duration(750).style("fill", null);
counties.selectAll("path").remove();
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity,
d3.zoomTransform(svg.node()).invert([width / 2, height / 2])
);
}

function clicked(event, d) {
const [[x0, y0], [x1, y1]] = path.bounds(d);
event.stopPropagation();
if (target == d.id) {
return reset();
} else {
target = d.id;
}
state = d3.select(this).style("fill", color);
states.transition().style("fill", null);
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(Math.min(8, 0.9 / Math.max((x1 - x0) / width, (y1 - y0) / height)))
.translate(-(x0 + x1) / 2, -(y0 + y1) / 2),
d3.pointer(event, svg.node())
);
counties.selectAll("path")
.data(topojson.feature(us, us.objects.counties).features.filter(d => d.id.slice(0,2) == target))
.join("path")
.attr("d", path)
.attr("fill", d => colors(moved_in.get(d.id)))
.style("stroke", "white")
.style("stroke-linejoin", "round")
.on("click", reset)
}

function zoomed(event) {
const {transform} = event;
g.attr("transform", transform);
g.attr("stroke-width", 1 / transform.k);
}
function recolor(d) {
colors = d;
color = colors(5);
state.style("fill", d => (d.id == target) ? color : null)
counties.selectAll("path")
.attr("fill", d => colors(moved_in.get(d.id)))
}

return Object.assign(svg.node(), {
recolor: recolor
});
}
Insert cell
// cntydata = ({
// moving_in: Object.assign(new Map(d3.csvParse(await FileAttachment("cleancnty.csv").text(), ({id, movedin}) => [id, +movedin])), {title: "Total Moving In"}),
// moving_out: Object.assign(new Map(d3.csvParse(await FileAttachment("cleancnty.csv").text(), ({id, movedout}) => [id, +movedout])), {title: "Total Moving Out"})
// })
Insert cell
moved_in = Object.assign(new Map(d3.csvParse(await FileAttachment("cleancnty.csv").text(), ({id, movedin}) => [id, +movedin])), {title: "Total Moving In"})
Insert cell
Insert cell
import { data } from "@d3/choropleth"
Insert cell
path = d3.geoPath()
Insert cell
us = FileAttachment("counties-albers-10m.json").json()
Insert cell
topojson = require("topojson-client@3")
Insert cell
d3 = require("d3@6")
Insert cell
import {Button} from "@observablehq/inputs"
Insert cell
import {Radio} from "@observablehq/inputs"
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