Python 连接开放航空交通数据,轻松构建航班跟踪应用!

作者 | geomatics

译者 | 弯月,责编 | 郑丽媛

图 | CSDN 下载自视觉中国

出品 | CSDN(ID:CSDNnews)

以下为译文:

我喜欢跟踪位置这个主题,因为感觉像是我有第六感一样。尽管看不到物体,却可以知道物体怎样移动。那么怎样才能获得第六感呢?通常人类只有五种感官。

我认为,既然我们生活在数字时代,那么科技就是我们的第六感。这篇文章将介绍的航班跟踪就是如此。现在已有很多航班跟踪应用,如flightradar24、FlightAware、flightview等,我们能够通过它们监控飞机在地球上的位置。本文不打算讨论这些应用,而是要探讨如何用Python制作自己的航班跟踪应用。

之前我发表过两篇用python跟踪航班的教程。一篇是使用python创建简单的航班跟踪应用,另一篇是使用pandas和bokeh创建航班跟踪应用。那么那两篇文章跟本文有什么区别?主要的区别是数据源。那两篇文章我使用了ADS-B Exchange,而这篇文章将使用Opensky Network。另一个区别就是模块的版本。本文将使用最新的python库,特别是绘图库。所以代码会略有不同。

闲话少说,现在开始介绍怎样通过python使用开放航空交通数据构建航班跟踪应用。本文由几个主题组成,包括:获取数据,导入依赖库,加载基础地图,绘制飞机位置,还有制作“实时”的航班跟踪应用。我们将依次讨论每个部分,在本文结束时,我们将会得到一个在浏览器中运行的航班跟踪应用,如图1所示。

图1 航班跟踪应用

获取航班交通数据

前面说过,本文将使用OpenSky Network提供的开放航空交通数据。OpenSky Network是一个非营利组织,它面向公众提供了开放的航空交通数据,用于研究和非商业用途。这些数据可以通过REST API、Python API和Java API访问。本文我们使用REST API来获取实时的航空交通数据。

使用REST API获取数据,可以通过发送请求来完成。可以使用两种类型的请求。第一种就是根据UNIX时间戳格式的时间,或者ICAO24地址来请求指定的航班。第二种就是使用WGS84坐标系统指定的地区,获取地区内的所有飞机数据。而且,数据访问可以匿名进行,也可以通过注册用户进行。匿名用户的数据分辨率为10秒,注册用户为5秒。

本文我们使用第二种方式。我们使用最小和最大坐标定义一个地区,然后发送查询,获取该地区内的所有飞机数据。例如,如果我们要获取美国上空的所有飞机,那么最小坐标为-125.974,30.038,最大坐标为-68.748,52.214。匿名用户和注册用户使用的查询分别如下所示。

# 匿名用户查询

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

lamax=52.214&lomax=-68.748

# 注册用户查询

https://username:[email protected]/api/states/all?lamin=30.038&lomin=-125.974&

lamax=52.214&lomax=-68.748

在继续阅读之前,我们先来尝试一下这两个请求,确保它们是正确的。将匿名查询复制粘贴到浏览器中。如果能获得如图2所示的响应,就说明是正确的。

图2 航空交通数据响应

图2中的响应的格式为JSON,包含两个键。第一个是time,第二个是states,它是一个列表数组,其中包含每架飞机的数据。该列表数组中有许多数据,如ICAO24地址、飞机的呼号、所属国家、时间位置、最后联系、经度、纬度、气压计高度等等。关于数据相应的完整解释和有关OpenSky Network API的进一步说明,请参见OpenSky Network API文档。

使用Python获取航空交通数据

我们已经通过浏览器使用REST API获取了交通数据。下面我们使用Python来获取数据,并进行后续的处理。本文中我使用Jupyter notebook和Python 3.8.2,以及一些库,如Bokeh 2.1.1、Pandas 0.25.3、requests、json和numpy等。

下面这段代码会发送请求,并对数据进行一些处理。代码开头导入了依赖的库,如requests、json和Pandas。然后使用变量lon_min、lat_min、lon_max和lat_max定义WGS84的坐标。然后使用坐标来生成请求。如果你是注册用户,则可以在11-12行的user_name和password变量中提供用户名和密码。根据指定的坐标和用户数据,13行创建了查询请求,放在了url_data变量中。其余代码负责将响应数据放到pandas的数据框中,然后用“No Data”替换空值。最后一行调用数据框的head方法,显示数据的前五行,如图3所示。

