This tutorial will take you to a journey to create a simple flight tracking with python. Knowing something live out there is always amazing, it just like having sixth sense to know something which is not directly in front of our eyes, like a position of an aircraft in the sky, but we truly believe it is somewhere over there. I was so amazed to see some flight tracking website that show hundreds of aircraft around the globe. I was thinking how they can do it? This question encouraged me to take a quite long journey till I can write this post. Days of effort and frustration have been paid, and I'd like to share the result with you.In this tutorial we will plot aircraft position based on geographic coordinate on Open Street Map (OSM) basemap. The center of the map will be a location like an airport, and we will request all aircraft in a range of some km from the center point. The position will be updated every one second. At the end we will get a simple live flight tracking with python like the figure below.

Getting Flight Data

Importing Libraries

% matplotlib tk import urllib.request import json import matplotlib.pyplot as plt from matplotlib import animation import cartopy.crs as ccrs from cartopy.io.img_tiles import OSM

Setting Up The Plot Tracking Figure

#DEFINE FIGURE fig, ax = plt . subplots() #SET AXES FOR PLOTTING AREA ax = plt . axes(projection = ccrs . PlateCarree()) ax . set_ylim( 40.6051 , 40.6825 ) ax . set_xlim( -73.8288 , -73.7258 ) #ADD OSM BASEMAP osm_tiles = OSM() ax . add_image(osm_tiles, 13 ) #Zoom level 13 #PLOT JFK INTL AIRPORT ax . text( -73.778889 , 40.639722 , 'JFK Intl' ,horizontalalignment = 'right' ,size = 'large' ) ax . plot([ -73.778889 ],[ 40.639722 ], 'bo' ) #Plot a point in blue color

Figure 2. OSM Basemap

Query Parameter to Request Flight Data

http://public-api.adsbexchange.com/VirtualRadar/AircraftList.json?lat=40.639722&lng=-73.778889&fDstL=0&fDstU=20



In the url query above, can be seen some parameters like lat, lng, and fDst.

lat is the decimal latitude to measure distance and calculate bearings.

is the decimal latitude to measure distance and calculate bearings. lng is the decimal longitude to measure distance and calculate bearings.

is the decimal longitude to measure distance and calculate bearings. fDst is the distance in km. It will return a range number. Then L and U is suffix character for Lower and Upper condition There are many query parameters available at Virtual Radar Server . Take a look the website if you are interested for more. In the url query above, can be seen some parameters like, and

Sending Query

# DEFINE REQUEST AND HEADER(BEFORE THE FUNCTION) opener = urllib . request . build_opener() opener . addheaders = [( 'User-agent' , 'Mozilla/5.0' )] #SEND QUERY (IN THE FUNCTION) fp = opener . open( 'http://public-api.adsbexchange.com/VirtualRadar/AircraftList.json?lat=40.639722&lng=-73.778889&fDstL=0&fDstU=20' ) mybyte = fp . read() mystr = mybyte . decode( "utf8" ) js_str = json . loads(mystr) fp . close()

{'flgH': 20, 'totalAc': 7677, 'src': 1, 'showPic': True, 'flgW': 85, 'stm': 1543157476791, 'lastDv': '636786720907884695', 'feeds': [{'id': 1, 'polarPlot': False, 'name': 'From Cons'}], 'shtTrlSec': 65, 'showSil': True, 'srcFeed': 1, 'showFlg': True, 'acList': [{'TSecs': 25, 'Trt': 5, 'Gnd': False, 'SpdTyp': 0, 'Op': 'JetBlue Airways', 'Man': 'Airbus', 'CMsgs': 9, 'Long': -73.817566, 'Type': 'A320', 'Sig': 200, 'Trak': 276.1, 'Reg': 'N588JB', 'InHg': 29.8372135, 'FlightsCount': 0, 'Species': 1, 'Vsi': 2688, 'HasPic': False, 'Mlat': False, 'Interested': False, 'OpIcao': 'JBU', 'TAlt': 4992, 'FSeen': '/Date(1543157451601)/', 'PosTime': 1543157475146, 'Mdl': '2004 AIRBUS A320-232', 'HasSig': True, 'WTC': 2, 'Icao': 'A7946A', 'AltT': 0, 'EngMount': 0, 'Cou': 'United States', 'Sqk': '1174', 'TrkH': False, 'Mil': False, 'GAlt': 1067, 'Alt': 1150, 'Tisb': False, 'Dst': 3.31, 'Engines': '2', 'CallSus': False, 'Year': '2004', 'Bad': False, 'EngType': 3, 'Lat': 40.644928, 'VsiT': 1, 'Id': 10982506, 'CNum': '2201', 'TTrk': 241.875, 'Spd': 170.0, 'Help': False, 'Brng': 280.1, 'Rcvr': 1}]}

