Backend Development 14 min read

Building a Real‑Time Flight Tracking Application with Python and OpenSky Network Data

This tutorial explains how to retrieve live aircraft positions from the OpenSky Network via its REST API, process the data with Python libraries such as requests, pandas and NumPy, convert coordinates, and visualise the results on an interactive Bokeh map that updates every few seconds in a web browser.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Building a Real‑Time Flight Tracking Application with Python and OpenSky Network Data

In the digital age, open aviation data can serve as a "sixth sense" for tracking aircraft; this article demonstrates how to build a custom flight‑tracking application using the OpenSky Network’s public REST API.

The OpenSky Network provides real‑time flight data that can be accessed anonymously (10‑second resolution) or with a registered account (5‑second resolution). Example queries for a rectangular area covering the United States are:

https://opensky-network.org/api/states/all?lamin=30.038&lomin=-125.974&lamax=52.214&lomax=-68.748

Using Python, the data is fetched, loaded into a pandas DataFrame, and missing values are replaced with "No Data". The essential code is:

import requests, json, pandas as pd
lon_min, lat_min = -125.974, 30.038
lon_max, lat_max = -68.748, 52.214
url_data = f"https://opensky-network.org/api/states/all?lamin={lat_min}&lomin={lon_min}&lamax={lat_max}&lomax={lon_max}"
response = requests.get(url_data).json()
col_name = ['icao24','callsign','origin_country','time_position','last_contact','long','lat','baro_altitude','on_ground','velocity','true_track','vertical_rate','sensors','geo_altitude','squawk','spi','position_source']
flight_df = pd.DataFrame(response['states'], columns=col_name)
flight_df = flight_df.fillna('No Data')
flight_df.head()

To visualise the aircraft, Bokeh is used. First, the required libraries are imported and a conversion from WGS‑84 latitude/longitude to Web Mercator coordinates is defined:

from bokeh.plotting import figure, show
from bokeh.tile_providers import get_provider, STAMEN_TERRAIN
from bokeh.models import HoverTool, LabelSet, ColumnDataSource
import numpy as np

def wgs84_web_mercator_point(lon, lat):
    k = 6378137
    x = lon * (k * np.pi/180.0)
    y = np.log(np.tan((90 + lat) * np.pi/360.0)) * k
    return x, y

def wgs84_to_web_mercator(df, lon='long', lat='lat'):
    k = 6378137
    df['x'] = df[lon] * (k * np.pi/180.0)
    df['y'] = np.log(np.tan((90 + df[lat]) * np.pi/360.0)) * k
    return df

After converting the coordinates, a Bokeh figure with a Stamen Terrain basemap is created, aircraft icons are plotted, and interactive hover tools and labels are added:

xy_min = wgs84_web_mercator_point(lon_min, lat_min)
xy_max = wgs84_web_mercator_point(lon_max, lat_max)
flight_df = wgs84_to_web_mercator(flight_df)
flight_df['rot_angle'] = -flight_df['true_track']
flight_df['url'] = 'https://example.com/plane_icon.png'
flight_source = ColumnDataSource(flight_df)

x_range, y_range = ([xy_min[0], xy_max[0]], [xy_min[1], xy_max[1]])
p = figure(x_range=x_range, y_range=y_range, x_axis_type='mercator', y_axis_type='mercator', sizing_mode='scale_width', plot_height=300)
 p.add_tile(get_provider(STAMEN_TERRAIN))
 p.image_url(url='url', x='x', y='y', source=flight_source, anchor='center', angle_units='deg', angle='rot_angle', w=40, h=40)
 p.circle('x', 'y', source=flight_source, fill_color='red', hover_color='yellow', size=10, fill_alpha=0.8, line_width=0)

 hover = HoverTool(tooltips=[('Call sign', '@callsign'), ('Origin Country', '@origin_country'), ('Velocity (m/s)', '@velocity'), ('Altitude (m)', '@baro_altitude')])
 labels = LabelSet(x='x', y='y', text='callsign', level='glyph', x_offset=5, y_offset=5, source=flight_source, render_mode='canvas', background_fill_color='white', text_font_size='8pt')
 p.add_tools(hover)
 p.add_layout(labels)
 show(p)

For a near‑real‑time web application, the Bokeh server is employed. The core function flight_tracking creates a column data source, defines an update callback that re‑fetches the OpenSky data every five seconds, streams the new data, and redraws the map. The server is started on a chosen port:

from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler

def flight_tracking(doc):
    flight_source = ColumnDataSource({ ... })  # columns as above
    def update():
        response = requests.get(url_data).json()
        df = pd.DataFrame(response['states'], columns=col_name)
        df = wgs84_to_web_mercator(df)
        df = df.fillna('No Data')
        df['rot_angle'] = -df['true_track']
        df['url'] = 'https://example.com/plane_icon.png'
        flight_source.stream(df.to_dict('list'), len(df))
    doc.add_periodic_callback(update, 5000)
    # figure setup (same as above)
    doc.title = 'REAL TIME FLIGHT TRACKING'
    doc.add_root(p)

apps = {'/': Application(FunctionHandler(flight_tracking))}
server = Server(apps, port=8084)
server.start()

Running the script launches a Bokeh server; opening http://localhost:8084 in a browser displays the interactive flight‑tracking map that refreshes automatically, providing a practical example of building a backend service that consumes open aviation data and visualises it in real time.

The article concludes that by combining the OpenSky Network API, Python data‑processing libraries, and Bokeh’s interactive plotting and server capabilities, developers can create a functional, near‑real‑time flight‑tracking web application.

Data VisualizationBokehrealtimeflight-trackingopensky
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.