Public
Edited
Sep 11, 2024
Insert cell
Insert cell
Insert cell
Plot.plot({
grid: true,
width,
x: {
nice: 5,
ticks: 5
},
y: {
tickFormat: "s",
zero: true,
nice: 3,
ticks: 3
},
marks: [
Plot.line(combined, {
x: "date",
y: "value",
strokeOpacity: 0.3,
strokeWidth: 0.5
}),
Plot.line(
combined,
Plot.windowY({ x: "date", y: "value", k: 14, tip: true })
)
]
})
Insert cell
extent = d3.extent(combined, (d) => d.date)
Insert cell
combined = d3.sort([...past_years_data, ...this_year_data], (d) => d.date)
Insert cell
this_year_data = {
const url = `https://www.tsa.gov/travel/passenger-volumes`;
const response = await fetch(`https://paulmurray.io/api/cors?url=${url}`);
const text = await response.text();
return parseTable(text).map((d) => ({
...d,
date: d3.timeParse("%m/%d/%Y")(d.Date),
value: +d[this_year]?.replace(/,/g, "")
}));
}
Insert cell
past_years_data = Promise.all(
d3
.range(2019, this_year)
.map((year) => `https://www.tsa.gov/travel/passenger-volumes/${year}`)
.map((url) => {
const full_url = `https://paulmurray.io/api/cors?url=${url}`;
console.log(`fetch:`, full_url);
return fetch(full_url)
.then((res) => res.text())
.then((html) => parseTable(html));
})
).then((arrays) =>
arrays.flat().map((d) => ({
...d,
date: d3.timeParse("%m/%d/%Y")(d.Date),
value: +d.Numbers?.replace(/,/g, "")
}))
)
Insert cell
function parseTable(string) {
console.log(string);
const parser = new DOMParser();
const doc = parser.parseFromString(string, "text/html");
const table = doc.querySelector("table");
const data = [];
const [header, ...rows] = Array.from(table.querySelectorAll("tr"));
const headers = Array.from(header.querySelectorAll("th")).map((th) =>
th.textContent.trim()
);
for (const row of rows) {
const rowData = {};
Array.from(row.querySelectorAll("td")).forEach((cell, j) => {
rowData[headers[j]] = cell.textContent.trim();
});
data.push(rowData);
}
return data;
}
Insert cell
this_year = new Date().getFullYear()
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