#IMPORTING LIBRARY


import requests


import json


import pandas as pd


 


#AREA EXTENT COORDINATE WGS4


lon_min,lat_min=-125.974,30.038


lon_max,lat_max=-68.748,52.214


 


#REST API QUERY


user_name=''


password=''


url_data='https://'+user_name+':'+password+'@opensky-network.org/api/states/all?'+'lamin='+str(lat_min)+'&lomin='+str(lon_min)+'&lamax='+str(lat_max)+'&lomax='+str(lon_max)


response=requests.get(url_data).json()


 


#LOAD TO PANDAS DATAFRAME


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') #replace NAN with No Data


flight_df.head()

图3 航班跟踪数据的数据帧

你需要确保在执行完代码之后得到的结果类似于图3。这表明一切正确,我们可以进行下一步了。


在地图上绘制飞机

在获得数据之后,接下来该在地图上绘制所有飞机的位置了。我们使用Bokeh库绘图。因此首先需要导入库。此外还需要导入NumPy库进行坐标转换。

坐标系统的转换在函数 wgs84_web_mercator_ 中实现。顾名思义,该函数的用途是将 WGS84坐标转化成墨卡托坐标系。该转换是必须的,因为我们使用的基础地图是STAMEN_TERRAIN,它采用墨卡托坐标系。

创建好坐标转换系统函数之后,就可以对数据框和坐标进行转换了。下一步我们来进行绘图设置,使用x、y坐标指定绘图区域的范围。我们在基础地图上,利用x、y坐标点,以及飞机的图标来绘制飞机的位置。为什么要同时使用点和飞机图标呢?图标可以更好地可视化,旋转图标可以表明飞行路线的角度。但很不幸的是,图标无法高亮显示选中对象,也无法在鼠标悬停时显示更多信息。为了解决这个问题,我们同时使用图标和点对象,在实现漂亮的可视化同时,还可以使用选择和悬停工具。

下面是到此为止的代码。执行后将获得图4。

#IMPORT PLOTTING LIBRARIES


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


 


#FUNCTION TO CONVERT GCS WGS84 TO WEB MERCATOR


#POINT


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


 


#DATA FRAME


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


 


#COORDINATE CONVERSION


xy_min=wgs84_web_mercator_point(lon_min,lat_min)


xy_max=wgs84_web_mercator_point(lon_max,lat_max)


wgs84_to_web_mercator(flight_df)


flight_df['rot_angle']=flight_df['true_track']*-1 #Rotation angle


icon_url='https://.....' #Icon url


flight_df['url']=icon_url


 


 


#FIGURE SETTING


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)


 


#PLOT BASEMAP AND AIRPLANE POINTS


flight_source=ColumnDataSource(flight_df)


tile_prov=get_provider(STAMEN_TERRAIN)


p.add_tile(tile_prov,level='image')


