Public
Edited
Oct 30, 2024
14 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = d3.csvParse(csv, d3.autoType)
Insert cell
contested = data
.filter((d) => d.category === "none")
.sort(sortStates)
Insert cell
sortStates = (a, b) => {
// Sort in descending order by votes and then ascending order by name
if (d3.descending(a.votes, b.votes) === 0) {
return d3.ascending(a.name, b.name);
} else {
return d3.descending(a.votes, b.votes);
}
}
Insert cell
totalD = d3.sum(data.filter(d => d.category === "D").map(d => d.votes))
Insert cell
totalR = d3.sum(data.filter(d => d.category === "R").map(d => d.votes))
Insert cell
decided = new Map(
Object.entries(selectStates).filter(([key, value]) => value !== "none")
)
Insert cell
treeData = {
const root = {
name: "",
votes: 0,
votesD: totalD,
votesR: totalR
};
const states = contested.sort((a, b) => {
if (decided.has(a.name)) {
return -1;
} else if (decided.has(b.name)) {
return 1;
} else return sortStates(a, b);
});
function buildTree(node, depth) {
if (depth < states.length && !winner(node)) {
const state = states[depth];
const status = decided.get(state.name);
node.children = [];
if (!status || status === "D") {
node.children.push({
name: state.name,
shortname: state.shortname,
party: "D",
votes: state.votes,
votesD: node.votesD + state.votes,
votesR: node.votesR
});
}
if (!status || status === "R") {
node.children.push({
name: state.name,
shortname: state.shortname,
party: "R",
votes: state.votes,
votesD: node.votesD,
votesR: node.votesR + state.votes
});
}
node.children.forEach((child) => buildTree(child, depth + 1));
}
return node;
}
return buildTree(root, 0);
}
Insert cell
tree = d3.tree().size([targetHeight, targetWidth])
Insert cell
root = tree(d3.hierarchy(treeData))
Insert cell
linkWidth = d3.scaleLinear().domain([root.height, 0]).range([1, 7])
Insert cell
targetWidth = Math.min(width, 780)
Insert cell
targetHeight = 600
Insert cell
circleSize = d3
.scaleSqrt()
.domain(d3.extent(contested.map((d) => d.votes)))
.range([2.5, 5.5])
Insert cell
votesScale = d3
.scaleLinear()
.domain([0, 538])
.range([0, targetWidth])
Insert cell
result = d =>
d.votesD > 269
? "D"
: d.votesR > 269
? "R"
: d.votesD === 269 && d.votesR === 269
? "tie"
: null
Insert cell
winner = d => {
const outcome = result(d);
return !outcome || outcome === "tie" ? null : outcome;
}
Insert cell
isDecided = (d) => {
return decided.has(d.name);
}
Insert cell
partyColor = d => (d.party === "D" ? colorD : d.party === "R" ? colorR : "#888")
Insert cell
colorD = "#2a72c9"
Insert cell
colorR = "#c92a2a"
Insert cell
normalOpacity = 0.3
Insert cell
fullOpacity = 1.0
Insert cell
strokeOpacity = (highlight) => (highlight ? fullOpacity : normalOpacity)
Insert cell
stateLabel = d => (width > 800 ? d.name : d.shortname)
Insert cell
candidateD = "Harris"
Insert cell
candidateR = "Trump"
Insert cell
import { form } from "@mbostock/form-input"
Insert cell
d3 = require("d3@6")
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