Public
Edited
Mar 1, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
map = {
worldMap.select("#cities").remove()
worldMap.select("#connections").remove()
worldMap.select("#names").remove()

let nodes = data.nodes.filter(row=> row['rank'] === 'rank_' + index);
let edges = processEdges(nodes);

worldMap.append("g")
.attr("id", "connections")
.selectAll("paths")
.data(edges)
.enter()
.append("path")
.attr("d", (d) => {
let src = [d['src_lng'], d['src_lat']];
let trg = [d['trg_lng'], d['trg_lat']];
let toDraw = {type: "LineString", coordinates: [src, trg]};
let fullPath = mapPath(toDraw);
return fullPath;
})
.attr("stroke", (d) => {
if (d['new_route'] === 'True') {
return newRouteColor;
} else {
return oldRouteColor;
}
})
.attr("stroke-opacity", (d) => {
if (year === '2050') {
if (d['new_route'] === 'True') {
return 0.1;
} else {
return linkOpacity;
}
} else {
return linkOpacity;
}
})
.attr("fill", "none")
.attr("stroke-linecap", "round")
.attr("stroke-width", (d) => widthFxn(d[linkBase]));

worldMap.append("g")
.attr("id", "cities")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("transform", d => `translate(${mapProjection([d[lngBase], d[latBase]])})`)
.attr('r', d => radiusFxn(d[radBase]))
.attr('fill', d => rankScale(d['rank']))
.attr("stroke", 'white')//d => colorScale(d[colorBase]) === '#000000' ? 'white' : 'black')
.attr("stroke-width", 0.5)

return worldMap.node()
}
Insert cell
function processEdges(nodes) {
let nodeIds = nodes.map(row => row['id'] + '|' + row['country']);
return data.edges.filter(row => nodeIds.includes(getName(row, 'src')) && nodeIds.includes(getName(row, 'target')));
}
Insert cell
processEdges(data.nodes.slice(5))
Insert cell
function getName(row, key) {
if (key === 'src') {
return row['source'] + '|' + row['src_country'];
} else {
return row['target'] + '|' + row['trg_country'];
}
}
Insert cell
Insert cell
colorRange = ["#F5DA49", "#C5BA48", "#96B478", "#679DA6", "#4C8EDA"]
Insert cell
colorDomain = ['rank_0', 'rank_1', 'rank_2', 'rank_3', 'rank_4']
Insert cell
rankScale = d3.scaleOrdinal().domain(colorDomain).range(colorRange);
Insert cell
widthFxn = d3.scaleLinear().domain(widthDomain).range(widthRange)
Insert cell
widthDomain = {
let flatArray = [].concat.apply([], [old_edges, new_edges]);
let counts = []
for (let i in flatArray) {
let row = flatArray[i];
counts.push(parseInt(row[radBase]));
}

return d3.extent(counts);
}
Insert cell
linkOpacity = 0.1
Insert cell
newRouteColor = "#ff6700"
Insert cell
oldRouteColor = "#87BBEC"
Insert cell
data.nodes[0]
Insert cell
radBase = year === 2019 ? "total_flights" : 'total_flights_2050';
Insert cell
linkBase = year === 2019 ? "total_flights" : 'total_flights_2050';
Insert cell
colorBase = year === 2019 ? "community" : 'community_all_combined';
Insert cell
lngBase = 'city_lng'
Insert cell
latBase = 'city_lat'
Insert cell
colorScale = d3.scaleOrdinal().domain(communityDomain).range(['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#ffffff', '#000000']);
Insert cell
Insert cell
Insert cell
Insert cell
data = {
if (year == 2019) {
return {nodes: old_nodes.sort(function compareFn(a, b) {return b['total_flights'] - a['total_flights']}), edges: old_edges};
} else {
return {nodes: new_nodes.sort(function compareFn(a, b) {return b['total_flights_2050'] - a['total_flights_2050']}), edges: new_edges};
}
}
Insert cell
Insert cell
new_edges = FileAttachment("new-all-city-year-edges-small.csv").csv({typed: true})
Insert cell
old_nodes = FileAttachment("all-whole-year-city-nodes.csv").csv({typed: true})
Insert cell
old_edges = FileAttachment("all-whole-year-city-edges.csv").csv({typed: true})
Insert cell
Insert cell
import {legend, Swatches} from "@d3/color-legend"
Insert cell
import {rangeSlider} from '@mootari/range-slider'
Insert cell
import {mapProjection, mapPath, activeColorScheme, worldMap} from "b3a0a78984d6df2e"
Insert cell
import {slider} from "@jashkenas/inputs"
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