p.image_url(url='url', x='x', y='y',source=flight_source,anchor='center',angle_units='deg',angle='rot_angle',h_units='screen',w_units='screen',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 INFORMATION AND LABEL


my_hover=HoverTool()


my_hover.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(my_hover)


p.add_layout(labels)


 


show(p)

图4 绘制飞机

构建航班跟踪应用

到此为止,我们讨论了航空交通数据并在地图上绘制了飞机。最后一节我们将展示如何构建一个在Web浏览器中运行的航班跟踪应用。该应用能够按照指定的间隔,自动获取最新数据,并在地图上绘制数据。本节我们将前面几步的代码合并起来,使用Bokeh库打包成一个应用程序。完整的代码在本文末尾。

仔细观察代码就会发现,我们需要导入额外的Bokeh库,如Server、Application和FunctionHandler。应用程序代码从第50行开始。此处创建了应用程序的主函数flight_tracking。主函数包含了所有流程,如更新航班数据、注入Pandas数据框、转化成Bokeh数据列源和流、每隔5秒调用更新并在地图上绘制数据。在创建了应用程序主函数后,代码的末尾是一些服务器所需的变量或参数。所有的流程可以从代码中的注释中找到。

'''


FLIGHT TRACKING WITH PYTHON AND OPEN AIR TRAFFIC DATA


by ideagora geomatics | www.geodose.com | @ideageo


'''


#IMPORT LIBRARY


import requests


import json


import pandas as pd


from bokeh.plotting import figure


from bokeh.models import HoverTool,LabelSet,ColumnDataSource


from bokeh.tile_providers import get_provider, STAMEN_TERRAIN


import numpy as np


from bokeh.server.server import Server


from bokeh.application import Application


from bokeh.application.handlers.function import FunctionHandler


 


#FUNCTION TO CONVERT GCS WGS84 TO WEB MERCATOR


#DATAFRAME


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


 


#POINT


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


 


#AREA EXTENT COORDINATE WGS84


lon_min,lat_min=-125.974,30.038


lon_max,lat_max=-68.748,52.214


 


#COORDINATE CONVERSION


xy_min=wgs84_web_mercator_point(lon_min,lat_min)


xy_max=wgs84_web_mercator_point(lon_max,lat_max)


 


#COORDINATE RANGE IN WEB MERCATOR


x_range,y_range=([xy_min[0],xy_max[0]], [xy_min[1],xy_max[1]])


 


#REST API QUERY


user_name=''


password=''


url_data='https://'+user_name+':'+password+'@opensky-network.org/api/states/all?'+'lamin='+str(lat_min)+'&lomin='+str(lon_min)+'&lamax='+str(lat_max)+'&lomax='+str(lon_max)


 


    


#FLIGHT TRACKING FUNCTION


def flight_tracking(doc):


    # init bokeh column data source


    flight_source = ColumnDataSource({


        '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':[],'x':[],'y':[],


        'rot_angle':[],'url':[]


    })


    


    # UPDATING FLIGHT DATA


    def update():


        response=requests.get(url_data).json()


        


        #CONVERT TO PANDAS DATAFRAME


        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_data=response['states']


        flight_df=pd.DataFrame(flight_data,columns=col_name)


        wgs84_to_web_mercator(flight_df)


        flight_df=flight_df.fillna('No Data')


        flight_df['rot_angle']=flight_df['true_track']*-1


        icon_url='https:...' #icon url


        flight_df['url']=icon_url


        


        # CONVERT TO BOKEH DATASOURCE AND STREAMING


        n_roll=len(flight_df.index)


        flight_source.stream(flight_df.to_dict(orient='list'),n_roll)


        


    #CALLBACK UPATE IN AN INTERVAL


    doc.add_periodic_callback(update, 5000) #5000 ms/10000 ms for registered user .


.     


    #PLOT AIRCRAFT POSITION


    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)


    tile_prov=get_provider(STAMEN_TERRAIN)


    p.add_tile(tile_prov,level='image')


    p.image_url(url='url', x='x', y='y',source=flight_source,anchor='center',angle_units='deg',angle='rot_angle',h_units='screen',w_units='screen',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)


 


    #ADD HOVER TOOL AND LABEL


    my_hover=HoverTool()


    my_hover.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(my_hover)


    p.add_layout(labels)


    


    doc.title='REAL TIME FLIGHT TRACKING'


    doc.add_root(p)


    


# SERVER CODE


apps = {'/': Application(FunctionHandler(flight_tracking))}


server = Server(apps, port=8084) #define an unused port


server.start()

下面可以测试应用程序了。运行代码并打开Web浏览器。输入localhost:端口号(例如localhost:8084)。你将会看到航班跟踪应用在浏览器中运行,如下图所示。 

图5 Web浏览器中的航班跟踪应用

本文介绍了如何使用Python和开放航空交通数据构建一个几乎“实时”的航班跟踪应用。在本文中,我们学习了如何从OpenSky Networks获取开放航空交通数据,如何对其进行处理并构建一个能在浏览器中运行的航班跟踪应用。在本文结束之际,我想感谢OpenSky Networks的辛劳工作,这些数据才得以公开。感谢您的阅读!

原文:https://www.geodose.com/2020/08/create-flight-tracking-apps-using-python-open-data.html

本文为 CSDN 翻译,转载请注明来源出处。

更多精彩推荐
☞头秃,在线求名字:网易使用昵称交流,再也没有“哥,姐,总”
☞高科技公司的 CEO 要写代码吗?
☞文件系统:隐匿在 Linux 背后的机制
☞CPU有个禁区,内核权限也无法进入!
☞5年5亿美金,华为昇腾如何构建全行业AI生态?
☞将比特币用作结算网络中蕴含的经济学知识
点分享点点赞点在看

猜你喜欢

转载自blog.csdn.net/csdnnews/article/details/108426748