Parsing the JSON Response

Update Aircraft Position

% matplotlib tk import urllib.request import json import matplotlib.pyplot as plt from matplotlib import animation import cartopy.crs as ccrs from cartopy.io.img_tiles import OSM #SET AXES fig, ax = plt . subplots() ax = plt . axes(projection = ccrs . PlateCarree()) ax . set_ylim( 40.6051 , 40.6825 ) ax . set_xlim( -73.8288 , -73.7258 ) #ADD OSM BASEMAP osm_tiles = OSM() ax . add_image(osm_tiles, 13 ) #Zoom Level 13 #PLOT JFK INTL AIRPORT ax . text( -73.778889 , 40.639722 , 'JFK Intl' ,horizontalalignment = 'right' ,size = 'large' ) ax . plot([ -73.778889 ],[ 40.639722 ], 'bo' ) #PLOT TRACK track, = ax . plot([], [], 'ro' ) opener = urllib . request . build_opener() opener . addheaders = [( 'User-agent' , 'Mozilla/5.0' )] #UPDATE FUNCTION def update ( self ): #SEND QUERY fp = opener . open( 'http://public-api.adsbexchange.com/VirtualRadar/AircraftList.json?lat=40.639722&lng=-73.778889&fDstL=0&fDstU=20' ) mybyte = fp . read() mystr = mybyte . decode( "utf8" ) js_str = json . loads(mystr) fp . close() lat_list = [] long_list = [] for num,flight_data in enumerate (js_str[ 'acList' ]): lat = flight_data[ 'Lat' ] lon = flight_data[ 'Long' ] lat_list . append(lat) long_list . append(lon) track . set_data(long_list,lat_list) return track, #UPDATING EVERY SECOND anim = animation . FuncAnimation(fig, update,interval =1000 , blit = False ) plt . show()

Live Flight Tracking Python

Labeling Aircraft

% matplotlib tk import urllib.request import json import matplotlib.pyplot as plt from matplotlib import animation import cartopy.crs as ccrs from cartopy.io.img_tiles import OSM #SET AXES fig, ax = plt . subplots() ax = plt . axes(projection = ccrs . PlateCarree()) ax . set_ylim( 40.6051 , 40.6825 ) ax . set_xlim( -73.8288 , -73.7258 ) #ADD OSM BASEMAP osm_tiles = OSM() ax . add_image(osm_tiles, 13 ) #Zoom Level 13 #PLOT JFK INTL AIRPORT ax . text( -73.778889 , 40.639722 , 'JFK Intl' ,horizontalalignment = 'right' ,size = 'large' ) ax . plot([ -73.778889 ],[ 40.639722 ], 'bo' ) #PLOT TRACK track, = ax . plot([], [], 'ro' ) opener = urllib . request . build_opener() opener . addheaders = [( 'User-agent' , 'Mozilla/5.0' )] #UPDATE FUNCTION def update ( self ): #SEND QUERY fp = opener . open( 'http://public-api.adsbexchange.com/VirtualRadar/AircraftList.json?lat=40.639722&lng=-73.778889&fDstL=0&fDstU=20' ) mybyte = fp . read() mystr = mybyte . decode( "utf8" ) js_str = json . loads(mystr) fp . close() lat_list = [] long_list = [] op_list = [] #OPERATOR LIST for num,flight_data in enumerate (js_str[ 'acList' ]): lat = flight_data[ 'Lat' ] lon = flight_data[ 'Long' ] lat_list . append(lat) long_list . append(lon) op_list . append(flight_data[ 'Op' ]) #STORE OPERATOR DATA INTO LIST track . set_data(long_list,lat_list) # LABELING #REMOVE LABEL for num, annot in enumerate (anotation_list): annot . remove() anotation_list[:] = [] #CREATE LABEL CONTAINER for num,annot in enumerate (js_str[ 'acList' ]): annotation = ax . annotate( 'text' ,xy = ( 0 , 0 ),size = 'smaller' ) anotation_list . append(annotation) # UPDATE LABEL POSITION AND OPERATOR for num,ano in enumerate (anotation_list): ano . set_position((long_list[num],lat_list[num])) ano . xy = (long_list[num],lat_list[num]) txt_op = str (op_list[num]) ano . set_text(txt_op) return track,ano, #UPDATING EVERY SECOND anim = animation . FuncAnimation(fig, update,interval =1000 , blit = False ) plt . show()

