Public
Edited
Dec 10, 2023
Insert cell
Insert cell
airportDelays = d3.json("https://raw.githubusercontent.com/e9d8v/cs448b/main/airports_delays.json", function(d) {
return {
airport: d.origin_airport,
delayRate: +d.delay_rate,
flights: +d.flights_count
};
});


Insert cell
height = 500
width = 800
margin = { top: 20, right: 30, bottom: 40, left: 90 }

svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("width", "100%")
.style("height", "auto");

Insert cell
xScale = d3.scaleBand()
.domain(airportDelays.map(d => d.airport))
.range([margin.left, width - margin.right])

yScale = d3.scaleLinear()
.domain([0, d3.max(airportDelays, d => d.delayRate)])
.range([height - margin.bottom, margin.top])

colorScale = d3.scaleSequential(d3.interpolateReds)
.domain([0, d3.max(airportDelays, d => d.delayRate)])

sizeScale = d3.scaleLinear()
.domain(d3.extent(airportDelays, d => d.flights))
.range([5, 20]) // Adjust the min and max size as needed
Insert cell
svg.selectAll("rect")
.data(airportDelays)
.join("rect")
.attr("x", d => xScale(d.airport))
.attr("y", d => yScale(d.delayRate))
.attr("width", xScale.bandwidth())
.attr("height", d => sizeScale(d.flights))
.attr("fill", d => colorScale(d.delayRate));
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale))

yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale))

svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
Insert cell
tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);

svg.selectAll("rect")
.on("mouseover", (event, d) => {
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`Airport: ${d.airport}<br/>Delay Rate: ${d.delayRate}<br/>Flights: ${d.flights}`)
.style("left", (event.pageX) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mouseout", d => {
tooltip.transition().duration(500).style("opacity", 0);
});

Insert cell
slider = d3.sliderBottom()
.min(d3.min(airportDelays, d => d.flights))
.max(d3.max(airportDelays, d => d.flights))
.width(300)
.tickFormat(d3.format('.2s'))
.on('onchange', val => {
svg.selectAll("rect")
.data(airportDelays.filter(d => d.flights >= val))
.join("rect")
// ... rest of the attributes as in Step 4
});

d3.select('div#slider')
.append('svg')
.attr('width', 500)
.attr('height', 100)
.append('g')
.attr('transform', 'translate(30,30)')
.call(slider);
Insert cell
margin = ({top: 20, right: 0, bottom: 40, left: 50})
Insert cell
width = 800 - margin.left - margin.right
Insert cell
height = 600 - margin.top - margin.bottom
Insert cell
xScale = {
const scale = d3.scaleBand()
.domain(airportDelays.map(d => d.airport))
.rangeRound([0, width])
.paddingInner(0.1);
return scale;
}
Insert cell
yScale = {
const scale = d3.scaleLinear()
.domain([0, d3.max(airportDelays, d => d.delayRate)])
.range([height, 0]);
return scale;
}
Insert cell
colorScale = {
return d3.scaleSequential(d3.interpolateReds)
.domain([0, d3.max(airportDelays, d => d.delayRate)]);
}
Insert cell
sizeScale = {
return d3.scaleSqrt()
.domain([0, d3.max(airportDelays, d => d.flights)])
.range([0, xScale.bandwidth()]);
}
Insert cell
tooltip = d3.select(DOM.element('div'))
.attr('class', 'tooltip')
.style('opacity', 0)
.style('position', 'absolute')
.style('text-align', 'center')
.style('width', '120px')
.style('height', '28px')
.style('padding', '2px')
.style('font', '12px sans-serif')
.style('background', 'lightsteelblue')
.style('border', '0px')
.style('border-radius', '8px')
.style('pointer-events', 'none')

Insert cell
slider = {
const div = d3.create('div');
div.append('input')
.attr('type', 'range')
.attr('min', 0)
.attr('max', d3.max(airportDelays, d => d.flights))
.attr('value', 0)
.on('input', function() {
const threshold = +this.value;
d3.selectAll('rect')
.attr('visibility', d => d.flights >= threshold ? 'visible' : 'hidden');
});
return div.node();
}
Insert cell
heatmap = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width + margin.left + margin.right, height + margin.top + margin.bottom])
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

svg.selectAll("rect")
.data(airportDelays)
.enter().append("rect")
.attr("x", d => xScale(d.airport))
.attr("y", d => yScale(d.delayRate))
.attr("width", d => sizeScale(d.flights))
.attr("height", d => height - yScale(d.delayRate))
.attr("fill", d => colorScale(d.delayRate))
.on("mouseover", (event, d) => {
tooltip.style('opacity', 1);
tooltip.html(`Airport: ${d.airport}<br>Delay Rate: ${d.delayRate}<br>Flights: ${d.flights}`)
.style('left', `${event.pageX}px`)
.style('top', `${event.pageY - 28}px`);
})
.on("mouseout", () => tooltip.style('opacity', 0));

return svg.node();
}

Insert cell
// heatmap = {
// const svg = d3.create("svg")
// .attr("viewBox", [0, 0, width, height]);

// svg.selectAll("rect")
// .data(airportDelays)
// .enter().append("rect")
// .attr("x", d => xScale(d.airport))
// .attr("y", d => yScale(d.delayRate))
// .attr("width", d => sizeScale(d.flights))
// .attr("height", d => height - yScale(d.delayRate))
// .attr("fill", d => colorScale(d.delayRate));

// 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