Airport Destination Mapper in Real Time

 
airport_mapper_example.gif
 

For this entry into the live-plotting series, I will incorporate all of the previous methods of plotting in Python so that we can create a real-time airport destination mapper. Above, you can see the destination mapper animation, which, at the time of making, was returning the most recent departures from New York's JFK airport. The function works by accessing a website called Flight Aware and using its scheduled departures API to web crawl specific airports and return the most recent departures (called scheduled departures, so they may be delayed departures as well as flights in progress). The application of this tool could be for last-minute flight planning, tracking flight progress, and even airline activity reporting. 

  https://www.flickr.com/photos/superjetinternational/5476115362

https://www.flickr.com/photos/superjetinternational/5476115362


  https://commons.wikimedia.org/wiki/File:Macedonia_International_Airport_map.svg

https://commons.wikimedia.org/wiki/File:Macedonia_International_Airport_map.svg

There is an open-source database of airport information that can be found at:

The site hosts multiple files full of information about runways, airport communication frequencies, and general geographic data. I will be using the file named 'airports.csv,' which contains latitude, longitude, elevation, country, and International Air Transport Association (IATA) codes that will help us uniquely identify each airport from its call sign mentioned in the flight destination data discussed in the next section.

A direct download of airport data can be found at the link below:

 http://ourairports.com/data/airports.csv

Make sure to save the 'airports.csv' file to the local directory before proceeding to the next section and beyond.


Accessing The Flight Aware Data

Flight Aware is a website that contains live-tracking information about flights across the world. It has arrival, departure, en-route, and scheduled flight information, among other features regarding aircraft, weather, and general aviation guidance. 

I will be focusing on the scheduled airport departures to create a real-time visualization for outgoing flights using the web format outlined below:

 

https://flightaware.com/live/airport/KJFK/scheduled?;offset=0;order=filed_departuretime;sort=ASC

This format tells Flight Aware a few things:

 
KJFK - Airport identification code (IATA)
scheduled - Type of request (departure, arrival, scheduled)
offset=0 - Steps beyond most recent (in steps of 20)
order=filed_departuretime;sort=ASC - order and sorting of flights
 

Using the coding above, the user can change the airport identification code to their desired airport and the rest can stay the same. In the code in a later section, I will demonstrate how to iterate through the offset to get future departures as well.


The scheduled departures site is a table full of information about airline, aircraft, destinations, and departure and arrival times. We will crawl this table format to acquire information that we can then plot using Python to create a live destination mapper.

The table can be crawled by identifying the start and end points of each column and row of the table using html code. The html points look something like this:

name endpoint identifier = '"ltr">'
airport identifier = 'itemprop="url">'
departure time identifier = '</a>)</span></td><td class="smallrow'+'1'+'" style="text-align: left">'

The full code is referenced below with comments, so I won't spend much time discussed the minutia of the methods. It's by no means at all the most efficient or most well-written code, however, it runs at a reasonable speed. Additionally, many of the methods used in the plotting have been used in previous tutorial, so please reference those for further elaboration.

import requests,time,json,csv
import matplotlib
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np

plt.ion()           
fig,ax0 = plt.subplots(figsize=(8,6))
fig_width = (fig.get_figwidth())*(fig.get_dpi())
ax0.set_position([0.0,0.0,1.0,1.0])

# add axis for space background effect
galaxy_image = plt.imread('galaxy_image.png')
ax0.imshow(galaxy_image) 
ax0.set_axis_off()
ax1 = fig.add_axes([0.1,0.25,0.5,0.5])

# define map coordinates from full-scale globe
m1 = Basemap(projection='ortho', 
          lat_0=0.0, lon_0=0.0,resolution=None)

map_coords_xy = [m1.llcrnrx,m1.llcrnry,m1.urcrnrx,m1.urcrnry]
map_coords_geo = [m1.llcrnrlat,m1.llcrnrlon,m1.urcrnrlat,m1.urcrnrlon]

#zoom proportion and re-plot map 
zoom_prop = 2.0 # use 2.0 for full-scale map

# font size for annotation
annot_font_size = 12
annot_pix_size = 16 # font size to pixels

