Public
Edited
Aug 5, 2024
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
// Plot the results
{
let plt1, plt2, plt3;

let theory = option.startGap,
real = d3.mean(passengers, (d) => d.waits);

plt1 = Plot.plot({
title: `Waits shorter than theory, ${real.toFixed(2)} | ${theory.toFixed(
2
)}`,
width: 600,
height: 300,
x: { nice: true },
y: { nice: true },
color: { legend: true, scheme: "Reds" },
grid: true,
marks: [
// Plot.boxY(passengers, { y: "waits", tip: true }),
Plot.barY(
passengers,
Plot.binX({ y: "count", fill: "count" }, { x: "waits" })
),
Plot.ruleX([theory], { stroke: "blue" }),
Plot.ruleX([real], { stroke: "red" })
]
});

plt2 = Plot.plot({
title: "Latter station takes longer waiting",
marginTop: 32,
marginBottom: 28,
width: 600,
height: 340,
x: { nice: true },
y: { nice: true },
color: { legend: true },
grid: true,
marks: [
Plot.boxY(passengers, { x: "station", y: "waits" }),
Plot.ruleY([d3.mean(passengers, (d) => d.waits)], { stroke: "blue" }),
Plot.linearRegressionY(passengers, {
x: "station",
y: "waits",
stroke: "red",
fill: "red",
tip: true
})
]
});

plt3 = Plot.plot({
title: "Slower bus takes more",
width: 1200,
height: 400,
x: { nice: true },
y: { nice: true },
grid: true,
marks: [
Plot.dot(summary, { x: "costs", y: "count" }),
Plot.linearRegressionY(summary, {
x: "costs",
y: "count",
stroke: "red",
fill: "red",
tip: true
}),
Plot.ruleY([d3.mean(summary, (d) => d.count)], { stroke: "blue" })
]
});

return htl.html`
<div style="display:flex">
${plt1}
${plt2}
</div>
${plt3}

`;
}
Insert cell
Insert cell
summary = generateSummary()
Insert cell
summary
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
summary.find((d) => d.bus == -1)
Insert cell
generateSummary = () => {
let summary = [];

passengers.map((p) => {
let b = p.bus;

// Find the bus, if not in summary, push it.
if (summary.find((d) => d.bus == b.bus) === undefined) {
let costs = d3.max(
buses.filter((d) => d.bus == b.bus),
(d) => d.costs
);
summary.push({ bus: b.bus, count: 0, costs });
}

// Update the bus's passenger count
let f = summary.find((d) => d.bus == b.bus);
f.count += 1;
});

return summary;
}
Insert cell
passengers = generatePassengers()
Insert cell
passengers
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
generatePassengers = () => {
let passengers = [];

let tmin = option.startGap * option.stations,
tmax = d3.max(buses, (d) => d.arrives),
rndArrives = d3.randomUniform(tmin, tmax),
rndStation = d3.randomInt(option.stations);

// Passengers randomly arrive
for (let i = 0; i < option.passengers; ++i) {
passengers.push({
passenger: i,
arrives: rndArrives(),
station: rndStation()
});
}

// Passengers take which bus
passengers.map((p) => {
let b = d3.sort(
buses.filter((b) => b.station === p.station && b.arrives > p.arrives),
(d) => d.arrives
)[0];

if (b) {
let leaves = b.arrives,
waits = leaves - p.arrives;
Object.assign(p, { leaves, waits, bus: b });
}
});

return passengers.filter((d) => d.waits);
}
Insert cell
buses = generateBuses()
Insert cell
buses
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
generateBuses = () => {
let buses = [];

let t, t0;

for (let i = 0; i < option.buses; ++i) {
// Bus starts
t0 = i * option.startGap;
t = t0;
for (let j = 0; j < option.stations; ++j) {
// Bus moves to the next station
t += randomNormal();
buses.push({ bus: i, station: j, arrives: t, costs: t - t0 });
}
}

return buses;
}
Insert cell
randomNormal = d3.randomNormal(option.startGap, option.std)
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