spec = {
const origin = vl.selectPoint().fields('origin')
.on('mouseover').nearest(true);
const map = vl.markGeoshape({fill: '#ddd', stroke: '#fff', strokeWidth: 1})
.data(vl.topojson('data/us-10m.json').feature('states'));
const foreign = vl.data('data/airports.csv').key('iata').fields('latitude', 'longitude');
const routes = vl.markRule({color: '#000', opacity: 0.35})
.data('data/flights-airport.csv')
.transform(
vl.filter(origin.empty(false)),
vl.lookup('origin').from(foreign),
vl.lookup('destination').from(foreign).as('lat2', 'lon2')
)
.encode(
vl.latitude().fieldQ('latitude'),
vl.longitude().fieldQ('longitude'),
vl.latitude2().field('lat2'),
vl.longitude2().field('lon2')
);
const points = vl.markCircle()
.data('data/flights-airport.csv')
.transform(
vl.groupby('origin').aggregate(vl.count().as('routes')),
vl.lookup('origin').from(foreign.fields('state', 'latitude', 'longitude')),
vl.filter('datum.state !== "PR" && datum.state !== "VI"')
)
.select(origin)
.encode(
vl.latitude().fieldQ('latitude'),
vl.longitude().fieldQ('longitude'),
vl.size().fieldQ('routes').scale({range: [0, 1000]}).legend(null),
vl.order().fieldQ('routes').sort('descending')
);
return vl.layer(map, routes, points)
.project(vl.projection('albersUsa'))
.width(900).height(500)
.config({view: {stroke: null}});
}