Published
Edited
Nov 20, 2019
Fork of Hexbin map
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, 960, 600]);

svg.append("g")
.attr("transform", "translate(600,40)")
.call(legend);

svg.append("path")
.datum(topojson.mesh(us, us.objects.states))
.attr("fill", "none")
.attr("stroke", "#777")
.attr("stroke-width", 0.5)
.attr("stroke-linejoin", "round")
.attr("d", d3.geoPath());

svg.append("g")
.selectAll("path")
.data(data)
.join("path")
.attr("transform", d => `translate(${d.x},${d.y})`)
.attr("d", d => hexbin.hexagon(radius(d.length)))
.attr("fill", d => color(d.date))
.attr("stroke", d => d3.lab(color(d.date)).darker())
.append("title")
.text(d => `${d.length.toLocaleString()} stores
${d.date.getFullYear()} median opening`);

return svg.node();
}
Insert cell
legend = g => {
const width = 240;

g.append("image")
.attr("width", width)
.attr("height", 8)
.attr("preserveAspectRatio", "none")
.attr("xlink:href", ramp(color.interpolator()).toDataURL());

g.append("text")
.attr("class", "caption")
.attr("y", -6)
.attr("fill", "#000")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.title);

g.call(d3.axisBottom(d3.scaleTime(color.domain(), [0, width]))
.ticks(6)
.tickSize(13))
.select(".domain")
.remove();
}
Insert cell
data = {
const parseDate = d3.timeParse("%m/%d/%Y");
const projection = d3.geoAlbersUsa().scale(1280).translate([480, 300]);
const data = d3.tsvParse(await FileAttachment("FBMBranchMap.txt").text(), d => {
const p = projection(d);
p.date = parseDate(d.date);
return p;
});
return Object.assign(
hexbin(data)
.map(d => (d.date = new Date(d3.median(d, d => d.date)), d))
.sort((a, b) => b.length - a.length),
{title: "Median opening year"}
);
}
Insert cell
color = d3.scaleSequential(d3.extent(data, d => d.date), d3.interpolateSpectral)
Insert cell
radius = d3.scaleSqrt([0, d3.max(data, d => d.length)], [0, hexbin.radius() * Math.SQRT2])
Insert cell
hexbin = d3.hexbin().extent([[0, 0], [width, height]]).radius(10)
Insert cell
function ramp(color, n = 512) {
const canvas = DOM.canvas(n, 1);
const context = canvas.getContext("2d");
canvas.style.margin = "0 -14px";
canvas.style.width = "calc(100% + 28px)";
canvas.style.height = "40px";
canvas.style.imageRendering = "pixelated";
for (let i = 0; i < n; ++i) {
context.fillStyle = color(i / (n - 1));
context.fillRect(i, 0, 1, 1);
}
return canvas;
}
Insert cell
width = 975
Insert cell
height = 600
Insert cell
us = FileAttachment("10m.json").json()
Insert cell
topojson = require("topojson-client@3")
Insert cell
d3 = require("d3@5", "d3-hexbin@0.2")
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