Skip to main content

Airport Connections Example

Vega Airport Connections Example and the corresponding tutorial.

Vega example



NetPanorama example

Vega specification


{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "Interactive map of U.S. airport connections in 2008.",
"width": 900,
"height": 560,
"padding": {"top": 25, "left": 0, "right": 0, "bottom": 0},
"autosize": "none",

Signals required for interactivity



"signals": [
{
"name": "scale", "value": 1200,
"bind": {"input": "range", "min": 500, "max": 3000}
},
{
"name": "translateX", "value": 450,
"bind": {"input": "range", "min": -500, "max": 1200}
},
{
"name": "translateY", "value": 260,
"bind": {"input": "range", "min": -300, "max": 700}
},
{
"name": "shape", "value": "line",
"bind": {"input": "radio", "options": ["line", "curve"]}
},
{
"name": "hover",
"value": null,
"on": [
{"events": "@cell:mouseover", "update": "datum"},
{"events": "@cell:mouseout", "update": "null"}
]
},
{
"name": "title",
"value": "U.S. Airports, 2008",
"update": "hover ? hover.name + ' (' + hover.iata + ')' : 'U.S. Airports, 2008'"
},
{
"name": "cell_stroke",
"value": null,
"on": [
{"events": "dblclick", "update": "cell_stroke ? null : 'brown'"},
{"events": "mousedown!", "update": "cell_stroke"}
]
}
],


"data": [

load data for background map


{
"name": "states",
"url": "https://vega.github.io/vega/data/us-10m.json",
"format": {"type": "topojson", "feature": "states"},
"transform": [
{
"type": "geopath",
"projection": "projection"
}
]
},

load flight data, and apply transform to calculate total number of flights per airport


{
"name": "traffic",
"url": "https://vega.github.io/vega/data/flights-airport.csv",
"format": {"type": "csv", "parse": "auto"},
"transform": [
{
"type": "aggregate",
"groupby": ["origin"],
"fields": ["count"], "ops": ["sum"], "as": ["flights"]
}
]
},

Load airport data and transform: join with flight counts, remove airports with no flights, project lat/lon,

remove airports with unknown location, compute Voroni cell around each airport, and sort by flight count


{
"name": "airports",
"url": "https://vega.github.io/vega/data/airports.csv",
"format": {"type": "csv","parse": "auto"
},
"transform": [
{
"type": "lookup",
"from": "traffic", "key": "origin",
"fields": ["iata"], "as": ["traffic"]
},
{
"type": "filter",
"expr": "datum.traffic != null"
},
{
"type": "geopoint",
"projection": "projection",
"fields": ["longitude", "latitude"]
},
{
"type": "filter",
"expr": "datum.x != null && datum.y != null"
},
{
"type": "voronoi", "x": "x", "y": "y"
},
{
"type": "collect", "sort": {
"field": "traffic.flights",
"order": "descending"
}
}
]
},

load flight data, and transform to: remove all rows except for those whose origin is the hovered-over airport, then construct linkpath


{
"name": "routes",
"url": "https://vega.github.io/vega/data/flights-airport.csv",
"format": {"type": "csv", "parse": "auto"},
"transform": [
{
"type": "filter",
"expr": "hover && hover.iata == datum.origin"
},
{
"type": "lookup",
"from": "airports", "key": "iata",
"fields": ["origin", "destination"], "as": ["source", "target"]
},
{
"type": "filter",
"expr": "datum.source && datum.target"
},
{
"type": "linkpath",
"shape": {"signal": "shape"}
}
]
}
],

Projections and scales



"projections": [
{
"name": "projection",
"type": "albersUsa",
"scale": {"signal": "scale"},
"translate": [{"signal": "translateX"}, {"signal": "translateY"}]
}
],

"scales": [
{
"name": "size",
"type": "linear",
"domain": {"data": "traffic", "field": "flights"},
"range": [16, 1000]
}
],



"marks": [

draw shapes for states


{
"type": "path",
"from": {"data": "states"},
"encode": {
"enter": {
"fill": {"value": "#dedede"},
"stroke": {"value": "white"}
},
"update": {
"path": {"field": "path"}
}
}
},

draw a circle for each airport


{
"type": "symbol",
"from": {"data": "airports"},
"encode": {
"enter": {
"size": {"scale": "size", "field": "traffic.flights"},
"fill": {"value": "steelblue"},
"fillOpacity": {"value": 0.8},
"stroke": {"value": "white"},
"strokeWidth": {"value": 1.5}
},
"update": {
"x": {"field": "x"},
"y": {"field": "y"}
}
}
},

draw an invisible Voronoi cell around each airport to act as a hover target


{
"type": "path",
"name": "cell",
"from": {"data": "airports"},
"encode": {
"enter": {
"fill": {"value": "transparent"},
"strokeWidth": {"value": 0.35}
},
"update": {
"path": {"field": "path"},
"stroke": {"signal": "cell_stroke"}
}
}
},

draw a path for each flight route from the hovered node


{
"type": "path",
"interactive": false,
"from": {"data": "routes"},
"encode": {
"enter": {
"path": {"field": "path"},
"stroke": {"value": "black"},
"strokeOpacity": {"value": 0.35}
}
}
},

display the name of the hovered airport


{
"type": "text",
"interactive": false,
"encode": {
"enter": {
"x": {"value": 895},
"y": {"value": 0},
"fill": {"value": "black"},
"fontSize": {"value": 20},
"align": {"value": "right"}
},
"update": {
"text": {"signal": "title"}
}
}
}
]
}

