Published
Edited
Oct 28, 2020
Insert cell
Insert cell
Insert cell
d3 = require("d3@6");
Insert cell
Insert cell
Insert cell
data = d3.csvParse(await FileAttachment("alphabet.csv").text(),
({letter, frequency}) => ({name: letter, value: +frequency}))
.sort((a, b) => b.value - a.value)
Insert cell
margin = ({top: 20, right: 0, bottom: 30, left: 40});
Insert cell
height = 500;
Insert cell
Insert cell
{
const testScale = d3.scaleLinear()
// .nice() will extend domain to nice-looking rounded numbers, extended as 0 to 100 in this case
.domain([0, 99.9]).nice()
.range([-100, 100]);
return testScale(50);
}
Insert cell
x = d3.scaleBand() // creates a band scale (maps dicrete to contiguous)
.domain(data.map(d => d.name)) // set the (input) domain of the scale
.range([margin.left, width - margin.right]) // set the mapped (output) range of the scale
.padding(0.1) // set the padding (band scale only parameter)
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
xAxis = selection => selection
// place the bounding box <g> of axis at bottom
// all sub elements created by d3.axisBottom contained in <g> will be moved accordingly
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
Insert cell
yAxis = selection => selection
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(selection => selection.select(".domain").remove())
Insert cell
Insert cell
Insert cell
function zoom(svg) {
// bounding box coordinate, left upper corner, right lower corner
const extent = [[margin.left, margin.top], [width - margin.right, height - margin.top]];

svg.call(d3.zoom() // creates the zoom behavior
.scaleExtent([1, 8]) // min scale factor 1, max scale factor 8
.translateExtent(extent)
.extent(extent) // zooming viewport size (i.e. view window size)
.on("zoom", zoomed));
// This called closure
// svg is captured from outside,
// every time a "zoom" event is triggered, zoomed will execute on svg
function zoomed(event) {
// event stores information about location of current event, type of event, etc.
// event are usally user mouse inputs
// event.transform.applyX will transform x coordinate to x*k + t_x
// update x axis range
x.range([margin.left, width - margin.right].map(d => event.transform.applyX(d)));
// update width of each bars
// no need to update height, we just stretch bars horizontally
svg.selectAll(".bars rect").attr("x", d => x(d.name)).attr("width", x.bandwidth());
// update xAxis and draw new ticks
svg.selectAll(".x-axis").call(xAxis);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.call(zoom); // .call() will invoke the passed function with the current selection set

svg.append("g")
.attr("class", "bars")
.attr("fill", "steelblue")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", d => x(d.name))
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
.attr("width", x.bandwidth()); // width of each band in the band scale

svg.append("g")
.attr("class", "x-axis")
.call(xAxis);

svg.append("g")
.attr("class", "y-axis")
.call(yAxis);

return svg.node();
}
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