Public
Edited
Jul 12, 2023
Insert cell
Insert cell
Insert cell
// Canvas version
{
// Set up the canvas
let canvas = d3
.create("canvas")
.style("margin", `${pad}px`)
.attr("width", w)
.attr("height", h);
let ctx = canvas.node().getContext("2d");

// Draw the rectangles
data.forEach(function (o) {
ctx.fillStyle = color(o.cylinders);
ctx.fillRect(
x_scale(o.year) + 5,
y_scale(o.accumulation),
x_scale(71) - x_scale(70) - 15,
y_scale(o.height) - y_scale(0) + 3
);
});

// Draw the axes
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(pad, y_scale(0));
ctx.lineTo(w - pad, y_scale(0));
ctx.stroke();
ctx.fillStyle = "black";
ctx.lineWidth = 0.5;
d3.range(70, 83).forEach(function (x) {
ctx.beginPath();
ctx.moveTo(x_scale(x) + 26, y_scale(0));
ctx.lineTo(x_scale(x) + 26, y_scale(0) + 8);
ctx.stroke();
ctx.fillText(x, x_scale(x) + 20, y_scale(0) + 15);
});
ctx.lineWidth = 1;
d3.range(0, 45, 5).forEach(function (y) {
ctx.beginPath();
ctx.moveTo(pad, y_scale(y));
ctx.lineTo(pad + 5, y_scale(y));
ctx.stroke();
ctx.fillText(y, pad - 15, y_scale(y) + 3);
});

return canvas.node();
}
Insert cell
// SVG version
{
// Set up the SVG:
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, w, h])
.style("max-width", `${w}px`);

// Add the rectangles
svg
.append("g")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", (d) => x_scale(d.year))
.attr("y", (d) => y_scale(d.height + d.accumulation))
.attr("height", (d) => y_scale(0) - y_scale(d.height))
.attr("width", x_scale.bandwidth())
.attr("fill", (o) => color(o.cylinders))
.attr("stroke", "white")
.attr("stroke-width", 2);

// Add the axes
let x_axis = svg
.append("g")
.attr("transform", `translate(0,${h - pad})`)
.call(d3.axisBottom(x_scale).tickSizeOuter(0));
let y_axis = svg
.append("g")
.attr("transform", `translate(${pad})`)
.call(d3.axisLeft(y_scale).tickSizeOuter(0));
y_axis.select("path.domain").attr("stroke", null);

return svg.node();
}
Insert cell
Insert cell
color = d3.scaleOrdinal().domain([3, 4, 5, 6, 8]).range(d3.schemeCategory10)
Insert cell
y_scale = d3
.scaleLinear()
.domain([0, max_count])
.range([h - pad, pad])
Insert cell
max_count = d3.max(
Array.from(d3.group(data, (o) => o.year).values())
.map((a) => a.slice(-1)[0])
.map((o) => o.height + o.accumulation)
)
Insert cell
x_scale = d3
.scaleBand()
.domain(data.map((o) => o.year))
.range([pad, w - pad])
.padding(0.2)
Insert cell
pad = 20
Insert cell
h = 500
Insert cell
w = 800
Insert cell
// Manipulate the cars data set into a form more suitable for stacks.
// I suppose that a lot of folks would use d3.stack for this, but
// I prefer the following.
data = {
let data = [];
d3.group(
d3.sort(
cars,
(o) => o.year,
(o) => o.cylinders
),
(o) => o.year,
(o) => o.cylinders
).forEach(function (cylinder_group, year) {
let accumulation = 0;
cylinder_group.forEach(function (a, cylinders) {
data.push({
year,
cylinders,
height: a.length,
accumulation
});
accumulation = accumulation + a.length;
});
});

return data;
}
Insert cell
import { Swatches } from "@d3/color-legend"
Insert cell
// cars = d3.csv(
// "https://raw.githubusercontent.com/sandialabs/slycat-data/master/cars.csv",
// d3.autoType
// )
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