Published
Edited
Oct 11, 2022
26 forks
Insert cell
Insert cell
Insert cell
jsonCarData = FileAttachment("cars.json").json()
Insert cell
Insert cell
Insert cell
margin = ({top: 10, right: 20, bottom: 50, left: 105});
Insert cell
visWidth = 400;
Insert cell
visHeight = 400;
Insert cell
Insert cell
origins = Array.from(new Set(carData.map(d => d.origin)));
Insert cell
carColor = d3.scaleOrdinal().domain(origins).range(d3.schemeCategory10);
Insert cell
// x = ?
Insert cell
// y = ?
Insert cell
Insert cell
xAxis = (g, scale, label) =>
g.attr('transform', `translate(0, ${visHeight})`)
// add axis
.call(d3.axisBottom(scale))
// remove baseline
.call(g => g.select('.domain').remove())
// add grid lines
// references https://observablehq.com/@d3/connected-scatterplot
.call(g => g.selectAll('.tick line')
.clone()
.attr('stroke', '#d3d3d3')
.attr('y1', -visHeight)
.attr('y2', 0))
// add label
.append('text')
.attr('x', visWidth / 2)
.attr('y', 40)
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text(label)
Insert cell
yAxis = (g, scale, label) =>
// add axis
g.call(d3.axisLeft(scale))
// remove baseline
.call(g => g.select('.domain').remove())
// add grid lines
// refernces https://observablehq.com/@d3/connected-scatterplot
.call(g => g.selectAll('.tick line')
.clone()
.attr('stroke', '#d3d3d3')
.attr('x1', 0)
.attr('x2', visWidth))
// add label
.append('text')
.attr('x', -40)
.attr('y', visHeight / 2)
.attr('fill', 'black')
.attr('dominant-baseline', 'middle')
.text(label)
Insert cell
Insert cell
Insert cell
Insert cell
{
const bar = barChart();
bar.update(carData);
return bar;
}
Insert cell
function barChart() {
// set up
const margin = {top: 10, right: 20, bottom: 50, left: 50};
const visWidth = 300;
const visHeight = 200;

const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// create scales
const x = d3.scaleLinear()
.range([0, visWidth]);
const y = d3.scaleBand()
.domain(carColor.domain())
.range([0, visHeight])
.padding(0.2);
// create and add axes
const xAxis = d3.axisBottom(x).tickSizeOuter(0);
const xAxisGroup = g.append("g")
.attr("transform", `translate(0, ${visHeight})`);
xAxisGroup.append("text")
.attr("x", visWidth / 2)
.attr("y", 40)
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("Count");
const yAxis = d3.axisLeft(y);
const yAxisGroup = g.append("g")
.call(yAxis)
// remove baseline from the axis
.call(g => g.select(".domain").remove());
let barsGroup = g.append("g");

function update(data) {
// get the number of cars for each origin
const originCounts = d3.rollup(
data,
group => group.length,
d => d.origin
);

// update x scale
x.domain([0, d3.max(originCounts.values())]).nice()

// update x axis

const t = svg.transition()
.ease(d3.easeLinear)
.duration(200);

xAxisGroup
.transition(t)
.call(xAxis);
// draw bars
barsGroup.selectAll("rect")
.data(originCounts, ([origin, count]) => origin)
.join("rect")
.attr("fill", ([origin, count]) => carColor(origin))
.attr("height", y.bandwidth())
.attr("x", 0)
.attr("y", ([origin, count]) => y(origin))
.transition(t)
.attr("width", ([origin, count]) => x(count))
}
return Object.assign(svg.node(), { update });;
}
Insert cell
Insert cell
Insert cell
d3 = require("d3")
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