First of all and the most important thing in this tutorial is to get the information about the flight, where we can get it? After doing some searching and investigations, I found there are many services and mostly in API that offers flight information. Finally I chose ADS-B Exchange . ADS-B Exchange is the world largest co-op of unfiltered flight data. It provides flight data around the world that fed by worldwide community. It's free but they really appreciate a donation especially for commercial application.In creating the flight tracker in python, we will use some libraries like urllib, json, matplotlib and cartopy. Make sure you have all libraries in your system. If not, do installation for the missing library. Then import the required libraries as the code below. Anyway for this tutorial I'm using Jupyter Notebook with Python 3.6.Next, we will prepare the plotting figure, set the axes into flat square projection (), adding OSM basemap and add a center location. For this case, the John F. Kennedy International Airport in New York will be the center point with coordinate 40.639722N,73.778889W. You can change for any location as you wish.Before proceeding to the next step, I suggest to addline at the end of the code above and run it. If you see a map with a blue dot as below, then everything is fine.We've come to heart of this system that is creating a function to request flight data from ADS-B Exchange API service. For that we have to send a query. Then the server will send back a response with available flight data in JSON format. Next we will parse the JSON and plot the data on the map. That's the main idea. Now let's see in more detail.As I mentioned above, we will track all flight in range of some km from a center point. For example 20 km from JFK International Airport. The query will be: Before sending the query we need to define the request and header withmethod andmethod fromlibrary. After sending the query, then read the response, decode and load it as JSON. At the end don't forget to close the opening request withmethod. The code can be seen as follow.The response of the query will look like this:We already get the response and the next step is to parse it to take some required data. Coordinate in latitude and longitude are the most important thing, because we need them to plot aircraft's position on the OSM map. The coordinate can be extracted from the JSON withandkey. More keys are available in the JSON response as you can see above, which contains some information about the flight such asfor aircraft's operator,: the ground speed in knots,: Aircraft's model,: Aircraft's manufacture, etc. The complete description can be found at ADS-B Exchange Datafields To extract the latitude and longitude of each aircraft can be done through a looping in the response JSON list. But firstly an empty latitude and longitude list must be created, which will be used to dump each latitude and longitude. Later the aircraft's position will be plotted on the OSM using the latitude and longitude list.To update the aircraft's position the request will be sent every one second. So in every second we will get new response. Each response will be parsed and the position will be updated. To make it happen can be done with theclass from matplotlib.This is the complete code up to this step.If the code is running, you should get a live tracking flight in red dots as in animated picture below.Just seeing dots without knowing what it is exactly is not so meaningful. Therefore in this section we will give a label to those red dots. For example we want to give aircraft's operator label. To get operator data we can usekey. To do that we need initiate a list that will be used to to store operator data. In each response the operator data will be extracted and store to that list. Because of that, the labeling code will be included in the update function. Here it is the complete code.That's all the tutorial how to create a simple flight tracking with Python. Before ending this tutorial, I want to give a final note. Sometimes when the code is executed, you will get a key error. If this happen, just stay calm, close the map/figure and run it again.In another post I wrote a tutorial how to make a flight tracking application using Pandas and Bokeh . The application is running on local server with a nice visualization and interactivity.