Public
Edited
Dec 4, 2022
1 fork
6 stars
Insert cell
Insert cell
map = {
let svg = d3.create("svg").attr("width", w).attr("height", h);

let map = svg.append("g").attr("id", "map");
let path = d3.geoPath().projection(projection);
map
.selectAll("path")
.data(contiguous_states.features)
.join("path")
.attr("d", path)
.attr("fill", "white")
.attr("stroke", "black")
.attr("stroke-width", 2);

let nodes = contiguous_states.features.map(function (o, id) {
let [x0, y0] = projection([o.properties.longitude, o.properties.latitude]);
return {
id: o.properties.postal,
neighbors: o.properties.neighbors,
x: x0,
y: y0
};
});

let link = svg.append("g").attr("class", "links");
link
.selectAll("line")
.data(state_adjacencies)
.join("line")
.attr("x1", (d) => d.x1)
.attr("y1", (d) => d.y1)
.attr("x2", (d) => d.x2)
.attr("y2", (d) => d.y2)
.attr("class", (d) => `${d.source} ${d.target}`)
.attr("stroke-width", 0.1)
.attr("stroke", "black");

let node = svg.append("g");
node
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("id", function (d) {
return d.id;
})
.attr("r", 5)
.attr("fill", "black")
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.on("pointerenter", function (_, n) {
d3.select(this).attr("fill", "green");
let state = n.id;
link.selectAll(`.${state}`).attr("stroke-width", 2);
n.neighbors.forEach(function (i) {
node
.selectAll(`#${contiguous_states.features[i].properties.postal}`)
.attr("fill", "red");
});
})
.on("pointerleave", function () {
link.selectAll("line").attr("stroke-width", 0.1);
node.selectAll("circle").attr("fill", "black");
});

return svg.node();
}
Insert cell
projection = d3.geoAlbers().fitSize([w - 10, h], contiguous_states)
Insert cell
h = 0.625 * w
Insert cell
w = d3.min([width, 1000])
Insert cell
contiguous_states = {
let contiguous_states = await (
await FileAttachment("contiguous_states3.json")
).json();
contiguous_states.objects.contiguous_states.geometries =
contiguous_states.objects.contiguous_states.geometries.filter(
(o) => o.properties.postal != "DC"
);
let adjacency_lists = topojson.neighbors(
contiguous_states.objects.contiguous_states.geometries
);
contiguous_states = topojson.feature(
contiguous_states,
contiguous_states.objects.contiguous_states
);
contiguous_states.features.forEach(function (o, i) {
o.properties.neighbors = adjacency_lists[i];
});
return contiguous_states;
}
Insert cell
state_adjacencies = {
let properties = contiguous_states.features.map((o) => o.properties);
let adjacency_indices = contiguous_states.features
.map((o, i) => o.properties.neighbors.map((j) => [i, j]))
.flat()
.filter((a) => a[0] < a[1]);
adjacency_indices = adjacency_indices.map(function (a) {
let [x1, y1] = projection([
properties[a[0]].longitude,
properties[a[0]].latitude
]);
let [x2, y2] = projection([
properties[a[1]].longitude,
properties[a[1]].latitude
]);
return {
source: properties[a[0]].postal,
target: properties[a[1]].postal,
x1,
x2,
y1,
y2
};
});

return adjacency_indices;
}
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