Public
Edited
Dec 10, 2023
Insert cell
Insert cell
map = mapFunc2(mapdata2)
Insert cell
map2 = mapFunc(mapdata, ['test'])
Insert cell
Insert cell
mapFunc2 = (raw) => {
const width = 975;
const height = 610;
const margin = 35;

// Adjust the data filtering
const data = raw.filter(d => d.NAME !== undefined && d.NAME > 1);

const projection = d3.geoAlbersUsa().scale(1300).translate([width / 2, height / 2]);
const path = d3.geoPath();

const svg = d3.create('svg')
.attr("viewBox", [-margin, -2 * margin, width + margin, height + 2.5 * margin]);

const statesBackground = svg
.append('path')
.attr('fill', '#ddd')
.attr('d', path(topojson.feature(us, us.objects.nation)));

const statesBorders = svg
.append('path')
.attr('fill', 'none')
.attr('stroke', '#fff')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('d', path(topojson.mesh(us, us.objects.states, (a, b) => a !== b)));

const stateCapitalElements = svg
.selectAll('g')
.data(data)
.join('g');

// Define the scale function
const scale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d.Q2) || 1])
.range([2, 20]);

const capitalGroups = stateCapitalElements
.append('g')
.attr('transform', ({ INTPTLONG, INTPTLAT }) => {
const coords = projection([INTPTLONG, INTPTLAT]);
return coords ? `translate(${coords.join(",")})` : "translate(0,0)";
});

capitalGroups.append('circle')
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', ({ Q2 }) => Q2 ? scale(Q2) : scale(1));

const tooltip = svg.append("g");

svg
.selectAll('g')
.on('touchmove mousemove', function(event, d) {
tooltip.call(
callout,
`${d.Q7}, ${d.Code}\nMedian salary: ${d3.format("($,")(d.Q2)}\nNo. respondents: ${d.NAME}`
);
tooltip.attr("transform", `translate(${d3.pointer(event, this)[0]},${d3.pointer(event, this)[1]+10})`);
d3.select(this).select('circle')
.attr("fill", "#ffc87c")
.attr('stroke', "#ffc87c")
})
.on("touchend mouseleave", function() {
tooltip.call(callout, null);
d3.select(this).select('circle')
.attr("fill", 'steelblue')
.attr('stroke', 'steelblue')
});

svg.append("text")
.attr("x", -margin)
.attr("y", -margin - 10)
.attr("text-anchor", "left")
.style("font-family", "Georgia")
.style("font-size", "18px")
.text('Median Salary by City');

svg.append("text")
.attr("x", -margin)
.attr("y", 10-margin)
.attr("text-anchor", "left")
.style("font-size", "14px")
.style("font-style", "italic")
.text('Cities with fewer than 2 respondents are not included');

svg.append("text")
.attr("x", width-3*margin)
.attr("y", -0.5*margin+3)
.attr("text-anchor", "left")
.style("font-family", "sans-serif")
.style("font-size", "0.7em")
.style("font-weight", "bold")
.text('$120,000');

svg.append("circle")
.attr("cx", width-4*margin)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(120000));

svg.append("circle")
.attr("cx", width-4*margin-50)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(90000));

svg.append("circle")
.attr("cx", width-4*margin-83)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(60000));

svg.append("circle")
.attr("cx", width-4*margin-103)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(30000));

svg.append("text")
.attr("x", width-4*margin-160)
.attr("y", -0.5*margin+3)
.attr("text-anchor", "left")
.style("font-family", "sans-serif")
.style("font-size", "0.7em")
.style("font-weight", "bold")
.text('$30,000');
return svg.node();
};

Insert cell
Insert cell
airports_jsonData = d3.json("https://raw.githubusercontent.com/e9d8v/cs448b/main/airports.json").then(function(airports_jsonData) {
// Assuming jsonData is already in the correct format
return airports_jsonData;
});
Insert cell
airportsData = airports_jsonData
Insert cell
Insert cell
mapdata2 = Object.entries(airportsData).map(([key, item], index) => ({
":": index,
"City/State": `${item.city}${item.state}`,
"Q2": item.delay_rate, // Assuming delay_rate corresponds to Q2
"Q7": item.city,
"Code": item.state,
"INTPTLAT": parseFloat(item.latitude),
"INTPTLONG": parseFloat(item.longitude),
"NAME": item.flights_count // Assuming flights_count corresponds to NAME
}))

Insert cell
scale = d3.scaleLinear()
.domain([30000, 120000])
.range([2, 25])
Insert cell
scale(35000)
Insert cell
scale(80000)
Insert cell
Insert cell
Insert cell
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