airport_array,airport_lat,airport_lon,airport_names = [],[],[],[]
with open('airports.csv','r',encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        iata = row['iata_code']
        lat = row['latitude_deg']
        lon = row['longitude_deg']
        name = row['name']
        airport_size = row['type']
        if iata=='' or lat=='' or lon=='':
            continue
        if airport_size=='large_airport' or airport_size=='medium_airport':
            airport_array.append(iata)
            airport_lat.append(lat)
            airport_lon.append(lon)
            airport_names.append(name)
        else:
            continue

name_ident = '"ltr">'
airport_ident = 'itemprop="url">'
depart_time_ident1 = '</a>)</span></td><td class="smallrow'+'1'+'" style="text-align: left">'
depart_time_ident2 = '</a>)</span></td><td class="smallrow'+'2'+'" style="text-align: left">'

depart_airport = 'jfk'

seek_interv = 0
while True:
    
    page = requests.get('https://flightaware.com/live/airport/'+depart_airport+'/scheduled?;offset='+str(seek_interv)+';order=filed_departuretime;sort=ASC')
    page_url = page.url.split('/')
    if page_url[-1]=='scheduled':
        depart_airport = page_url[-2]
        page = requests.get('https://flightaware.com/live/airport/'+depart_airport+'/scheduled?;offset='+str(seek_interv)+';order=filed_departuretime;sort=ASC')

    content = page.text

    key_match_start = '</a></th></tr></thead>'
    key_match_end = '</td></tr></table>'

    flight_indx_start = [i+len(key_match_start) for i, j in enumerate(content) if content[i:i+len(key_match_start)] == key_match_start]
    flight_indx_end = [i+len(key_match_end) for i, j in enumerate(content) if content[i:i+len(key_match_end)] == key_match_end]

    flight_info_full = content[flight_indx_start[0]:flight_indx_end[0]-len(key_match_end)]

    skip = 0
    destination_ident_vector,destination_name_vector,depart_time_vector,airport_match_coords = [],[],[],[]
    airport_lats = []
    airport_lons = []

    for jj in range(skip,len(flight_info_full)):
        if flight_info_full[jj]=='>':
            for kk in range(jj-1,len(flight_info_full)):
                if flight_info_full[kk]=='<':
                    if flight_info_full[jj-len(name_ident)+1:jj+1]==name_ident and flight_info_full[jj+1:kk]!='(':
                        print('flight destination: {}'.format(flight_info_full[jj+1:kk]))
                        destination_name_vector = (flight_info_full[jj+1:kk])
                    if flight_info_full[jj-len(airport_ident)+1:jj+1]==airport_ident:
                        print('airport ident: {}'.format(flight_info_full[jj+1:kk]))
                        destination_ident_vector = (flight_info_full[jj+1:kk])
                        iata_code = flight_info_full[jj+1:kk].upper().split('/')[0].replace(' ','')
                        if len(iata_code)>3:
                            iata_code = iata_code[1:]

                        airport_indx = [i for i, s in enumerate(airport_array) if iata_code in s]
                        if airport_indx!=[]:
                            airport_plot_lat = (float(airport_lat[airport_indx[0]]))
                            airport_plot_lon = float(airport_lon[airport_indx[0]])
                        else:
                            airport_plot_lat = np.nan
                            airport_plot_lon = np.nan
                            
                    if flight_info_full[jj-len(depart_time_ident1)+1:jj+1]==depart_time_ident1 or\
                       flight_info_full[jj-len(depart_time_ident2)+1:jj+1]==depart_time_ident2:
                        depart_time_vector = (flight_info_full[jj+1:kk].split('&nbsp;')[0])

                        if np.isnan(airport_plot_lat):
                            continue

                        ax1.clear()
                        ax1.set_axis_off()
                        
                        m = Basemap(projection='ortho',resolution='l',
                                  lat_0=airport_plot_lat,lon_0=airport_plot_lon,llcrnrx=-map_coords_xy[2]/zoom_prop,
                                    llcrnry=-map_coords_xy[3]/zoom_prop,urcrnrx=map_coords_xy[2]/zoom_prop,
                                    urcrnry=map_coords_xy[3]/zoom_prop)

                        m.bluemarble(scale=0.5)
                        m.drawcoastlines()

                        # scatter for airport destination point
                        x, y = m(airport_plot_lon, airport_plot_lat)
                        ax1.plot(x,y,marker='o',color='w',zorder=10)
                        
                        # annotate the destination airport
                        destination_info = 'Destination: '+destination_name_vector+'\nDeparture Time: '+depart_time_vector
                        annot1 = plt.annotate(destination_info,xy = (0.6,0.5),xycoords='figure fraction',
                                        color='k',fontsize=annot_font_size,bbox=dict(facecolor='w', alpha=0.5))    
                        
                        plt.show()
                        plt.pause(0.01)
                        
                    skip = jj
                    break
        
    seek_interv+=20

airport_mapper_conclusion_blog.png

In this short tutorial, I brought together many of the aspects cover in my live-plotting series using Python. Above, I introduced a method for plotting real-time airport destinations by first downloading a database of airport information. Then, I discussed the website Flight Aware and how to use its live-tracking application to retrieve information about flights from a specific airport. Then, I presented a code that crawls the Flight Aware webpage for scheduled destinations to plot airport information using the IATA code from Flight Aware and the airport information from the airport database to create a visual representation of flight destinations from any airport in the world. This entry into the live-plotting series was meant to combine many of the tools used in previous tutorials, and I hope the application was interesting and helpful to the user. 

 

See More in Programming and Python: