使用Networkx和Basemap可视化社交网络
在本教程结束时,您将能够构建像这样的飞行网络的可视化
我将介绍非常强大的工具来可视化网络- Networkx和Basemap。许多有趣的问题自然来自或激发某种形式的图模型 - 顶点(或节点)与连接这些顶点的边之间的关系。例如:网站的链接和链接结构可以用有向图来表示,其中顶点表示网页,有向边代表从一个页面到另一个页面的链接。另一个例子是朋友圈,其中顶点代表不同的人,边代表关系的类型。
当谈到复杂的网络如病毒爆发,各国之间的现金流量或2005年地震的地震波时,以视觉,描述和有效方式说明网络属性仍然是一项挑战。我们希望观众在其地理环境中快速掌握网络。Networkx和Basemap(matplotlib软件包的一个工具包)提供了一个“一体化”的解决方案,从创建网络图形到计算各种度量到整洁的可视化。
在这个例子中,我们看看美利坚合众国机场之间的航线网络。我们的目标是表示顶点(机场)和边缘(航线),并保留不同顶点之间的地理关系(例如:我们要看图,并告诉这个顶点是JFK或洛根机场或其他什么)
起初我们加载相关的软件包:
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
matplotlib basemap工具包是一个用于在Python中的映射上绘制2D数据的库。Networkx是一个研究网络结构的综合性类库。
读取机场数据
第一步是获取数据并进行处理。在这里,我使用了OpenFlight(https://openflights.org/data.html)数据库获得信息机场和航线。他们有非常全面的数据。不幸的是,路由数据库并不是最新的。目前,全球共有531家航空公司在3,209个机场之间开通了59,036条航线。直到今天,世界上有多达17678个商业机场。尽管如此,当前的数据集对于我们今天的演示目的来说已经足够了。
有两个相关的数据集:
该airport.dat数据集包含所有列出的机场的地理信息
表1:快速浏览一下 airport.dat数据集的外观
routes.dat数据集
表2: routes.dat数据集
处理机场和航线数据集:
Networkx无法读取原始格式的数据,因此我们的第一项工作是处理数据,以获取Networkx可以读取的routes 的干净数据aframe。注意两个数据集是如何通过机场代码连接的(三个字母IATA代码)。您可以在这里找到处理我的源代码中的数据的完整代码(https://github.com/tuangauss/Various-projects/blob/master/Python/flights_networkx.py)。
我们的数据处理步骤的目的是获取以下两个Panda dataframes:
- 一个浓缩的routes_us数据框,其中每一行代表一条独特的航线,并且该航线上运营的航空公司总数(例如,有3家航空公司运营从利哈伊谷机场(ABE)飞往亚特兰大国际机场(ATL)的航班)。 。
Table 3: a condensed and cleaned routes dataframe.
- 精简的位置数据框,每行代表美国各机场的IATA代码,更重要的是纵向和横向细节
在前一个数据框中,我们准备好绘制飞行网络的第一个草图
起初,我们将我们的数据框转换成图形。请注意,我们的图是一个有向图,也就是说,一个有一组顶点的曲线图通过与它们相关联的方向进行连接。这意味着在我们的图中,两条路由JFK-ATL和ATL-JFK是分开的,因为即使它们连接相同的2个节点,两条路由也有不同的(相反的)方向。
我们使用Networkx的from_panda_dataframe()函数快速导入图形。在这里,我们从我们的数据框routes_us创建一个图,其中源是“Source Airport”列,目标是使用定向图模型的“Dest Airport”列。edge_attr意味着我们可以将信息添加到图形的边缘。我已经将路线上运营的航空公司的数量添加为边缘属性
graph = nx.from_pandas_dataframe(routes_us, source = 'Source Airport', target = 'Dest Airport', edge_attr = 'number of flights',create_using = nx.DiGraph())
Networkx确实有一个图形工具,可以用来绘制我们的网络。但我保证它不会很令人印象深刻。
plt.figure(figsize = (10,9))
nx.draw_networkx(graph)
plt.savefig("./images/map_0.png", format = "png", dpi = 300)
plt.show()
由Networkx的默认绘图网络功能绘制的图形
这个粗糙的网络的问题是,我们真的不知道哪个机场是哪个和哪些路线相互关联。
用Basemap绘制网络:
现在,我们需要帮助Basemap定义美国的边界。让我们定义一个包含阿拉斯加和波多黎各的相对较大的地图。我也选择熟悉的墨卡托投影。这是一个圆柱形的正形投影,在高纬度地区有很大的失真。是的,这是一幅错误的地图,在每一间教室里,阿拉斯加和非洲大陆一样大
plt.figure(figsize = (10,9))
m = Basemap(projection='merc',llcrnrlon=-180,llcrnrlat=10,urcrnrlon=-50,
urcrnrlat=70, lat_ts=0, resolution='l',suppress_ticks=True)
现在,我们需要定义我们的机场在Basemap上的位置。到目前为止,我们只有它们的纵向和横向信息。我们需要找到他们在基地地图上的真实投影。注意我如何调用我们的位置数据集,获取长数据和Lat数据,并将它们投射到Basemap表面
mx, my = m(pos_data['Long'].values, pos_data['Lat'].values)
pos = {}
for count, elem in enumerate (pos_data['IATA']):
pos[elem] = (mx[count], my[count])
下一步是让Networkx向Basemap添加节点、边和它们的属性。可以这样做:
nx.draw_networkx_nodes(G = graph, pos = pos, node_list = graph.nodes(),node_color = 'r', alpha = 0.8, node_size = 100)
nx.draw_networkx_edges(G = graph, pos = pos, edge_color='g', alpha=0.2, arrows = False)
最后一步是绘制国家,海岸线和状态线,使其看起来像一张地图
m.drawcountries(linewidth = 3)
m.drawstates(linewidth = 0.2)
m.drawcoastlines(linewidth=3)
plt.tight_layout()
plt.savefig("./images/map_1.png", format = "png", dpi = 300)
plt.show()
Networkx和Basemap绘制的基本图
它看起来很好,但不是很好。看到地图看起来相当丑陋的事实,我们实在无法从图表中分辨出任何东西。例如,我们希望看到更多信息,例如:
- 哪些机场正忙?
- 哪条航线更加突出?
为了回答这些问题,可能最好将每个机场的进出航班总数加起来,并将其作为机场规模。例如,一个有大量进出航班的机场将在地图上有更大的尺寸和更明显的空间。
为此,我们重复相同的代码,并进行小小的调整:
nx.draw_networkx_nodes(G = graph, pos = pos, node_list = graph.nodes(), node_color = 'r', alpha = 0.8, node_size = [counts['total_flight'][s]*3 for s in graph.nodes()])
由Networkx和Basemap绘制的图表,其中节点大小表示进出机场的航班的相对数量
这就好多了,一旦您熟悉了Networkx和Basemap,您就可以根据自己的喜好开始使用个性化地图了。例如,在这里,我将地图限制在内地机场,并且对地图的样式有一点不同
由Networkx和Basemap绘制的图形,其中节点是标签并分成大小机场组
类似地,对于精度τ,我们知道这些必须是非负的,所以选择一个限制为非负值的分布是有意义的 - 例如,我们可以使用低形状和尺度参数的Gamma分布。
我们可以开始做各种有趣的观察:例如,一些大型机场大多位于2个沿海地区(以及拉斯维加斯,丹佛,达拉斯/沃斯堡,休斯敦和亚特兰大)。与其他任何地区相比,我们可以开始看到西海岸地区的国内航线特别密集。有趣的是,像丹佛国际机场(Denver International Airport)这样的机场看起来好像是一个集散中心,也就是说,它可以作为转机(或停留)点将乘客送到最终目的地。