Skip to content

Chapter 13: Airport Network

Binder

%load_ext autoreload
%autoreload 2
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
import networkx as nx
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

Introduction

In this chapter, we will analyse the evolution of US Airport Network between 1990 and 2015. This dataset contains data for 25 years[1995-2015] of flights between various US airports and metadata about these routes. Taken from Bureau of Transportation Statistics, United States Department of Transportation.

Let's see what can we make out of this!

from nams import load_data as cf
pass_air_data = cf.load_airports_data()

In the pass_air_data dataframe we have the information of number of people that fly every year on a particular route on the list of airlines that fly that route.

pass_air_data.head()


id
YEAR

 
ORIGIN

 
DEST

 
UNIQUE_CARRIER_NAME

 
PASSENGERS

 
0 1990 ABE ACY {'US Airways Inc.'} 73
1 1990 ABE ATL {'Eastern Air Lines Inc.'} 73172
2 1990 ABE AVL {'Westair Airlines Inc.'} 0
3 1990 ABE AVP {'Westair Airlines Inc.', 'US Airways Inc.', 'E... 8397
4 1990 ABE BHM {'Eastern Air Lines Inc.'} 59

Every row in this dataset is a unique route between 2 airports in United States territory in a particular year. Let's see how many people flew from New York JFK to Austin in 2006.

NOTE: This will be a fun chapter if you are an aviation geek and like guessing airport IATA codes.

jfk_aus_2006 = (pass_air_data
 .query('YEAR == 2006')
 .query("ORIGIN == 'JFK' and DEST == 'AUS'"))

jfk_aus_2006.head()


id
YEAR

 
ORIGIN

 
DEST

 
UNIQUE_CARRIER_NAME

 
PASSENGERS

 
215634 2006 JFK AUS {'Shuttle America Corp.', 'Ameristar Air Cargo'... 105290

From the above pandas query we see that according to this dataset 105290 passengers travelled from JFK to AUS in the year 2006.

But how does this dataset translate to an applied network analysis problem? In the previous chapter we created different graph objects for every book. Let's create a graph object which encompasses all the edges.

NetworkX provides us with Multi(Di)Graphs to model networks with multiple edges between two nodes.

In this case every row in the dataframe represents a directed edge between two airports, common sense suggests that if there is a flight from airport A to airport B there should definitely be a flight from airport B to airport A, i.e direction of the edge shouldn't matter. But in this dataset we have data for individual directions (A -> B and B -> A) so we create a MultiDiGraph.

passenger_graph = nx.from_pandas_edgelist(
    pass_air_data, source='ORIGIN',
    target='DEST', edge_key='YEAR',
    edge_attr=['PASSENGERS', 'UNIQUE_CARRIER_NAME'],
    create_using=nx.MultiDiGraph())

We have created a MultiDiGraph object passenger_graph which contains all the information from the dataframe pass_air_data. ORIGIN and DEST represent the column names in the dataframe pass_air_data used to construct the edge. As this is a MultiDiGraph we can also give a name/key to the multiple edges between two nodes and edge_key is used to represent that name and in this graph YEAR is used to distinguish between multiple edges between two nodes. PASSENGERS and UNIQUE_CARRIER_NAME are added as edge attributes which can be accessed using the nodes and the key form the MultiDiGraph object.

Let's check if can access the same information (the 2006 route between JFK and AUS) using our passenger_graph.

To check an edge between two nodes in a Graph we can use the syntax GraphObject[source][target] and further specify the edge attribute using GraphObject[source][target][attribute].

passenger_graph['JFK']['AUS'][2006]
{'PASSENGERS': 105290.0,
 'UNIQUE_CARRIER_NAME': "{'Shuttle America Corp.', 'Ameristar Air Cargo', 'JetBlue Airways', 'United Parcel Service'}"}

Now let's use our new constructed passenger graph to look at the evolution of passenger load over 25 years.

# Route betweeen New York-JFK and SFO

values = [(year, attr['PASSENGERS'])
          for year, attr in 
          passenger_graph['JFK']['SFO'].items()]
x, y = zip(*values)
plt.plot(x, y)
plt.show()

We see some usual trends all across the datasets like steep drops in 2001 (after 9/11) and 2008 (recession).

# Route betweeen SFO and Chicago-ORD

values = [(year, attr['PASSENGERS'])
          for year, attr in 
          passenger_graph['SFO']['ORD'].items()]
x, y = zip(*values)
plt.plot(x, y)
plt.show()

To find the overall trend, we can use our pass_air_data dataframe to calculate total passengers flown in a year.

pass_air_data.groupby(
    ['YEAR']).sum()['PASSENGERS'].plot()
plt.show()

Exercise

Find the busiest route in 1990 and in 2015 according to number of passengers, and plot the time series of number of passengers on these routes.

You can use the DataFrame instead of working with the network. It will be faster :)

from nams.solutions.airport import busiest_route, plot_time_series
busiest_route(pass_air_data, 1990).head()


id
YEAR

 
ORIGIN

 
DEST

 
UNIQUE_CARRIER_NAME

 
PASSENGERS

 
3917 1990 LAX HNL {'Heavylift Cargo Airlines Lt', 'Hawaiian Airli... 1.82716e+06
plot_time_series(pass_air_data, 'LAX', 'HNL')
busiest_route(pass_air_data, 2015).head()


id
YEAR

 
ORIGIN

 
DEST

 
UNIQUE_CARRIER_NAME

 
PASSENGERS

 
445978 2015 LAX SFO {'Hawaiian Airlines Inc.', 'Delta Air Lines Inc... 1.86907e+06
plot_time_series(pass_air_data, 'LAX', 'SFO')

Before moving to the next part of the chapter let's create a method to extract edges from passenger_graph for a particular year so we can better analyse the data on a granular scale.

def year_network(G, year):
    """ Extract edges for a particular year from
        a MultiGraph. The edge is also populated with
        two attributes, weight and weight_inv where
        weight is the number of passengers and
        weight_inv the inverse of it.
    """
    year_network = nx.DiGraph()
    for edge in G.edges:
        source, target, edge_year = edge
        if edge_year == year:
            attr = G[source][target][edge_year]
            year_network.add_edge(
                source, target,
                weight=attr['PASSENGERS'],
                weight_inv=1/(attr['PASSENGERS']
                if attr['PASSENGERS'] != 0.0 else 1),
                airlines=attr['UNIQUE_CARRIER_NAME'])
    return year_network
pass_2015_network = year_network(passenger_graph, 2015)
# Extracted a Directed Graph from the Multi Directed Graph
# Number of nodes = airports
# Number of edges = routes

print(nx.info(pass_2015_network))
Name: 
Type: DiGraph
Number of nodes: 1258
Number of edges: 25354
Average in degree:  20.1542
Average out degree:  20.1542

Visualise the airports

# Loadin the GPS coordinates of all the airports
from nams import load_data as cf
lat_long = cf.load_airports_GPS_data()
lat_long.columns = [
    "CODE4",
    "CODE3",
    "CITY",
    "PROVINCE",
    "COUNTRY",
    "UNKNOWN1",
    "UNKNOWN2",
    "UNKNOWN3",
    "UNKNOWN4",
    "UNKNOWN5",
    "UNKNOWN6",
    "UNKNOWN7",
    "UNKNOWN8",
    "UNKNOWN9",
    "LATITUDE",
    "LONGITUDE"
]
lat_long
wanted_nodes = list(pass_2015_network.nodes())
us_airports = lat_long.query("CODE3 in @wanted_nodes").drop_duplicates(subset=["CODE3"]).set_index("CODE3")
us_airports
# us_airports


CODE3
CODE4

 
CITY

 
PROVINCE

 
COUNTRY

 
UNKNOWN1

 
UNKNOWN2

 
UNKNOWN3

 
UNKNOWN4

 
UNKNOWN5

 
UNKNOWN6

 
UNKNOWN7

 
UNKNOWN8

 
UNKNOWN9

 
LATITUDE

 
LONGITUDE

 
ABI KABI ABILENE RGNL ABILENE USA 32 24 40 N 99 40 54 W 546 32.411 -99.682
ABQ KABQ nan ALBUQUERQUE USA 0 0 0 U 0 0 0 U 0 0 0
ACK KACK NANTUCKET MEM NANTUCKET USA 41 15 10 N 70 3 36 W 15 41.253 -70.06
ACT KACT WACO RGNL WACO USA 31 36 40 N 97 13 49 W 158 31.611 -97.23
ACY KACY ATLANTIC CITY INTERNATIONAL ATLANTIC CITY USA 39 27 27 N 74 34 37 W 23 39.458 -74.577
ADW KADW ANDREWS AFB CAMP SPRINGS USA 38 48 38 N 76 52 1 W 86 38.811 -76.867
AEX KAEX ALEXANDRIA INTERNATIONAL ALEXANDRIA USA 31 19 38 N 92 32 54 W 28 31.327 -92.548
AGS KAGS AUGUSTA RGNL AT BUSH FLD BUSH FIELD USA 33 22 11 N 81 57 52 W 44 33.37 -81.964
ALB KALB ALBANY INTERNATIONAL ALBANY USA 42 44 53 N 73 48 10 W 87 42.748 -73.803
AMA KAMA AMARILLO INTERNATIONAL AMARILLO USA 35 13 9 N 101 42 21 W 1100 35.219 -101.706
ANB KANB ANNISTON METROPOLITAN ANNISTON USA 33 35 17 N 85 51 29 W 187 33.588 -85.858
AOO KAOO ALTOONA BLAIR CO ALTOONA USA 40 17 47 N 78 19 12 W 459 40.296 -78.32
ARA KARA ACADIANA REGIONAL LOUISIANA USA 30 2 15 N 91 53 2 W 8 30.038 -91.884
ART KART WATERTOWN INTERNATIONAL WATERTOWN USA 43 59 30 N 76 1 18 W 100 43.992 -76.022
ATL KATL THE WILLIAM B HARTSFIELD ATLANTA INTERNATIONAL ATLANTA USA 33 38 25 N 84 25 37 W 313 33.64 -84.427
AUG KAUG AUGUSTA STATE AUGUSTA USA 44 19 14 N 69 47 50 W 108 44.321 -69.797
AUS KAUS AUSTIN BERGSTROM INTERNATIONAL AUSTIN USA 30 11 40 N 97 40 11 W 166 30.194 -97.67
BAD KBAD BARKSDALE AFB SHREVEPORT USA 32 30 6 N 93 39 45 W 51 32.502 -93.663
BCT KBCT BOCA RATON BOCA RATON USA 26 22 42 N 80 6 27 W 4 26.378 -80.107
BDL KBDL BRADLEY INTERNATIONAL WINDSOR LOCKS USA 41 56 20 N 72 40 59 W 53 41.939 -72.683
BDR KBDR IGOR I SIKORSKY MEM STRATFORD USA 41 9 48 N 73 7 34 W 3 41.163 -73.126
BED KBED LAURENCE G HANSCOM FLD BEDFORD USA 42 28 11 N 71 17 20 W 41 42.47 -71.289
BFI KBFI BOEING FLD KING CO INTERNATIONAL SEATTLE USA 47 31 47 N 122 18 7 W 6 47.53 -122.302
BFL KBFL MEADOWS FLD BAKERSFIELD USA 35 26 0 N 119 3 24 W 155 35.433 -119.057
BFM KBFM MOBILE DOWNTOWN MOBILE USA 30 37 35 N 88 4 4 W 8 30.626 -88.068
BGR KBGR BANGOR INTERNATIONAL BANGOR USA 44 48 26 N 68 49 41 W 59 44.807 -68.828
BHM KBHM BIRMINGHAM INTERNATIONAL BIRMINGHAM USA 33 33 46 N 86 45 12 W 197 33.563 -86.753
BIF KBIF BIGGS AAF EL PASO USA 31 50 58 N 106 22 48 W 1203 31.849 -106.38
BLI KBLI BELLINGHAM INTERNATIONAL BELLINGHAM USA 48 47 33 N 122 32 15 W 52 48.792 -122.537
BLV KBLV SCOTT AFB MIDAMERICA BELLEVILLE USA 38 32 42 N 89 50 6 W 140 38.545 -89.835
BNA KBNA NASHVILLE INTERNATIONAL NASHVILLE USA 36 7 28 N 86 40 41 W 183 36.124 -86.678
BOI KBOI BOISE AIR TERMINAL BOISE USA 43 33 51 N 116 13 22 W 876 43.564 -116.223
BOS KBOS GENERAL EDWARD LAWRENCE LOGAN INTERNATIONAL BOSTON USA 42 21 51 N 71 0 18 W 6 42.364 -71.005
BPT KBPT SOUTHEAST TEXAS RGNL BEAUMONT USA 29 57 3 N 94 1 14 W 5 29.951 -94.021
BRO KBRO BROWNSVILLE SOUTH PADRE ISLAND INTERNATIONAL BROWNSVILLE USA 25 54 24 N 97 25 33 W 7 25.907 -97.426
BTR KBTR BATON ROUGE METRO RYAN FLD BATON ROUGE USA 30 31 59 N 91 8 58 W 22 30.533 -91.149
BTV KBTV BURLINGTON INTERNATIONAL BURLINGTON USA 44 28 18 N 73 9 11 W 103 44.472 -73.153
BUF KBUF BUFFALO NIAGARA INTERNATIONAL BUFFALO USA 42 56 25 N 78 43 55 W 221 42.94 -78.732
BUR KBUR BURBANK GLENDALE PASADENA BURBANK USA 34 12 2 N 118 21 31 W 238 34.201 -118.359
BWI KBWI BALTIMORE WASHINGTON INTERNATIONAL BALTIMORE USA 39 10 31 N 76 40 6 W 45 39.175 -76.668
CAE KCAE COLUMBIA METROPOLITAN COLOMBIA USA 33 56 19 N 81 7 10 W 72 33.939 -81.119
CDC KCDC CEDAR CITY RGNL CEDAR CITY USA 37 42 3 N 113 5 55 W 1714 37.701 -113.099
CEF KCEF WESTOVER ARB METROPOLITAN CHICOPEE FALLS USA 42 11 53 N 72 32 3 W 75 42.198 -72.534
CEW KCEW BOB SIKES CRESTVIEW USA 30 46 43 N 86 31 19 W 65 30.779 -86.522
CHA KCHA LOVELL FLD CHATTANOOGA USA 35 2 7 N 85 12 13 W 208 35.035 -85.204
CHS KCHS CHARLESTON AFB INTERNATIONAL CHARLESTON USA 32 53 55 N 80 2 25 W 14 32.899 -80.04
CIC KCIC CHICO MUNI CHICO USA 39 47 43 N 121 51 30 W 73 39.795 -121.858
CLE KCLE CLEVELAND HOPKINS INTERNATIONAL CLEVELAND USA 41 24 42 N 81 50 59 W 242 41.412 -81.85
CLL KCLL EASTERWOOD FLD COLLEGE STATION USA 30 35 18 N 96 21 49 W 98 30.588 -96.364
CLT KCLT CHARLOTTE DOUGLAS INTERNATIONAL CHARLOTTE USA 35 12 50 N 80 56 35 W 229 35.214 -80.943
CMH KCMH PORT COLUMBUS INTERNATIONAL COLUMBUS USA 39 59 52 N 82 53 30 W 249 39.998 -82.892
CNM KCNM CAVERN CITY AIR TERMINAL CARLSBAD USA 32 20 14 N 104 15 47 W 1005 32.337 -104.263
COS KCOS CITY OF COLORADO SPRINGS MUNI COLORADO SPRINGS USA 38 48 20 N 104 42 0 W 1885 38.806 -104.7
COU KCOU COLUMBIA RGNL COLUMBIA USA 38 49 5 N 92 13 10 W 271 38.818 -92.219
CPR KCPR NATRONA CO INTERNATIONAL CASPER USA 42 54 28 N 106 27 51 W 1631 42.908 -106.464
CRP KCRP CORPUS CHRISTI INTERNATIONAL CORPUS CHRISTI USA 27 46 13 N 97 30 4 W 14 27.77 -97.501
CVG KCVG CINCINNATI NORTHERN KENTUCKY INTERNATIONAL CINCINNATI USA 39 2 46 N 84 39 43 W 274 39.046 -84.662
CVS KCVS CANNON AFB CLOVIS USA 34 22 57 N 103 19 19 W 1310 34.383 -103.322
CYS KCYS CHEYENNE CHEYENNE USA 41 9 20 N 104 48 42 W 1877 41.156 -104.812
DAL KDAL DALLAS LOVE FLD DALLAS USA 32 50 49 N 96 51 6 W 149 32.847 -96.852
DAY KDAY JAMES M COX DAYTON INTERNATIONAL DAYTON USA 39 54 8 N 84 13 9 W 308 39.902 -84.219
DCA KDCA RONALD REAGAN WASHINGTON NATIONAL WASHINGTON USA 38 51 7 N 77 2 15 W 5 38.852 -77.037
DEN KDEN DENVER INTERNATIONAL DENVER USA 39 51 30 N 104 40 1 W 1656 39.858 -104.667
DET KDET DETROIT CITY DETROIT USA 42 24 33 N 83 0 35 W 191 42.409 -83.01
DFW KDFW DALLAS FORT WORTH INTERNATIONAL DALLAS-FORT WORTH USA 32 53 47 N 97 2 15 W 184 32.896 -97.037
DHN KDHN DOTHAN RGNL DOTHAN USA 31 19 16 N 85 26 58 W 123 31.321 -85.449
DLH KDLH DULUTH INTERNATIONAL DULUTH USA 46 50 31 N 92 11 37 W 436 46.842 -92.194
DMA KDMA DAVIS MONTHAN AFB TUCSON USA 32 9 59 N 110 52 59 W 825 32.166 -110.883
DOV KDOV DOVER AFB DOVER USA 39 7 48 N 75 27 59 W 10 39.13 -75.466
DPA KDPA DU PAGE WEST CHICAGO USA 41 54 28 N 88 14 55 W 232 41.908 -88.249
DRO KDRO DURANGO LA PLATA CO DURANGO USA 37 9 5 N 107 45 13 W 2038 37.151 -107.754
DRT KDRT DEL RIO INTERNATIONAL DEL RIO USA 29 22 22 N 100 55 33 W 305 29.373 -100.926
DSM KDSM DES MOINES INTERNATIONAL DES MOINES USA 41 32 2 N 93 39 45 W 292 41.534 -93.663
DTW KDTW DETROIT METRO WAYNE CO DETROIT USA 42 12 44 N 83 21 12 W 197 42.212 -83.353
EDW KEDW EDWARDS AFB EDWARDS AFB USA 34 54 19 N 117 53 1 W 702 34.905 -117.884
EFD KEFD ELLINGTON FLD HOUSTON USA 29 36 26 N 95 9 31 W 10 29.607 -95.159
ELD KELD SOUTH ARKANSAS RGNL AT GOODWIN FLD EL DORADO USA 33 13 15 N 92 48 47 W 85 33.221 -92.813
ELP KELP EL PASO INTERNATIONAL EL PASO USA 31 48 24 N 106 22 40 W 1207 31.807 -106.378
ENV KENV WENDOVER WENDOVER USA 40 43 7 N 114 1 51 W 1291 40.719 -114.031
EWN KEWN CRAVEN CO RGNL NEW BERN USA 35 4 22 N 77 2 34 W 6 35.073 -77.043
EWR KEWR NEWARK LIBERTY INTERNATIONAL NEWARK USA 40 41 32 N 74 10 7 W 6 40.692 -74.169
EYW KEYW KEY WEST INTERNATIONAL KEY WEST USA 24 33 22 N 81 45 34 W 1 24.556 -81.759
FAT KFAT FRESNO YOSEMITE INTERNATIONAL FRESNO USA 36 46 34 N 119 43 5 W 103 36.776 -119.718
FFO KFFO WRIGHT PATTERSON AFB DAYTON USA 39 49 34 N 84 2 54 W 251 39.826 -84.048
FLL KFLL FORT LAUDERDALE HOLLYWOOD INTERNATIONAL FORT LAUDERDALE USA 26 4 21 N 80 9 9 W 3 26.072 -80.153
FLO KFLO FLORENCE RGNL FLORENCE USA 34 11 7 N 79 43 26 W 45 34.185 -79.724
FMH KFMH OTIS ANGB FALMOUTH USA 41 39 30 N 70 31 17 W 40 41.658 -70.521
FMN KFMN FOUR CORNERS RGNL FARMINGTON USA 36 44 28 N 108 13 47 W 1679 36.741 -108.23
FMY KFMY PAGE FLD FORT MYERS USA 26 35 11 N 81 51 47 W 6 26.586 -81.863
FOD KFOD FORT DODGE RGNL FORT DODGE USA 42 33 5 N 94 11 33 W 353 42.551 -94.193
FOE KFOE FORBES FLD TOPEKA USA 38 57 3 N 95 39 49 W 329 38.951 -95.664
FOK KFOK THE FRANCIS S GABRESKI WEST HAMPTON BEACH USA 40 50 37 N 72 37 54 W 21 40.844 -72.632
FSI KFSI HENRY POST AAF FORT SILL USA 34 38 59 N 98 24 7 W 363 34.65 -98.402
FSM KFSM FORT SMITH RGNL FORT SMITH USA 35 20 11 N 94 22 2 W 143 35.336 -94.367
FTW KFTW FORT WORTH MEACHAM INTERNATIONAL FORT WORTH USA 32 49 11 N 97 21 44 W 217 32.82 -97.362
FXE KFXE FORT LAUDERDALE EXECUTIVE FORT LAUDERDALE USA 26 11 50 N 80 10 14 W 5 26.197 -80.171
FYV KFYV DRAKE FLD FAYETTEVILLE USA 36 0 18 N 94 10 12 W 382 36.005 -94.17
GCK KGCK GARDEN CITY RGNL GARDEN CITY USA 37 55 39 N 100 43 27 W 881 37.927 -100.724
GEG KGEG SPOKANE INTERNATIONAL SPOKANE USA 47 37 11 N 117 32 1 W 723 47.62 -117.534
GFK KGFK GRAND FORKS INTERNATIONAL GRAND FORKS USA 47 56 57 N 97 10 34 W 258 47.949 -97.176
GGG KGGG EAST TEXAS RGNL LONGVIEW USA 32 23 5 N 94 42 41 W 112 32.385 -94.711
GNV KGNV GAINESVILLE RGNL GAINESVILLE USA 29 41 24 N 82 16 18 W 47 29.69 -82.272
GRB KGRB AUSTIN STRAUBEL INTERNATIONAL GREEN BAY USA 44 29 6 N 88 7 46 W 212 44.485 -88.129
GRF KGRF GRAY AAF FORT LEWIS USA 47 4 45 N 122 34 50 W 93 47.079 -122.581
GRK KGRK ROBERT GRAY AAF KILLEEN USA 31 4 2 N 97 49 44 W 311 31.067 -97.829
GRR KGRR GERALD R FORD INTERNATIONAL GRAND RAPIDS USA 42 52 51 N 85 31 22 W 242 42.881 -85.523
GSB KGSB SEYMOUR JOHNSON AFB GOLDSBORO USA 35 20 21 N 77 57 38 W 34 35.339 -77.961
GTF KGTF GREAT FALLS INTERNATIONAL GREAT FALLS USA 47 28 55 N 111 22 14 W 1121 47.482 -111.371
GUS KGUS GRISSOM ARB PERU USA 40 38 53 N 86 9 7 W 248 40.648 -86.152
GVT KGVT MAJORS GREENVILE USA 33 4 4 N 96 3 55 W 164 33.068 -96.065
HFD KHFD HARTFORD BRAINARD HARTFORD USA 41 44 10 N 72 39 0 W 6 41.736 -72.65
HIB KHIB CHISHOLM HIBBING HIBBING USA 47 23 11 N 92 50 20 W 413 47.386 -92.839
HKY KHKY HICKORY RGNL HICKORY USA 35 44 28 N 81 23 22 W 363 35.741 -81.389
HLN KHLN HELENA RGNL HELENA USA 46 36 24 N 111 58 57 W 1182 46.607 -111.983
HMN KHMN HOLLOMAN AFB ALAMOGORDO USA 32 51 9 N 106 6 23 W 1248 32.852 -106.106
HOB KHOB LEA CO RGNL HOBBS USA 32 41 15 N 103 13 1 W 1116 32.688 -103.217
HON KHON HURON RGNL HURON USA 44 23 6 N 98 13 42 W 393 44.385 -98.228
HOP KHOP CAMPBELL AAF HOPKINSVILLE USA 36 40 6 N 87 29 46 W 175 36.668 -87.496
HOU KHOU WILLIAM P HOBBY HOUSTON USA 29 38 43 N 95 16 44 W 15 29.645 -95.279
HPN KHPN WESTCHESTER CO WHITE PLAINS USA 41 4 1 N 73 42 27 W 134 41.067 -73.707
HRL KHRL VALLEY INTERNATIONAL HARLINGEN USA 26 13 42 N 97 39 15 W 11 26.228 -97.654
HRO KHRO BOONE CO HARRISON USA 36 15 41 N 93 9 17 W 417 36.261 -93.155
HUF KHUF TERRE HAUTE INTERNATIONAL HULMAN FLD TERRE HAUTE USA 39 27 5 N 87 18 27 W 180 39.451 -87.307
HVR KHVR HAVRE CITY CO HAVRE USA 48 32 34 N 109 45 44 W 790 48.543 -109.762
IAB KIAB MC CONNELL AFB WICHITA USA 37 37 22 N 97 16 2 W 418 37.623 -97.267
IAD KIAD WASHINGTON DULLES INTERNATIONAL WASHINGTON USA 38 56 40 N 77 27 20 W 96 38.944 -77.456
IAG KIAG NIAGARA FALLS INTERNATIONAL NIAGARA FALLS USA 43 6 26 N 78 56 46 W 180 43.107 -78.946
IAH KIAH GEORGE BUSH INTCNTL HOUSTON HOUSTON USA 29 58 49 N 95 20 23 W 30 29.98 -95.34
ICT KICT WICHITA MID CONTINENT WICHITA USA 37 38 59 N 97 25 59 W 407 37.65 -97.433
ILG KILG NEW CASTLE CO WILMINGTON USA 39 40 43 N 75 36 23 W 25 39.679 -75.606
ILM KILM WILMINGTON INTERNATIONAL WILMINGTON USA 34 16 14 N 77 54 9 W 10 34.271 -77.903
IND KIND INDIANAPOLIS INTERNATIONAL INDIANAPOLIS USA 39 43 2 N 86 17 39 W 243 39.717 -86.294
INL KINL FALLS INTERNATIONAL INTERNATIONAL FALLS USA 48 33 58 N 93 24 11 W 362 48.566 -93.403
INT KINT SMITH REYNOLDS WINSTON-SALEM USA 36 8 1 N 80 13 19 W 296 36.134 -80.222
IPL KIPL IMPERIAL CO IMPERIAL USA 32 50 3 N 115 34 43 W -17 32.834 -115.579
IPT KIPT WILLIAMSPORT RGNL WILLIAMSPORT USA 41 14 31 N 76 55 16 W 162 41.242 -76.921
ISN KISN SLOULIN FLD INTERNATIONAL WILLISTON USA 48 10 40 N 103 38 32 W 605 48.178 -103.642
ISP KISP LONG ISLAND MAC ARTHUR ISLIP USA 40 47 42 N 73 6 0 W 31 40.795 -73.1
JAN KJAN JACKSON INTERNATIONAL JACKSON USA 32 18 40 N 90 4 33 W 106 32.311 -90.076
JAX KJAX JACKSONVILLE INTERNATIONAL JACKSONVILLE USA 30 29 38 N 81 41 16 W 10 30.494 -81.688
JBR KJBR JONESBORO MUNI JONESBORO USA 35 49 54 N 90 38 46 W 80 35.832 -90.646
JFK KJFK JOHN F KENNEDY INTERNATIONAL NEW YORK USA 40 38 23 N 73 46 44 W 4 40.64 -73.779
LAN KLAN CAPITAL CITY LANSING USA 42 46 43 N 84 35 14 W 263 42.779 -84.587
LAS KLAS MC CARRAN INTERNATIONAL LAS VEGAS USA 36 4 49 N 115 9 8 W 665 36.08 -115.152
LAX KLAX LOS ANGELES INTERNATIONAL LOS ANGELES USA 33 56 33 N 118 24 29 W 39 33.942 -118.408
LBB KLBB LUBBOCK INTERNATIONAL LUBBOCK USA 33 39 49 N 101 49 22 W 1001 33.664 -101.823
LCH KLCH LAKE CHARLES RGNL LAKE CHARLES USA 30 7 34 N 93 13 24 W 5 30.126 -93.223
LCK KLCK RICKENBACKER INTERNATIONAL COLUMBUS USA 39 48 49 N 82 55 40 W 227 39.814 -82.928
LFI KLFI LANGLEY AFB HAMPTON USA 37 4 58 N 76 21 37 W 4 37.083 -76.36
LFT KLFT LAFAYETTE RGNL LAFAYETTE USA 30 12 19 N 91 59 15 W 13 30.205 -91.987
LGA KLGA LA GUARDIA NEW YORK USA 40 46 38 N 73 52 21 W 7 40.777 -73.872
LGB KLGB LONG BEACH LONG BEACH USA 33 49 3 N 118 9 5 W 19 33.818 -118.151
LIT KLIT ADAMS FLD LITTLE ROCK USA 34 43 46 N 92 13 27 W 80 34.729 -92.224
LNK KLNK LINCOLN MUNI LINCOLN USA 40 51 3 N 96 45 33 W 372 40.851 -96.759
LRD KLRD LAREDO INTERNATIONAL LAREDO USA 27 32 37 N 99 27 41 W 155 27.544 -99.461
LSF KLSF LAWSON AAF FORT BENNING USA 32 20 14 N 84 59 28 W 71 32.337 -84.991
LSV KLSV NELLIS AFB LAS VEGAS USA 36 14 10 N 115 2 3 W 570 36.236 -115.034
LUK KLUK CINCINNATI MUNI LUNKEN FLD CINCINNATI USA 39 6 12 N 84 25 7 W 148 39.103 -84.419
MAF KMAF MIDLAND INTERNATIONAL MIDLAND USA 31 56 33 N 102 12 6 W 876 31.942 -102.202
MCC KMCC MC CLELLAN AFLD SACRAMENTO USA 38 40 3 N 121 24 2 W 23 38.667 -121.401
MCF KMCF MACDILL AFB TAMPA USA 27 50 57 N 82 31 16 W 5 27.849 -82.521
MCI KMCI KANSAS CITY INTERNATIONAL KANSAS CITY USA 39 17 51 N 94 42 50 W 313 39.297 -94.714
MCN KMCN MIDDLE GEORGIA RGNL MACON USA 32 41 34 N 83 38 57 W 108 32.693 -83.649
MCO KMCO ORLANDO INTERNATIONAL ORLANDO USA 28 25 44 N 81 18 57 W 30 28.429 -81.316
MDT KMDT HARRISBURG INTERNATIONAL HARRISBURG USA 40 11 36 N 76 45 48 W 95 40.193 -76.763
MDW KMDW CHICAGO MIDWAY INTERNATIONAL CHICAGO USA 41 47 9 N 87 45 8 W 189 41.786 -87.752
MEM KMEM MEMPHIS INTERNATIONAL MEMPHIS USA 35 2 32 N 89 58 36 W 104 35.042 -89.977
MER KMER CASTLE MERCED USA 37 22 49 N 120 34 5 W 58 37.38 -120.568
MFE KMFE MC ALLEN MILLER INTERNATIONAL MCALLEN USA 26 10 33 N 98 14 19 W 33 26.176 -98.239
MHR KMHR SACRAMENTO MATHER SACRAMENTO USA 38 33 14 N 121 17 51 W 30 38.554 -121.297
MIA KMIA MIAMI INTERNATIONAL MIAMI USA 25 47 35 N 80 17 26 W 3 25.793 -80.291
MIB KMIB MINOT AFB MINOT USA 48 24 56 N 101 21 27 W 509 48.416 -101.357
MKE KMKE GENERAL MITCHELL INTERNATIONAL MILWAUKEE USA 42 56 50 N 87 53 47 W 221 42.947 -87.896
MKL KMKL MC KELLAR SIPES RGNL JACKSON USA 35 35 59 N 88 54 56 W 133 35.6 -88.916
MLB KMLB MELBOURNE INTERNATIONAL MELBOURNE USA 28 6 9 N 80 38 42 W 11 28.103 -80.645
MLU KMLU MONROE RGNL MONROE USA 32 30 39 N 92 2 15 W 25 32.511 -92.037
MOB KMOB MOBILE RGNL MOBILE USA 30 41 29 N 88 14 34 W 67 30.691 -88.243
MOD KMOD MODESTO CITY CO HARRY SHAM MODESTO USA 37 37 32 N 120 57 15 W 30 37.626 -120.954
MOT KMOT MINOT INTERNATIONAL MINOT USA 48 15 33 N 101 16 49 W 519 48.259 -101.28
MQT KMQT SAWYER INTERNATIONAL MARQUETTE USA 46 32 2 N 87 33 42 W 433 46.534 -87.562
MSN KMSN DANE CO RGNL TRUAX FLD MADISON USA 43 8 23 N 89 20 15 W 271 43.14 -89.337
MSP KMSP MINNEAPOLIS ST PAUL INTERNATIONAL MINNEAPOLIS USA 44 52 49 N 93 13 0 W 257 44.88 -93.217
MSS KMSS MASSENA INTERNATIONAL RICHARDS FLD MASSENA USA 44 56 9 N 74 50 43 W 66 44.936 -74.845
MSY KMSY LOUIS ARMSTRONG NEW ORLEANS INTERNATIONAL NEW ORLEANS USA 29 59 36 N 90 15 28 W 2 29.993 -90.258
MWH KMWH GRANT CO INTERNATIONAL GRANT COUNTY AIRPORT USA 47 12 27 N 119 19 12 W 362 47.208 -119.32
MXF KMXF MAXWELL AFB MONTGOMERY USA 32 22 45 N 86 21 45 W 53 32.379 -86.362
MYR KMYR MYRTLE BEACH INTERNATIONAL MYRTLE BEACH USA 33 40 47 N 78 55 42 W 8 33.68 -78.928
NBG KNBG NEW ORLEANS NAS JRB NEW ORLEANS USA 29 49 31 N 90 2 6 W 1 29.825 -90.035
NGU KNGU NORFOLK NS NORFOLK USA 36 56 15 N 76 17 21 W 5 36.938 -76.289
NIP KNIP JACKSONVILLE NAS JACKSONVILLE USA 30 14 9 N 81 40 50 W 7 30.236 -81.681
NJK KNJK EL CENTRO NAF EL CENTRO USA 32 49 45 N 115 40 18 W -13 32.829 -115.672
NKX KNKX MIRAMAR MCAS MIRAMAR USA 32 52 6 N 117 8 33 W 146 32.868 -117.143
NPA KNPA PENSACOLA NAS PENSACOLA USA 30 21 9 N 87 19 7 W 9 30.353 -87.319
NQA KNQA MILLINGTON MUNI MILLINGTON USA 35 21 24 N 89 52 13 W 98 35.357 -89.87
NQX KNQX KEY WEST NAS KEY WEST USA 24 34 33 N 81 41 20 W 2 24.576 -81.689
NTD KNTD POINT MUGU NAS POINT MUGU USA 34 7 13 N 119 7 15 W 4 34.12 -119.121
NTU KNTU OCEANA NAS OCEANA USA 36 49 14 N 76 2 0 W 7 36.821 -76.033
NUQ KNUQ MOFFETT FEDERAL AFLD MOUNTAIN VIEW USA 37 24 54 N 122 2 53 W 10 37.415 -122.048
NUW KNUW WHIDBEY ISLAND NAS WHIDBEY ISLAND USA 48 21 6 N 122 39 21 W 15 48.352 -122.656
NZC KNZC CECIL FLD JACKSONVILLE USA 30 13 7 N 81 52 35 W 25 30.219 -81.876
NZY KNZY NORTH ISLAND NAS SAN DIEGO USA 32 41 57 N 117 12 55 W 8 32.699 -117.215
OAK KOAK METROPOLITAN OAKLAND INTERNATIONAL OAKLAND USA 37 43 16 N 122 13 14 W 2 37.721 -122.221
OFF KOFF OFFUTT AFB OMAHA USA 41 7 6 N 95 54 45 W 321 41.118 -95.913
OGS KOGS OGDENSBURG INTERNATIONAL OGDENSBURG USA 44 40 55 N 75 27 56 W 91 44.682 -75.466
OKC KOKC WILL ROGERS WORLD OKLAHOMA CITY USA 35 23 35 N 97 36 2 W 395 35.393 -97.601
OMA KOMA EPPLEY AFLD OMAHA USA 41 18 9 N 95 53 37 W 300 41.302 -95.894
ONT KONT ONTARIO INTERNATIONAL ONTARIO USA 34 3 21 N 117 36 4 W 288 34.056 -117.601
OPF KOPF OPA LOCKA MIAMI USA 25 54 25 N 80 16 42 W 3 25.907 -80.278
ORD KORD CHICAGO OHARE INTERNATIONAL CHICAGO USA 41 58 46 N 87 54 16 W 204 41.979 -87.904
ORF KORF NORFOLK INTERNATIONAL NORFOLK USA 36 53 40 N 76 12 4 W 8 36.894 -76.201
ORL KORL EXECUTIVE ORLANDO USA 28 32 43 N 81 19 58 W 35 28.545 -81.333
PAE KPAE SNOHOMISH CO EVERETT USA 47 54 22 N 122 16 53 W 185 47.906 -122.281
PAM KPAM TYNDALL AFB PANAMA CITY USA 30 4 11 N 85 34 35 W 6 30.07 -85.576
PBG KPBG PLATTSBURGH INTERNATIONAL PLATTSBURGH USA 44 39 3 N 73 28 5 W 72 44.651 -73.468
PBI KPBI PALM BEACH INTERNATIONAL WEST PALM BEACH USA 26 40 59 N 80 5 44 W 6 26.683 -80.096
PDX KPDX PORTLAND INTERNATIONAL PORTLAND USA 45 35 19 N 122 35 51 W 10 45.589 -122.597
PHF KPHF NEWPORT NEWS WILLIAMSBURG INTERNATIONAL NEWPORT NEWS USA 37 7 54 N 76 29 34 W 14 37.132 -76.493
PHL KPHL PHILADELPHIA INTERNATIONAL PHILADELPHIA USA 39 52 19 N 75 14 28 W 12 39.872 -75.241
PHN KPHN ST CLAIR CO INTERNATIONAL PORT HURON USA 42 54 39 N 82 31 43 W 199 42.911 -82.529
PHX KPHX PHOENIX SKY HARBOR INTERNATIONAL PHOENIX USA 33 26 3 N 112 0 29 W 346 33.434 -112.008
PIE KPIE ST PETERSBURG CLEARWATER INTERNATIONAL ST. PETERSBURG USA 27 54 38 N 82 41 14 W 4 27.911 -82.687
PIT KPIT PITTSBURGH INTERNATIONAL PITTSBURGH (PENNSYLVA) USA 40 29 29 N 80 13 58 W 367 40.491 -80.233
PNE KPNE NORTHEAST PHILADELPHIA PHILADELPHIA USA 40 4 55 N 75 0 38 W 37 40.082 -75.011
PNS KPNS PENSACOLA RGNL PENSACOLA USA 30 28 23 N 87 11 14 W 37 30.473 -87.187
POB KPOB POPE AFB FAYETTEVILLE USA 35 10 15 N 79 0 52 W 67 35.171 -79.014
PQI KPQI NORTHERN MAINE RGNL AT PRESQUE ISLE PRESQUE ISLE USA 46 41 20 N 68 2 41 W 163 46.689 -68.045
PRC KPRC ERNEST A LOVE FLD PRESCOTT USA 34 39 16 N 112 25 10 W 1538 34.654 -112.419
PSP KPSP PALM SPRINGS INTERNATIONAL PALM SPRINGS USA 33 49 46 N 116 30 24 W 145 33.829 -116.507
PUB KPUB PUEBLO MEM PUEBLO MEMORIAL USA 38 17 20 N 104 29 47 W 1441 38.289 -104.496
PVD KPVD THEODORE FRANCIS GREEN STATE PROVIDENCE USA 41 43 26 N 71 25 41 W 17 41.724 -71.428
PWM KPWM PORTLAND INTERNATIONAL JETPORT PORTLAND USA 43 38 46 N 70 18 31 W 23 43.646 -70.309
RCA KRCA ELLSWORTH AFB RAPID CITY USA 44 8 42 N 103 6 12 W 1000 44.145 -103.103
RDU KRDU RALEIGH DURHAM INTERNATIONAL RALEIGH-DURHAM USA 35 52 39 N 78 47 14 W 133 35.877 -78.787
RIC KRIC RICHMOND INTERNATIONAL RICHMOND USA 37 30 18 N 77 19 10 W 51 37.505 -77.319
RIV KRIV MARCH ARB RIVERSIDE USA 33 52 50 N 117 15 34 W 468 33.881 -117.259
RME KRME GRIFFISS AIRPARK ROME USA 43 14 1 N 75 24 25 W 154 43.234 -75.407
RNO KRNO RENO TAHOE INTERNATIONAL RENO USA 39 29 54 N 119 46 5 W 1345 39.498 -119.768
ROC KROC GREATER ROCHESTER INTERNATIONAL ROCHESTER USA 43 7 7 N 77 40 20 W 171 43.119 -77.672
ROW KROW ROSWELL INDUSTRIAL AIR CENTER ROSWELL USA 33 18 5 N 104 31 50 W 1119 33.301 -104.531
RSW KRSW SOUTHWEST FLORIDA INTERNATIONAL FORT MYERS USA 26 32 10 N 81 45 18 W 10 26.536 -81.755
SAC KSAC SACRAMENTO EXECUTIVE SACRAMENTO USA 38 30 45 N 121 29 36 W 8 38.513 -121.493
SAF KSAF SANTA FE MUNI SANTA FE USA 35 37 0 N 106 5 17 W 1935 35.617 -106.088
SAN KSAN SAN DIEGO INTERNATIONAL LINDBERGH FLD SAN DIEGO USA 32 44 0 N 117 11 22 W 5 32.733 -117.189
SAT KSAT SAN ANTONIO INTERNATIONAL SAN ANTONIO USA 29 32 1 N 98 28 11 W 247 29.534 -98.47
SAV KSAV SAVANNAH HILTON HEAD INTERNATIONAL SAVANNAH USA 32 7 39 N 81 12 7 W 16 32.127 -81.202
SBY KSBY SALISBURY OCEAN CITY WICOMICO RGNL SALISBURY USA 38 20 25 N 75 30 37 W 16 38.34 -75.51
SCK KSCK STOCKTON METROPOLITAN STOCKTON USA 37 53 39 N 121 14 19 W 10 37.894 -121.239
SEA KSEA SEATTLE TACOMA INTERNATIONAL SEATTLE USA 47 26 56 N 122 18 33 W 131 47.449 -122.309
SFO KSFO SAN FRANCISCO INTERNATIONAL SAN FRANCISCO USA 37 37 8 N 122 22 29 W 4 37.619 -122.375
SFZ KSFZ NORTH CENTRAL STATE SMITHFIELD USA 41 55 14 N 71 29 28 W 135 41.921 -71.491
SHV KSHV SHREVEPORT RGNL SHREVEPORT USA 32 26 47 N 93 49 32 W 79 32.446 -93.826
SJC KSJC NORMAN Y MINETA SAN JOSE INTERNATIONAL SAN JOSE USA 37 21 42 N 121 55 44 W 18 37.362 -121.929
SJT KSJT SAN ANGELO RGNL MATHIS FLD SAN ANGELO USA 31 21 27 N 100 29 46 W 585 31.358 -100.496
SKF KSKF LACKLAND AFB KELLY FLD ANNEX SAN ANTONIO USA 29 23 3 N 98 34 51 W 211 29.384 -98.581
SLC KSLC SALT LAKE CITY INTERNATIONAL SALT LAKE CITY USA 40 47 18 N 111 58 39 W 1289 40.788 -111.978
SMF KSMF SACRAMENTO INTERNATIONAL SACRAMENTO USA 38 41 43 N 121 35 26 W 9 38.695 -121.591
SNA KSNA JOHN WAYNE ARPT ORANGE CO SANTA ANA USA 33 40 32 N 117 52 5 W 18 33.676 -117.868
SPB KSPB SCAPPOOSE INDUSTRIAL AIRPARK SAN LUIS USA 45 46 21 N 122 51 44 W 18 45.773 -122.862
SPS KSPS SHEPPARD AFB WICHITA FALLS MUNI WICHITA FALLS USA 33 59 19 N 98 29 30 W 311 33.989 -98.492
SSC KSSC SHAW AFB SUMTER USA 33 58 22 N 80 28 22 W 74 33.973 -80.473
STL KSTL LAMBERT ST LOUIS INTERNATIONAL ST. LOUIS USA 38 44 51 N 90 21 35 W 185 38.748 -90.36
SUU KSUU TRAVIS AFB FAIRFIELD USA 38 15 45 N 121 55 38 W 19 38.263 -121.927
SUX KSUX SIOUX GATEWAY COL BUD DAY FLD SIOUX CITY USA 42 24 9 N 96 23 3 W 335 42.402 -96.384
SVN KSVN HUNTER AAF HUNTER AAF USA 32 0 36 N 81 8 44 W 13 32.01 -81.146
SWF KSWF STEWART INTERNATIONAL NEWBURGH USA 41 30 14 N 74 6 17 W 150 41.504 -74.105
SYR KSYR SYRACUSE HANCOCK INTERNATIONAL SYRACUSE USA 43 6 40 N 76 6 22 W 129 43.111 -76.106
SZL KSZL WHITEMAN AFB KNOBNOSTER USA 38 43 49 N 93 32 52 W 266 38.73 -93.548
TBN KTBN WAYNESVILLE RGNL ARPT AT FORNEY FLD FORT LEONARDWOOD USA 37 44 29 N 92 8 26 W 354 37.741 -92.141
TEB KTEB TETERBORO TETERBORO USA 40 50 59 N 74 3 39 W 3 40.85 -74.061
TIK KTIK TINKER AFB OKLAHOMA CITY USA 35 24 53 N 97 23 11 W 394 35.415 -97.386
TLH KTLH TALLAHASSEE RGNL TALLAHASSEE USA 30 23 47 N 84 21 1 W 25 30.396 -84.35
TMB KTMB KENDALL TAMIAMI EXECUTIVE KENDALL-TAMIAMI USA 25 38 52 N 80 25 58 W 3 25.648 -80.433
TNT KTNT DADE COLLIER TRAINING AND TRANSITION MIAMI USA 25 51 42 N 80 53 49 W 4 25.862 -80.897
TPA KTPA TAMPA INTERNATIONAL TAMPA USA 27 58 31 N 82 31 59 W 8 27.975 -82.533
TTN KTTN TRENTON MERCER TRENTON USA 40 16 36 N 74 48 48 W 65 40.277 -74.813
TUL KTUL TULSA INTERNATIONAL TULSA USA 36 11 54 N 95 53 17 W 207 36.198 -95.888
TUS KTUS TUCSON INTERNATIONAL TUCSON USA 32 6 58 N 110 56 29 W 806 32.116 -110.941
TXK KTXK TEXARKANA RGNL WEBB FLD TEXARKANA USA 33 27 13 N 93 59 27 W 119 33.454 -93.991
TYR KTYR TYLER POUNDS RGNL TYLER USA 32 21 14 N 95 24 8 W 166 32.354 -95.402
TYS KTYS MC GHEE TYSON KNOXVILLE USA 35 48 44 N 83 59 34 W 300 35.812 -83.993
VAD KVAD MOODY AFB VALDOSTA USA 30 58 4 N 83 11 34 W 72 30.968 -83.193
VCV KVCV SOUTHERN CALIFORNIA LOGISTICS VICTORVILLE USA 34 35 35 N 117 22 46 W 880 34.593 -117.379
VPS KVPS EGLIN AFB VALPARAISO USA 30 28 59 N 86 31 31 W 27 30.483 -86.525
VRB KVRB VERO BEACH MUNI VERO BEACH USA 27 39 20 N 80 25 4 W 8 27.656 -80.418
WRB KWRB ROBINS AFB MACON USA 32 38 24 N 83 35 30 W 90 32.64 -83.592
WRI KWRI MC GUIRE AFB WRIGHTSTOWN USA 40 0 56 N 74 35 37 W 41 40.016 -74.594
WWD KWWD CAPE MAY CO WILDWOOD USA 39 0 30 N 74 54 29 W 8 39.008 -74.908
YIP KYIP WILLOW RUN DETROIT USA 42 14 16 N 83 31 49 W 219 42.238 -83.53
YNG KYNG YOUNGSTOWN WARREN RGNL YOUNGSTOWN USA 41 15 38 N 80 40 44 W 365 41.261 -80.679
YUM KYUM YUMA MCAS YUMA INTERNATIONAL YUMA USA 32 39 23 N 114 36 21 W 65 32.656 -114.606
PCA MMPC INGENIERO JUAN GUILLERMO VILLASANA PACHUCA MEXICO 20 4 38 N 98 46 56 W 2317 20.077 -98.782
PPG NSTU PAGO PAGO INTERNATIONAL PAGO PAGO SAMOA 14 19 51 S 170 42 37 W 10 -14.331 -170.71
PAQ PAAQ PALMER MUNI PALMER USA 61 35 41 N 149 5 19 W 76 61.595 -149.089
BTI PABA BARTER ISLAND LRRS BARTER ISLAND USA 70 8 2 N 143 34 37 W 2 70.134 -143.577
BET PABE BETHEL BETHEL USA 60 46 47 N 161 50 16 W 38 60.78 -161.838
BRW PABR WILEY POST WILL ROGERS MEM BARROW USA 71 17 7 N 156 45 57 W 14 71.285 -156.766
BTT PABT BETTLES BETTLES USA 66 54 55 N 151 31 41 W 196 66.915 -151.528
CDB PACD COLD BAY COLD BAY USA 55 12 20 N 162 43 27 W 30 55.206 -162.724
CDV PACV MERLE K MUDHOLE SMITH CORDOVA USA 60 29 30 N 145 28 39 W 13 60.492 -145.477
ADK PADK ADAK ADAK ISLAND USA 51 52 40 N 176 38 45 W 7 51.878 -176.646
DLG PADL DILLINGHAM DILLINGHAM USA 59 2 43 N 158 30 12 W 27 59.045 -158.503
ADQ PADQ KODIAK KODIAK USA 57 45 0 N 152 29 37 W 23 57.75 -152.494
DUT PADU UNALASKA UNALASKA USA 53 54 0 N 166 32 36 W 7 53.9 -166.543
EDF PAED ELMENDORF AFB ANCHORAGE USA 61 15 4 N 149 48 23 W 65 61.251 -149.806
EHM PAEH CAPE NEWENHAM LRRS CAPE NEWENHAM USA 58 38 50 N 162 3 38 W 165 58.647 -162.061
EIL PAEI EIELSON AFB FAIRBANKS USA 64 39 56 N 147 6 5 W 168 64.666 -147.101
ENA PAEN KENAI MUNI KENAI USA 60 34 23 N 151 14 42 W 31 60.573 -151.245
FAI PAFA FAIRBANKS INTERNATIONAL FAIRBANKS USA 64 48 54 N 147 51 22 W 133 64.815 -147.856
FBK PAFB WAINWRIGHT AAF FORT WAINWRIGHT USA 64 50 15 N 147 36 52 W 139 64.837 -147.614
GAL PAGA EDWARD G PITKA SR GALENA USA 64 44 10 N 156 56 14 W 47 64.736 -156.937
GKN PAGK GULKANA GULKANA USA 62 9 17 N 145 27 23 W 482 62.155 -145.456
SGY PAGY SKAGWAY SKAGWAY USA 59 27 36 N 135 18 56 W 14 59.46 -135.316
HOM PAHO HOMER HOMER USA 59 38 44 N 151 28 35 W 26 59.646 -151.476
ILI PAIL ILIAMNA ILIAMNA USA 59 45 13 N 154 54 39 W 57 59.754 -154.911
UTO PAIM INDIAN MOUNTAIN LRRS INDIAN MOUNTAINS USA 65 59 34 N 153 42 15 W 372 65.993 -153.704
JNU PAJN JUNEAU INTERNATIONAL JUNEAU USA 58 21 17 N 134 34 34 W 6 58.355 -134.576
AKN PAKN KING SALMON KING SALMON USA 58 40 36 N 156 38 57 W 18 58.677 -156.649
KTN PAKT KETCHIKAN INTERNATIONAL KETCHIKAN USA 55 21 20 N 131 42 49 W 30 55.356 -131.714
LUR PALU CAPE LISBURNE LRRS CAPE LISBURNE USA 68 52 30 N 166 6 36 W 4 68.875 -166.11
MCG PAMC MC GRATH MCGRATH USA 62 57 10 N 155 36 20 W 103 62.953 -155.606
MRI PAMR MERRILL FLD ANCHORAGE USA 61 12 51 N 149 50 46 W 42 61.214 -149.846
ANC PANC TED STEVENS ANCHORAGE INTERNATIONAL ANCHORAGE USA 61 10 27 N 149 59 46 W 47 61.174 -149.996
OME PAOM NOME NOME USA 64 30 43 N 165 26 42 W 12 64.512 -165.445
ORT PAOR NORTHWAY NORTHWAY USA 62 57 40 N 141 55 44 W 524 62.961 -141.929
OTZ PAOT RALPH WIEN MEM KOTZEBUE USA 66 53 4 N 162 35 54 W 4 66.884 -162.598
PML PAPM PLATINUM PORT MOLLER USA 59 0 40 N 161 49 10 W 5 59.011 -161.819
SCC PASC DEADHORSE DEADHORSE USA 70 11 41 N 148 27 54 W 19 70.195 -148.465
SIT PASI SITKA ROCKY GUTIERREZ SITKA USA 57 2 49 N 135 21 41 W 8 57.047 -135.361
SNP PASN ST PAUL ISLAND ST. PAUL ISLAND USA 57 10 2 N 170 13 13 W 20 57.167 -170.22
SVW PASV SPARREVOHN LRRS SPARREVOHN USA 61 5 50 N 155 34 27 W 484 61.097 -155.574
SYA PASY EARECKSON AS SHEMYA USA 52 42 44 N 174 6 49 E 30 52.712 174.114
TAL PATA RALPH M CALHOUN TANANA USA 65 10 27 N 152 6 33 W 70 65.174 -152.109
TNC PATC TIN CITY LRRS TIN CITY USA 65 33 47 N 167 55 20 W 83 65.563 -167.922
TKA PATK TALKEETNA TALKEETNA USA 62 19 13 N 150 5 37 W 110 62.32 -150.094
TLJ PATL TATALINA LRRS TATALINA USA 62 53 39 N 155 58 35 W 294 62.894 -155.976
UNK PAUN UNALAKLEET UNALAKLEET USA 63 53 18 N 160 47 56 W 7 63.888 -160.799
VDZ PAVD VALDEZ PIONEER FIELD VALDEZ USA 61 8 2 N 146 14 54 W 37 61.134 -146.248
AIN PAWT WAINWRIGHT AS FORT WAINWRIGHT USA 70 36 48 N 159 51 37 W 11 70.613 -159.86
YAK PAYA YAKUTAT YAKUTAT USA 59 30 11 N 139 39 36 W 12 59.503 -139.66
FYU PFYU FORT YUKON FORT YUKON USA 66 34 17 N 145 15 1 W 132 66.571 -145.25
ROP PGRO ROTA INTERNATIONAL ROTA MARIANA ISLANDS 14 10 28 N 145 14 36 E 186 14.174 145.243
SPN PGSN SAIPAN INTERNATIONAL SAIPAN MARIANA ISLANDS 15 7 10 N 145 43 45 E 66 15.119 145.729
UAM PGUA ANDERSEN AFB ANDERSEN MARIANA ISLANDS 13 35 2 N 144 55 48 E 192 13.584 144.93
GUM PGUM GUAM INTERNATIONAL AGANA MARIANA ISLANDS 13 29 2 N 144 47 49 E 91 13.484 144.797
HNM PHHN HANA HANA USA 20 47 44 N 156 0 51 W 24 20.796 -156.014
JHM PHJH KAPALUA LAHANIA-KAPALUA USA 20 57 46 N 156 40 27 W 79 20.963 -156.674
KOA PHKO KONA INTERNATIONAL AT KEAHOLE KONA USA 19 44 19 N 156 2 44 W 15 19.739 -156.046
LIH PHLI LIHUE LIHUE USA 21 58 34 N 159 20 19 W 47 21.976 -159.339
MKK PHMK MOLOKAI MOLOKAI USA 21 9 10 N 157 5 46 W 139 21.153 -157.096
MUE PHMU WAIMEA KOHALA KAMUELA USA 20 0 4 N 155 40 5 W 815 20.001 -155.668
NGF PHNG KANEOHE BAY MCAF KANEOHE BAY USA 21 26 57 N 157 46 4 W 6 21.449 -157.768
HNL PHNL HONOLULU INTERNATIONAL HONOLULU USA 21 18 57 N 157 55 36 W 4 21.316 -157.927
LNY PHNY LANAI LANAI USA 20 47 8 N 156 57 5 W 399 20.786 -156.951
OGG PHOG KAHULUI KAHULUI USA 20 53 55 N 156 25 50 W 17 20.899 -156.431
ITO PHTO HILO INTERNATIONAL HILO USA 19 43 13 N 155 2 55 W 12 19.72 -155.049
PIZ PPIZ POINT LAY LRRS POINT LAY USA 69 43 58 N 163 0 19 W 8 69.733 -163.005
STT TIST CYRIL E KING ST. THOMAS VIRGIN ISL. 18 20 14 N 64 58 24 W 8 18.337 -64.973
STX TISX HENRY E ROHLSEN ST. CRIOX ISLAND VIRGIN ISL. 17 42 6 N 64 47 54 W 20 17.702 -64.798
BQN TJBQ RAFAEL HERNANDEZ AGUADILLA PUERTO RICO 18 29 41 N 67 7 46 W 73 18.495 -67.129
SIG TJIG FERNANDO LUIS RIBAS DOMINICCI SAN JUAN PUERTO RICO 18 27 24 N 66 5 53 W 4 18.457 -66.098
MAZ TJMZ EUGENIO MARIA DE HOSTOS MAYAGUEZ PUERTO RICO 18 15 20 N 67 8 54 W 9 18.256 -67.148
PSE TJPS MERCEDITA PONCE PUERTO RICO 18 0 29 N 66 33 46 W 8 18.008 -66.563
SJU TJSJ LUIS MUNOZ MARIN INTERNATIONAL SAN JUAN PUERTO RICO 18 26 21 N 66 0 6 W 3 18.439 -66.002
# Annotate graph with latitude and longitude
no_gps = []
for n, d in pass_2015_network.nodes(data=True):
    try:
        pass_2015_network.nodes[n]["longitude"] = us_airports.loc[n, "LONGITUDE"] 
        pass_2015_network.nodes[n]["latitude"] = us_airports.loc[n, "LATITUDE"]
        pass_2015_network.nodes[n]["degree"] = pass_2015_network.degree(n)

    # Some of the nodes are not represented 
    except KeyError:
        no_gps.append(n)

# Get subgraph of nodes that do have GPS coords
has_gps = set(pass_2015_network.nodes()).difference(no_gps)
g = pass_2015_network.subgraph(has_gps)

Let's first plot only the nodes, i.e airports. Places like Guam, US Virgin Islands are also included in this dataset as they are treated as domestic airports in this dataset.

import nxviz as nv
from nxviz import nodes, plots, edges
plt.figure(figsize=(20, 9))
pos = nodes.geo(g, aesthetics_kwargs={"size_scale": 1})
plots.aspect_equal()
plots.despine()
/home/runner/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/nxviz/__init__.py:18: UserWarning: 
nxviz has a new API! Version 0.7.0 onwards, the old class-based API is being
deprecated in favour of a new API focused on advancing a grammar of network
graphics. If your plotting code depends on the old API, please consider
pinning nxviz at version 0.6.3, as the new API will break your old code.

To check out the new API, please head over to the docs at
https://ericmjl.github.io/nxviz/ to learn more. We hope you enjoy using it!

(This deprecation message will go away in version 1.0.)

  warnings.warn(

Let's also plot the routes(edges).

import nxviz as nv
from nxviz import nodes, plots, edges, annotate
plt.figure(figsize=(20, 9))
pos = nodes.geo(g, color_by="degree", aesthetics_kwargs={"size_scale": 1})
edges.line(g, pos, aesthetics_kwargs={"alpha_scale": 0.1})
annotate.node_colormapping(g, color_by="degree")
plots.aspect_equal()
plots.despine()

Before we proceed further, let's take a detour to briefly discuss directed networks and PageRank.

Directed Graphs and PageRank

The figure below explains the basic idea behind the PageRank algorithm. The "importance" of the node depends on the incoming links to the node, i.e if an "important" node A points towards a node B it will increase the PageRank score of node B, and this is run iteratively. In the given figure, even though node C is only connected to one node it is considered "important" as the connection is to node B, which is an "important" node.

Source: Wikipedia

To better understand this let's work through an example.

# Create an empty directed graph object
G = nx.DiGraph()
# Add an edge from 1 to 2 with weight 4
G.add_edge(1, 2, weight=4)
print(G.edges(data=True))
[(1, 2, {'weight': 4})]

# Access edge from 1 to 2
G[1][2]
{'weight': 4}

What happens when we try to access the edge from 2 to 1?

G[2][1]

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-137-d6b8db3142ef> in <module>
      1 # Access edge from 2 to 1
----> 2 G[2][1]

~/miniconda3/envs/nams/lib/python3.7/site-packages/networkx/classes/coreviews.py in __getitem__(self, key)
     52 
     53     def __getitem__(self, key):
---> 54         return self._atlas[key]
     55 
     56     def copy(self):

KeyError: 1

As expected we get an error when we try to access the edge between 2 to 1 as this is a directed graph.

G.add_edges_from([(1, 2), (3, 2),
                  (4, 2), (5, 2),
                  (6, 2), (7, 2)])
# nx.draw_spring(G, with_labels=True)
nv.circos(G, node_aes_kwargs={"size_scale": 0.3})
<AxesSubplot:>

Just by looking at the example above, we can conclude that node 2 should have the highest PageRank score as all the nodes are pointing towards it.

This is confirmed by calculating the PageRank of this graph.

nx.pagerank(G)
{1: 0.0826448180198328,
 2: 0.5041310918810031,
 3: 0.0826448180198328,
 4: 0.0826448180198328,
 5: 0.0826448180198328,
 6: 0.0826448180198328,
 7: 0.0826448180198328}

What happens when we add an edge from node 5 to node 6.

G.add_edge(5, 6)
nv.circos(G, node_aes_kwargs={"size_scale": 0.3})
# nx.draw_spring(G, with_labels=True)
<AxesSubplot:>
nx.pagerank(G)
{1: 0.08024854052495894,
 2: 0.4844028780560986,
 3: 0.08024854052495894,
 4: 0.08024854052495894,
 5: 0.08024854052495894,
 6: 0.11435441931910648,
 7: 0.08024854052495894}

As expected there was some change in the scores (an increase for 6) but the overall trend stays the same, with node 2 leading the pack.

G.add_edge(2, 8)
nv.circos(G, node_aes_kwargs={"size_scale": 0.3})
<AxesSubplot:>

Now we have an added an edge from 2 to a new node 8. As node 2 already has a high PageRank score, this should be passed on node 8. Let's see how much difference this can make.

nx.pagerank(G)
{1: 0.05378612718073915,
 2: 0.3246687852772877,
 3: 0.05378612718073915,
 4: 0.05378612718073915,
 5: 0.05378612718073915,
 6: 0.0766454192258098,
 7: 0.05378612718073915,
 8: 0.3297551595932067}

In this example, node 8 is now even more "important" than node 2 even though node 8 has only incoming connection.

Let's move back to Airports and use this knowledge to analyse the network.

Importants Hubs in the Airport Network

So let's have a look at the important nodes in this network, i.e. important airports in this network. We'll use centrality measures like pagerank, betweenness centrality and degree centrality which we gone through in this book.

Let's try to calculate the PageRank of passenger_graph.

nx.pagerank(passenger_graph)

---------------------------------------------------------------------------
NetworkXNotImplemented                    Traceback (most recent call last)
<ipython-input-144-15a6f513bf9b> in <module>
      1 # Let's try to calulate the PageRank measures of this graph.
----> 2 nx.pagerank(passenger_graph)

<decorator-gen-435> in pagerank(G, alpha, personalization, max_iter, tol, nstart, weight, dangling)

~/miniconda3/envs/nams/lib/python3.7/site-packages/networkx/utils/decorators.py in _not_implemented_for(not_implement_for_func, *args, **kwargs)
     78         if match:
     79             msg = 'not implemented for %s type' % ' '.join(graph_types)
---> 80             raise nx.NetworkXNotImplemented(msg)
     81         else:
     82             return not_implement_for_func(*args, **kwargs)

NetworkXNotImplemented: not implemented for multigraph type

As PageRank isn't defined for a MultiGraph in NetworkX we need to use our extracted yearly sub networks.

# As pagerank will take weighted measure
# by default we pass in None to make this
# calculation for unweighted network
PR_2015_scores = nx.pagerank(
    pass_2015_network, weight=None)
# Let's check the PageRank score for JFK
PR_2015_scores['JFK']
0.0036376572979606586
# top 10 airports according to unweighted PageRank
top_10_pr = sorted(PR_2015_scores.items(),
                   key=lambda x:x[1],
                   reverse=True)[:10]
# top 10 airports according to unweighted betweenness centrality
top_10_bc = sorted(
    nx.betweenness_centrality(pass_2015_network,
    weight=None).items(), key=lambda x:x[1],
    reverse=True)[0:10]
# top 10 airports according to degree centrality
top_10_dc = sorted(
    nx.degree_centrality(pass_2015_network).items(),
    key=lambda x:x[1], reverse=True)[0:10]

Before looking at the results do think about what we just calculated and try to guess which airports should come out at the top and be ready to be surprised :D

# PageRank
top_10_pr
[('ANC', 0.010425531156396332),
 ('HPN', 0.008715287139161587),
 ('FAI', 0.007865131822111036),
 ('DFW', 0.007168038232113773),
 ('DEN', 0.006557279519803018),
 ('ATL', 0.006367579588749718),
 ('ORD', 0.006178836107660135),
 ('YIP', 0.005821525504523931),
 ('ADQ', 0.005482597083474197),
 ('MSP', 0.005481962582230961)]
# Betweenness Centrality
top_10_bc
[('ANC', 0.28907458480586606),
 ('FAI', 0.08042857784594384),
 ('SEA', 0.06745549919241699),
 ('HPN', 0.06046810178534726),
 ('ORD', 0.045544143864829294),
 ('ADQ', 0.040170160000905696),
 ('DEN', 0.038543251364241436),
 ('BFI', 0.03811277548952854),
 ('MSP', 0.03774809342340624),
 ('TEB', 0.036229439542316354)]
# Degree Centrality
top_10_dc
[('ATL', 0.3643595863166269),
 ('ORD', 0.354813046937152),
 ('DFW', 0.3420843277645187),
 ('MSP', 0.3261734287987271),
 ('DEN', 0.31821797931583135),
 ('ANC', 0.3046937151949085),
 ('MEM', 0.29196499602227527),
 ('LAX', 0.2840095465393795),
 ('IAH', 0.28082736674622116),
 ('DTW', 0.27446300715990457)]

The Degree Centrality results do make sense at first glance, ATL is Atlanta, ORD is Chicago, these are defintely airports one would expect to be at the top of a list which calculates "importance" of an airport. But when we look at PageRank and Betweenness Centrality we have an unexpected airport 'ANC'. Do think about measures like PageRank and Betweenness Centrality and what they calculate. Do note that currently we have used the core structure of the network, no other metadata like number of passengers. These are calculations on the unweighted network.

'ANC' is the airport code of Anchorage airport, a place in Alaska, and according to pagerank and betweenness centrality it is the most important airport in this network. Isn't that weird? Thoughts?

Looks like 'ANC' is essential to the core structure of the network, as it is the main airport connecting Alaska with other parts of US. This explains the high Betweenness Centrality score and there are flights from other major airports to 'ANC' which explains the high PageRank score.

Related blog post: https://toreopsahl.com/2011/08/12/why-anchorage-is-not-that-important-binary-ties-and-sample-selection/

Let's look at weighted version, i.e taking into account the number of people flying to these places.

# Recall from the last chapter we use weight_inv
# while calculating betweenness centrality
sorted(nx.betweenness_centrality(
    pass_2015_network, weight='weight_inv').items(),
    key=lambda x:x[1], reverse=True)[0:10]
[('SEA', 0.4192179843829966),
 ('ATL', 0.3589665389741017),
 ('ANC', 0.32425767084369994),
 ('LAX', 0.2668567170342895),
 ('ORD', 0.10008664852621497),
 ('DEN', 0.0964658422388763),
 ('MSP', 0.09300021788810685),
 ('DFW', 0.0926644126226465),
 ('FAI', 0.08824779747216016),
 ('BOS', 0.08259764427486331)]
sorted(nx.pagerank(
    pass_2015_network, weight='weight').items(),
    key=lambda x:x[1], reverse=True)[0:10]
[('ATL', 0.037535963029303135),
 ('ORD', 0.028329766122739346),
 ('SEA', 0.028274564067008245),
 ('ANC', 0.027127866647567035),
 ('DFW', 0.02570050418889442),
 ('DEN', 0.025260024346433315),
 ('LAX', 0.02394043498608451),
 ('PHX', 0.018373176636420224),
 ('CLT', 0.01780703930063076),
 ('LAS', 0.017649683141049966)]

When we adjust for number of passengers we see that we have a reshuffle in the "importance" rankings, and they do make a bit more sense now. According to weighted PageRank, Atlanta, Chicago, Seattle the top 3 airports while Anchorage is at 4th rank now.

To get an even better picture of this we should do the analyse with more metadata about the routes not just the number of passengers.

How reachable is this network?

Let's assume you are the Head of Data Science of an airline and your job is to make your airline network as "connected" as possible.

To translate this problem statement to network science, we calculate the average shortest path length of this network, it gives us an idea about the number of jumps we need to make around the network to go from one airport to any other airport in this network on average.

We can use the inbuilt networkx method average_shortest_path_length to find the average shortest path length of a network.

nx.average_shortest_path_length(pass_2015_network)

---------------------------------------------------------------------------
NetworkXError                             Traceback (most recent call last)
<ipython-input-157-acfe9bf3572a> in <module>
----> 1 nx.average_shortest_path_length(pass_2015_network)

~/miniconda3/envs/nams/lib/python3.7/site-packages/networkx/algorithms/shortest_paths/generic.py in average_shortest_path_length(G, weight, method)
    401     # Shortest path length is undefined if the graph is disconnected.
    402     if G.is_directed() and not nx.is_weakly_connected(G):
--> 403         raise nx.NetworkXError("Graph is not weakly connected.")
    404     if not G.is_directed() and not nx.is_connected(G):
    405         raise nx.NetworkXError("Graph is not connected.")

NetworkXError: Graph is not weakly connected.

Wait, What? This network is not "connected" (ignore the term weakly for the moment). That seems weird. It means that there are nodes which aren't reachable from other set of nodes, which isn't good news in especially a transporation network.

Let's have a look at these far flung airports which aren't reachable.

components = list(
    nx.weakly_connected_components(
        pass_2015_network))
# There are 3 weakly connected components in the network.
for c in components:
    print(len(c))
1255
2
1

# Let's look at the component with 2 and 1 airports respectively.
print(components[1])
print(components[2])
{'SPB', 'SSB'}
{'AIK'}

The airports 'SSB' and 'SPB' are codes for Seaplanes airports and they have flights to each other so it makes sense that they aren't connected to the larger network of airports.

The airport is even more weird as it is in a component in itself, i.e there is a flight from AIK to AIK. After investigating further it just seems like an anomaly in this dataset.

AIK_DEST_2015 = pass_air_data[
    (pass_air_data['YEAR'] == 2015) &
    (pass_air_data['DEST'] == 'AIK')]
AIK_DEST_2015.head()


id
YEAR

 
ORIGIN

 
DEST

 
UNIQUE_CARRIER_NAME

 
PASSENGERS

 
433338 2015 AIK AIK {'Wright Air Service'} 0
# Let's get rid of them, we don't like them
pass_2015_network.remove_nodes_from(
    ['SPB', 'SSB', 'AIK'])
# Our network is now weakly connected
nx.is_weakly_connected(pass_2015_network)
True
# It's not strongly connected
nx.is_strongly_connected(pass_2015_network)
False

Strongly vs weakly connected graphs.

Let's go through an example to understand weakly and strongly connected directed graphs.

# NOTE: The notion of strongly and weakly exists only for directed graphs.
G = nx.DiGraph()

# Let's create a cycle directed graph, 1 -> 2 -> 3 -> 1
G.add_edge(1, 2)
G.add_edge(2, 3)
G.add_edge(3, 1)
nx.draw(G, with_labels=True)

In the above example we can reach any node irrespective of where we start traversing the network, if we start from 2 we can reach 1 via 3. In this network every node is "reachable" from one another, i.e the network is strongly connected.

nx.is_strongly_connected(G)
True
# Let's add a new connection
G.add_edge(3, 4)
nx.draw(G, with_labels=True)

It's evident from the example above that we can't traverse the network graph. If we start from node 4 we are stuck at the node, we don't have any way of leaving node 4. This is assuming we strictly follow the direction of edges. In this case the network isn't strongly connected but if we look at the structure and assume the directions of edges don't matter than we can go to any other node in the network even if we start from node 4.

In the case an undirected copy of directed network is connected we call the directed network as weakly connected.

nx.is_strongly_connected(G)
False
nx.is_weakly_connected(G)
True

Let's go back to our airport network of 2015.

After removing those 3 airports the network is weakly connected.

nx.is_weakly_connected(pass_2015_network)
True
nx.is_strongly_connected(pass_2015_network)
False

But our network is still not strongly connected, which essentially means there are airports in the network where you can fly into but not fly back, which doesn't really seem okay

strongly_connected_components = list(
    nx.strongly_connected_components(pass_2015_network))
# Let's look at one of the examples of a strong connected component
strongly_connected_components[0]
{'BCE'}
BCE_DEST_2015 = pass_air_data[
    (pass_air_data['YEAR'] == 2015) & 
    (pass_air_data['DEST'] == 'BCE')]
BCE_DEST_2015.head()


id
YEAR

 
ORIGIN

 
DEST

 
UNIQUE_CARRIER_NAME

 
PASSENGERS

 
451074 2015 PGA BCE {'Grand Canyon Airlines, Inc. d/b/a Grand Canyo... 8
BCE_ORI_2015 = pass_air_data[
    (pass_air_data['YEAR'] == 2015) & 
    (pass_air_data['ORIGIN'] == 'BCE')]
BCE_ORI_2015.head()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/mknotebooks/pandas_output_formatter.py in to_md(df, max_colwidth)
     24         # Truncate entries wider than max_colwidth
     25         return (
---> 26             df.astype(str)
     27             .apply(
     28                 lambda x: [

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/frame.py in apply(self, func, axis, raw, result_type, args, **kwds)
   7766             kwds=kwds,
   7767         )
-> 7768         return op.get_result()
   7769 
   7770     def applymap(self, func, na_action: Optional[str] = None) -> DataFrame:

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/apply.py in get_result(self)
    177         # one axis empty
    178         elif not all(self.obj.shape):
--> 179             return self.apply_empty_result()
    180 
    181         # raw

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/apply.py in apply_empty_result(self)
    216                 r = np.nan
    217 
--> 218             return self.obj._constructor_sliced(r, index=self.agg_axis)
    219         else:
    220             return self.obj.copy()

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/series.py in __init__(self, data, index, dtype, name, copy, fastpath)
    348                 try:
    349                     if len(index) != len(data):
--> 350                         raise ValueError(
    351                             f"Length of passed values is {len(data)}, "
    352                             f"index implies {len(index)}."

ValueError: Length of passed values is 0, index implies 5.
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/mknotebooks/pandas_output_formatter.py in to_md(df, max_colwidth)
     24         # Truncate entries wider than max_colwidth
     25         return (
---> 26             df.astype(str)
     27             .apply(
     28                 lambda x: [

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/frame.py in apply(self, func, axis, raw, result_type, args, **kwds)
   7766             kwds=kwds,
   7767         )
-> 7768         return op.get_result()
   7769 
   7770     def applymap(self, func, na_action: Optional[str] = None) -> DataFrame:

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/apply.py in get_result(self)
    177         # one axis empty
    178         elif not all(self.obj.shape):
--> 179             return self.apply_empty_result()
    180 
    181         # raw

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/apply.py in apply_empty_result(self)
    216                 r = np.nan
    217 
--> 218             return self.obj._constructor_sliced(r, index=self.agg_axis)
    219         else:
    220             return self.obj.copy()

~/work/Network-Analysis-Made-Simple/Network-Analysis-Made-Simple/nams_env/lib/python3.8/site-packages/pandas/core/series.py in __init__(self, data, index, dtype, name, copy, fastpath)
    348                 try:
    349                     if len(index) != len(data):
--> 350                         raise ValueError(
    351                             f"Length of passed values is {len(data)}, "
    352                             f"index implies {len(index)}."

ValueError: Length of passed values is 0, index implies 5.
Empty DataFrame
Columns: [YEAR, ORIGIN, DEST, UNIQUE_CARRIER_NAME, PASSENGERS]
Index: []

As we can see above you can fly into 'BCE' but can't fly out, weird indeed. These airport are small airports with one off schedules flights. For the purposes of our analyses we can ignore such airports.

# Let's find the biggest strongly connected component
pass_2015_strong_nodes = max(
    strongly_connected_components, key=len)
# Create a subgraph with the nodes in the
# biggest strongly connected component
pass_2015_strong = pass_2015_network.subgraph(
    nodes=pass_2015_strong_nodes)
nx.is_strongly_connected(pass_2015_strong)
True

After removing multiple airports we now have a strongly connected airport network. We can now travel from one airport to any other airport in the network.

# We started with 1258 airports
len(pass_2015_strong)
1190
nx.average_shortest_path_length(pass_2015_strong)
3.174661992635574

The 3.17 number above represents the average length between 2 airports in the network which means that it's possible to go from one airport to another in this network under 3 layovers, which sounds nice. A more reachable network is better, not necessearily in terms of revenue for the airline but for social health of the air transport network.

Exercise

How can we decrease the average shortest path length of this network?

Think of an effective way to add new edges to decrease the average shortest path length. Let's see if we can come up with a nice way to do this.

The rules are simple: - You can't add more than 2% of the current edges( ~500 edges)

from nams.solutions.airport import add_opinated_edges
new_routes_network = add_opinated_edges(pass_2015_strong)
nx.average_shortest_path_length(new_routes_network)
3.0888508809747615

Using an opinionated heuristic we were able to reduce the average shortest path length of the network. Check the solution below to understand the idea behind the heuristic, do try to come up with your own heuristics.

Can we find airline specific reachability?

Let's see how we can use the airline metadata to calculate the reachability of a specific airline.

# We have access to the airlines that fly the route in the edge attribute airlines
pass_2015_network['JFK']['SFO']
{'weight': 1179941.0,
 'weight_inv': 8.4750000211875e-07,
 'airlines': "{'Delta Air Lines Inc.', 'Virgin America', 'American Airlines Inc.', 'Sun Country Airlines d/b/a MN Airlines', 'JetBlue Airways', 'Vision Airlines', 'United Air Lines Inc.'}"}
# A helper function to extract the airlines names from the edge attribute
def str_to_list(a):
    return a[1:-1].split(', ')
for origin, dest in pass_2015_network.edges():
    pass_2015_network[origin][dest]['airlines_list'] = str_to_list(
        (pass_2015_network[origin][dest]['airlines']))

Let's extract the network of United Airlines from our airport network.

united_network = nx.DiGraph()
for origin, dest in pass_2015_network.edges():
    if "'United Air Lines Inc.'" in pass_2015_network[origin][dest]['airlines_list']:
            united_network.add_edge(
                origin, dest, 
                weight=pass_2015_network[origin][dest]['weight'])
# number of nodes -> airports
# number of edges -> routes
print(nx.info(united_network))
Name: 
Type: DiGraph
Number of nodes: 194
Number of edges: 1894
Average in degree:   9.7629
Average out degree:   9.7629

# Let's find United Hubs according to PageRank
sorted(nx.pagerank(
    united_network, weight='weight').items(),
       key=lambda x:x[1], reverse=True)[0:5]
[('ORD', 0.08385772266571424),
 ('DEN', 0.06816244850418422),
 ('LAX', 0.053065234147240105),
 ('IAH', 0.044410609028379185),
 ('SFO', 0.04326197030283029)]
# Let's find United Hubs according to Degree Centrality
sorted(nx.degree_centrality(
    united_network).items(),
       key=lambda x:x[1], reverse=True)[0:5]
[('ORD', 1.0),
 ('IAH', 0.9274611398963731),
 ('DEN', 0.8756476683937824),
 ('EWR', 0.8134715025906736),
 ('SFO', 0.6839378238341969)]

Solutions

Here are the solutions to the exercises above.

from nams.solutions import airport
import inspect

print(inspect.getsource(airport))
import networkx as nx
import pandas as pd


def busiest_route(pass_air_data, year):
    return pass_air_data[
        pass_air_data.groupby(["YEAR"])["PASSENGERS"].transform(max)
        == pass_air_data["PASSENGERS"]
    ].query(f"YEAR == {year}")


def plot_time_series(pass_air_data, origin, dest):
    pass_air_data.query(f"ORIGIN == '{origin}' and DEST == '{dest}'").plot(
        "YEAR", "PASSENGERS"
    )


def add_opinated_edges(G):
    G = nx.DiGraph(G)
    sort_degree = sorted(
        nx.degree_centrality(G).items(), key=lambda x: x[1], reverse=True
    )
    top_count = 0
    for n, v in sort_degree:
        count = 0
        for node, val in sort_degree:
            if node != n:
                if node not in G._adj[n]:
                    G.add_edge(n, node)
                    count += 1
                    if count == 25:
                        break
        top_count += 1
        if top_count == 20:
            break
    return G