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.
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.
Figure 1. Flight Tracking Python |
Getting Flight Data
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.
Before proceeding to the next step, I suggest to add plt.show() line 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.
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:
The response of the query will look like this:
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 the animation class 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.
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.
Importing Libraries
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.%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
Next, we will prepare the plotting figure, set the axes into flat square projection (plate carrée), 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.#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
Before proceeding to the next step, I suggest to add plt.show() line 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.
Figure 2. OSM Basemap |
Query Parameter to Request Flight Data
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:
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.
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.
- lng 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.
Sending Query
Before sending the query we need to define the request and header with build_opener method and addheaders method from urllib.request library. 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 with close method. The code can be seen as follow.# 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()
The response of the query will look like this:
{'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
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 with Lat and Long key. More keys are available in the JSON response as you can see above, which contains some information about the flight such as Op for aircraft's operator, Spd: the ground speed in knots, Mdl: Aircraft's model, Man: 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.
Update Aircraft Position
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 the animation class from matplotlib.
This is the complete code up to this step.
%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()
If the code is running, you should get a live tracking flight in red dots as in animated picture below.
Live Flight Tracking Python |
Labeling Aircraft
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 use "Op" key. 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.%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()
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.