NetPanorama specification


{

Define paramaters: my_selection will be directly updated by interactions, and then neighbours will be auto-updated to include its neighbours.


"parameters": [
{
"name": "my_selection",
"action": "replace",
"network": "network",
"type": "selection"
},
{
"name": "neighbours",
"source": "my_selection",
"transform": [
{ "type": "neighbours", "direction": "both" }
]
}
],

Load data...


"data": [
{
"name": "links",
"url": "https://vega.github.io/vega/data/flights-airport.csv",
"format": {"type": "csv", "parse": "auto"}
},
{
"name": "nodes",
"url": "https://vega.github.io/vega/data/airports.csv",
"format": {"type": "csv","parse": "auto"},
"transform": [
{"type": "calculate", "calculate": "datum.iata", "as": "id"}
]
}
],

...and assemble into a network. Then remove nodes with no connections, and calculate total flight count for each airport.


"networks": [
{
"name": "network",
"nodes": "nodes",
"links": "links",
"directed": true,
"source_node": [ "iata", "origin" ],
"target_node": [ "iata", "destination" ],

"transform": [
{"type": "removeIsolated"},
{"type": "connectivityBasedAttribute", "as": "flights", "attributeSelector": "link.count", "operation": "sum"}
]
}
],

Define a scale to set the node sizes.


"scales": [
{
"name": "size",
"type": "linear",
"domain": [0, 1000000],
"range": [16, 1000]
}
],

Specify which basemap to use, and which geographic region to show.


"maps": [
{
"name": "my_map",
"tiles": "Stamen_TerrainBackground",
"zoomLevel": 4,
"center": [40, -87.3]
}
],

Construct a layout that positions nodes correctly relative to the basemap.


"layouts": [
{
"name": "map-layout",
"network": "network",

"map": "my_map",
"lat": { "field": "latitude" },
"lng": { "field": "longitude" }
}
],

/


"vis": [

Render links to neighbours of the selected node.


{
"entries": "network.links",
"ifInSelection": "neighbours.links",

"layout": "map-layout",
"mark": {
"type": "linkpath",

"start": "source",
"end": "target",

"strokeWidth": 1,

"stroke": "black"
}
},

Render nodes.


{
"entries": "network.nodes",
"layout": "map-layout",
"mark": {
"type": "circle",
"area": { "field": "data.flights", "scale": "size" },
"fill": "steelblue",
"fillOpacity": 0.8,
"stroke": "white"

},

On mouseover, update the selected node.


"actions": [
{
"interaction": "select",
"using": "cursor",
"event": "mouseover",
"action": "replace",
"selection": "my_selection"
}
]


},

Display name and IATA code for selected node.


{
"mark": {
"type": "text",
"x": 20,
"y": 40,
"fontSize": 30,
"text": {"expression": "(params.my_selection.nodes.length > 0) ? (params.my_selection.nodes[0].name + ' (' + params.my_selection.nodes[0].iata + ')' ) : '' "}
}
},

Display the basemap.


{
"mark":{
"type": "map",
"map": "my_map"
}
}
]

}